diff --git a/Documentation/User Manual/3-simulation-models/TC.md b/Documentation/User Manual/3-simulation-models/TC.md index 0c0805bd232333e126a474d94a76b314f917aa8a..60800632be0d52e796582981d9f31f919b12aba9 100644 --- a/Documentation/User Manual/3-simulation-models/TC.md +++ b/Documentation/User Manual/3-simulation-models/TC.md @@ -1,55 +1,55 @@ -##Torque Converter Model - -The torque converter is defined as (virtual) separate gear. Independent of the chosen AT gearbox type (serial or power split), Vecto uses a powertrain architecture with a serial torque converter. The mechanical gear ratios and gears with torque converter are created by Vecto depending on the gearbox type and gear configuration. - -While the torque converter is active engine torque and speed are computed based on TC characteristic. - -  - - -###Torque converter characteristics file (.vtcc) - -The file is described [here](#torque-converter-characteristics-.vtcc). - -This file defines the torque converter characteristics as described in VDI 2153: - -- **Speed Ratio** (ν) = Output Speed / Input Speed -- **Torque Ratio** (μ) = Output Torque / Input Torque -- **Input Torque** (T~ref(ν)~) is the input torque (over ν) for a specific reference engine speed (see below). - -The Input Torque at  reference engine speed is needed to calculate the actual engine torque using this formula: - -$T_{in} = T_{ref}(v) \cdot ( \frac{n_{in}}{n_{ref}} )^{2}$ - -$μ(ν) = \frac{T_{out}}{T_{in}}$ - -with: - -- T~in~ = engine torque \[Nm\] -- T~ref(ν)~ = reference torque at reference rpm (from .vtcc file) \[Nm\] -- n~in~ = engine speed \[1/min\] -- n~ref~ = reference rpm \[1/min\] (see below) - -The torque converter characteristics must also be defined for speed ratios greater than one (ν>1) in order to calculate overrun conditions or engine drag (torque<0). - -**Note:** The torque converter characteristics must not contain parts where either the torque ratio or the input torque are constant! - -<div class="declaration"> -In declaration mode, the torque converter for drag points is automatically appended by VECTO. Input data with a speed ratio ≥ 1 are skipped. - -For Power Split transmissions, where the torque converter characteristics already contains the gearbox losses and transmission ratio, the generic drag points are adapted according to the following equations: - -$ν_{PS} = ν / ratio_i$ - -$μ_{PS} = μ \cdot ratio_i$ -</div> - -<div class="engineering"> -In engineering mode the drag points for the torque converter can be specified. If so, the input data has to cover at least the speed ratio up to 2.2. - -If the torque converter characteristics for drag are not specified, the generic points are appended as described above for declaration mode. -</div> - -The torque converter has a separate [Shift Polygon](#shift-polygon-file-.vgbs) which defines the conditions for switching from torque converter gear to locked gear. - - +##Torque Converter Model + +The torque converter is defined as (virtual) separate gear. Independent of the chosen AT gearbox type (serial or power split), Vecto uses a powertrain architecture with a serial torque converter. The mechanical gear ratios and gears with torque converter are created by Vecto depending on the gearbox type and gear configuration. + +While the torque converter is active engine torque and speed are computed based on TC characteristic. + +  + + +###Torque converter characteristics file (.vtcc) + +The file is described [here](#torque-converter-characteristics-.vtcc). + +This file defines the torque converter characteristics as described in VDI 2153: + +- **Speed Ratio** (ν) = Output Speed / Input Speed +- **Torque Ratio** (μ) = Output Torque / Input Torque +- **Input Torque** (T~ref(ν)~) is the input torque (over ν) for a specific reference engine speed (see below). + +The Input Torque at  reference engine speed is needed to calculate the actual engine torque using this formula: + +$T_{in} = T_{ref}(v) \cdot ( \frac{n_{in}}{n_{ref}} )^{2}$ + +$\mu(\nu) = \frac{T_{out}}{T_{in}}$ + +with: + +- T~in~ = engine torque \[Nm\] +- T~ref(ν)~ = reference torque at reference rpm (from .vtcc file) \[Nm\] +- n~in~ = engine speed \[1/min\] +- n~ref~ = reference rpm \[1/min\] (see below) + +The torque converter characteristics must also be defined for speed ratios greater than one (ν>1) in order to calculate overrun conditions or engine drag (torque<0). + +**Note:** The torque converter characteristics must not contain parts where either the torque ratio or the input torque are constant! + +<div class="declaration"> +In declaration mode, the torque converter for drag points is automatically appended by VECTO. Input data with a speed ratio ≥ 1 are skipped. + +For Power Split transmissions, where the torque converter characteristics already contains the gearbox losses and transmission ratio, the generic drag points are adapted according to the following equations: + +$\nu_{PS} = \nu / ratio_i$ + +$\mu_{PS} = \mu \cdot ratio_i$ +</div> + +<div class="engineering"> +In engineering mode the drag points for the torque converter can be specified. If so, the input data has to cover at least the speed ratio up to 2.2. + +If the torque converter characteristics for drag are not specified, the generic points are appended as described above for declaration mode. +</div> + +The torque converter has a separate [Shift Polygon](#shift-polygon-file-.vgbs) which defines the conditions for switching from torque converter gear to locked gear. + + diff --git a/Documentation/User Manual/convert.bat b/Documentation/User Manual/convert.bat index b7bc8691fc3e086418ebb19623c224c93fa1b266..c80082457f447f716e8e79be5b840c515a9ea6ae 100644 --- a/Documentation/User Manual/convert.bat +++ b/Documentation/User Manual/convert.bat @@ -8,7 +8,8 @@ set LIST= for /f %%f in (files.txt) do set LIST=!LIST! "%%f" -pandoc --verbose -f markdown+raw_html %LIST% -s -S --toc --toc-depth=2 --self-contained --email-obfuscation=none --section-divs --mathjax=includes/mathjax.js -c includes/style.css -c includes/print.css -B includes/header.html -A includes/footer.html -o help.html -H includes/jquery.js -H includes/jquery-ui.js -H includes/include.js +REM pandoc --verbose -f markdown+raw_html %LIST% -s -S --toc --toc-depth=2 --self-contained --email-obfuscation=none --section-divs --mathjax=includes/mathjax.js -c includes/style.css -c includes/print.css -B includes/header.html -A includes/footer.html -o help.html -H includes/jquery.js -H includes/jquery-ui.js -H includes/include.js +pandoc --verbose -f markdown+raw_html %LIST% -s -S --toc --toc-depth=2 --self-contained --email-obfuscation=none --section-divs --webtex -c includes/style.css -c includes/print.css -B includes/header.html -A includes/footer.html -o help.html -H includes/jquery.js -H includes/jquery-ui.js -H includes/include.js REM pandoc %LIST% -s -S --toc --toc-depth=2 --self-contained --email-obfuscation=none --section-divs --webtex -c includes/style.css -B includes/header.html -A includes/footer.html -o help.html -H includes/jquery.js -H includes/jquery-ui.js -H includes/include.js REM pandoc %LIST% -s -S --toc --toc-depth=2 --self-contained --email-obfuscation=none --section-divs --webtex="https://latex.codecogs.com/svg.latex?\large " -c includes/style.css -B includes/header.html -A includes/footer.html -o help.html -H includes/jquery.js -H includes/jquery-ui.js -H includes/include.js diff --git a/Documentation/User Manual/help.html b/Documentation/User Manual/help.html index 23f327a03c96bff5567b833fd1c49f485edf9d32..7e7708714a497d52edb982187aead8339233b5db 100644 --- a/Documentation/User Manual/help.html +++ b/Documentation/User Manual/help.html @@ -43,9 +43,8 @@ code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Ann code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */ code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */ </style> - <link href="data:text/css;charset=utf-8,body%20%7B%0Aheight%3A%20100%25%3B%0Amin%2Dheight%3A%20100%25%3B%0Afont%2Dfamily%3A%20Calibri%2C%20sans%2Dserif%3B%0A%7D%0Anav%2C%20%23TOC%20%7B%0Aposition%3A%20fixed%3B%0Awidth%3A%2021em%3B%0Aleft%3A%200px%3B%0Atop%3A%203%2E5em%3B%0Abottom%3A%202em%3B%0Abackground%2Dcolor%3A%20%23eee%3B%0Aoverflow%3A%20scroll%3B%0A%7D%0A%23HEADER%7B%0Atop%3A%200px%3B%0Aleft%3A%201px%3B%0Aborder%2Dbottom%2Dstyle%3A%20solid%3B%0Aborder%2Dbottom%2Dwidth%3A%20thin%3B%0Aborder%2Dbottom%2Dcolor%3A%20%23aaa%3B%0Aheight%3A%202%2E5em%3B%0A%7D%0A%23CONTENT%7B%0Apadding%2Dleft%3A%2021em%3B%0A%7D%0A%23FOOTER%20%7B%0Aborder%2Dtop%2Dstyle%3A%20solid%3B%0Aborder%2Dtop%2Dwidth%3A%20thin%3B%0Aborder%2Dtop%2Dcolor%3A%20%23aaa%3B%0Abottom%3A%200px%3B%0Aleft%3A%201px%3B%0A%7D%0A%23HEADER%2C%20%23FOOTER%20%7B%0Awidth%3A%20auto%3B%0Aposition%3A%20fixed%3B%0Awidth%3A%2099%25%3B%0Abackground%3A%20white%3B%0Apadding%3A%205px%3B%0A%7D%0Abody%20%3E%20div%3Anot%28%23TOC%29%3Anot%28%23HEADER%29%3Anot%28%23FOOTER%29%20%7B%0Adisplay%3A%20none%3B%0Apadding%2Dleft%3A%2021em%3B%0Apadding%2Dtop%3A%202em%3B%0Apadding%2Dbottom%3A%202em%3B%0Amargin%2Dleft%3A%201em%3B%0Awidth%3A%2050em%3B%0A%7D%0Atable%20%7B%0Aborder%2Dcollapse%3A%20collapse%3B%0Aborder%2Dspacing%3A%200%3B%0A%7D%0Anav%20ul%20%7B%0Aline%2Dheight%3A%201%2E7em%3B%0Alist%2Dstyle%2Dtype%3A%20none%3B%0Alist%2Dstyle%2Dposition%3A%20inside%3B%0A%7D%0Ath%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Ath%2C%20td%20%7B%0Apadding%3A%206px%3B%0Aborder%2Dwidth%3A%201px%3B%0Aborder%2Dstyle%3A%20solid%3B%0Aborder%2Dcolor%3A%20%23aaa%3B%0A%7D%0Ah1%2C%20h2%2C%20h3%20%7B%0Apadding%2Dbottom%3A%203px%3B%0Aborder%2Dbottom%2Dwidth%3A%201px%3B%0Aborder%2Dbottom%2Dstyle%3A%20solid%3B%0Aborder%2Dbottom%2Dcolor%3A%20%23aaa%3B%0A%7D%0Adt%20%7B%0Afont%2Dstyle%3A%20italic%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Eui%2Dresizable%2Dhandle%20%7B%0Aposition%3A%20absolute%3B%0Awidth%3A%2020px%3B%0Acursor%3A%20ew%2Dresize%3B%0Aright%3A%200px%3B%0Aheight%3A%20100%25%3B%0Atop%3A%200px%3B%0A%7D%0Adiv%2Evecto2%20%7B%0Aborder%2Dleft%3A%203px%20solid%20gray%3B%0Apadding%2Dleft%3A%205px%3B%0Amargin%2Dtop%3A%202em%3B%0Abackground%3A%20rgba%28128%2C128%2C128%2C0%2E05%29%3B%0A%7D%0Adiv%2Evecto2%3Abefore%20%7B%0Acontent%3A%20%27Note%3A%20Vecto%202%2E2%21%27%3B%0Abackground%3A%20gray%3B%0Acolor%3A%20white%3B%0Apadding%3A%205px%205px%205px%205px%3B%0Amargin%2Dleft%3A%20%2D8px%3B%0Afont%2Dweight%3A%20bold%3B%0Adisplay%3A%20inline%2Dblock%3B%0Afont%2Dsize%3A%20smaller%3B%0A%7D%0Adiv%2Evecto3%20%7B%0Aborder%2Dleft%3A%203px%20solid%20green%3B%0Apadding%2Dleft%3A%205px%3B%0Amargin%2Dtop%3A%202em%3B%0Abackground%3A%20rgba%280%2C128%2C0%2C0%2E05%29%3B%0A%7D%0Adiv%2Evecto3%3Abefore%20%7B%0Acontent%3A%20%27Note%3A%20Vecto%203%2Ex%21%27%3B%0Abackground%3A%20green%3B%0Acolor%3A%20white%3B%0Apadding%3A%205px%205px%205px%205px%3B%0Amargin%2Dleft%3A%20%2D8px%3B%0Afont%2Dweight%3A%20bold%3B%0Adisplay%3A%20inline%2Dblock%3B%0Afont%2Dsize%3A%20smaller%3B%0A%7D%0Adiv%2Eengineering%7B%0Aborder%2Dright%3A%205px%20solid%20%23d51000%3B%0Amargin%2Dright%3A%20%2D50px%3B%0Abackground%2Dimage%3A%20url%28data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8%2BDQo8IS0tIENyZWF0ZWQgd2l0aCBJbmtzY2FwZSAoaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvKSAtLT4NCg0KPHN2Zw0KICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIg0KICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyINCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyINCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciDQogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiDQogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSINCiAgIHdpZHRoPSI0NS4xNTU1NTZtbSINCiAgIGhlaWdodD0iNDQuMDI2NjY5bW0iDQogICB2aWV3Qm94PSIwIDAgMTYwIDE1Ni4wMDAwMSINCiAgIGlkPSJzdmc0MTY3Ig0KICAgdmVyc2lvbj0iMS4xIg0KICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MSByMTM3MjUiDQogICBzb2RpcG9kaTpkb2NuYW1lPSJpY29uX2VuZ2luZWVyaW5nLW1vZGUuc3ZnIj4NCiAgPGRlZnMNCiAgICAgaWQ9ImRlZnM0MTY5IiAvPg0KICA8c29kaXBvZGk6bmFtZWR2aWV3DQogICAgIGlkPSJiYXNlIg0KICAgICBwYWdlY29sb3I9IiNmZmZmZmYiDQogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2Ig0KICAgICBib3JkZXJvcGFjaXR5PSIxLjAiDQogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiDQogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiDQogICAgIGlua3NjYXBlOnpvb209IjIuOCINCiAgICAgaW5rc2NhcGU6Y3g9IjE4LjI1ODUwNCINCiAgICAgaW5rc2NhcGU6Y3k9Ijk3LjIzNzM3NCINCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4Ig0KICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiDQogICAgIHNob3dncmlkPSJmYWxzZSINCiAgICAgZml0LW1hcmdpbi10b3A9IjAiDQogICAgIGZpdC1tYXJnaW4tbGVmdD0iMCINCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCINCiAgICAgZml0LW1hcmdpbi1ib3R0b209IjAiDQogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCINCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTEzOCINCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii04Ig0KICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiDQogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiIC8%2BDQogIDxtZXRhZGF0YQ0KICAgICBpZD0ibWV0YWRhdGE0MTcyIj4NCiAgICA8cmRmOlJERj4NCiAgICAgIDxjYzpXb3JrDQogICAgICAgICByZGY6YWJvdXQ9IiI%2BDQogICAgICAgIDxkYzpmb3JtYXQ%2BaW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0Pg0KICAgICAgICA8ZGM6dHlwZQ0KICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPg0KICAgICAgICA8ZGM6dGl0bGU%2BPC9kYzp0aXRsZT4NCiAgICAgIDwvY2M6V29yaz4NCiAgICA8L3JkZjpSREY%2BDQogIDwvbWV0YWRhdGE%2BDQogIDxnDQogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIg0KICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIg0KICAgICBpZD0ibGF5ZXIxIg0KICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjM0LjI4NTcxLC0zNDUuNzkwNzgpIj4NCiAgICA8cGF0aA0KICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiDQogICAgICAgZD0ibSAyNTQuMjg1NzEsMzQ1Ljc5MDc4IC0yLDQgMjEsMTIgYyAwLDEwIC00LDE4IC0xMywyMyBsIC0yMSwtMTIgLTEsMiBjIDUsMTUgMTUsMjUgMzUsMjUgNSwwIDIwLDE1IDI4LDIzIGwgMTYsLTE2IGMgLTgsLTggLTI2LC0yNiAtMjYsLTMxIDAsLTE4IC01LC0zMCAtMzcsLTMwIHogbSAxMjUsNSAtMjAsMTQgLTIsOCAtNTgsNTggLTgsLTUgLTQsNCBjIDAsMTIgLTE0LDE4IC0yMCwxOCBsIC0zMywzMyBjIDAsMTAgMTEsMjEgMjEsMjEgbCAzMywtMzMgYyAwLC02IDYsLTIwIDE4LC0yMCBsIDQsLTQgLTUsLTggNTgsLTU4IDgsLTIgMTQsLTIwIC02LC02IHogbSAtNTAsNjggLTE2LDE2IGMgMTIsMTIgMjgsMjggMjgsMzMgMCwxOCA1LDMwIDM3LDMwIGwgMiwtNCAtMjEsLTEyIGMgMCwtMTAgNCwtMTggMTMsLTIzIGwgMjEsMTIgMSwtMiBjIC01LC0xNSAtMTUsLTI1IC0zNSwtMjUgLTUsMCAtMTgsLTEzIC0zMCwtMjUgeiINCiAgICAgICBpZD0iaW1hZ2Vib3RfMy0wIg0KICAgICAgIHN0eWxlPSJmaWxsOiNkNTEwMDA7ZmlsbC1vcGFjaXR5OjEiIC8%2BDQogIDwvZz4NCjwvc3ZnPg0K%29%3B%0Abackground%2Dcolor%3A%20rgba%28255%2C0%2C0%2C0%2E2%29%3B%0Apadding%3A%202px%2050px%202px%205px%3B%0Amargin%2Dbottom%3A%200%2E5em%3B%0Abackground%2Drepeat%3A%20no%2Drepeat%3B%0Abackground%2Dsize%3A%2038px%3B%0Abackground%2Dposition%3A%20top%20right%3B%0A%7D%0Adiv%2Edeclaration%20%7B%0Aborder%2Dright%3A%205px%20solid%20%2308c300%3B%0Amargin%2Dright%3A%20%2D50px%3B%0Abackground%2Dimage%3A%20url%28data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8%2BDQo8IS0tIENyZWF0ZWQgd2l0aCBJbmtzY2FwZSAoaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvKSAtLT4NCg0KPHN2Zw0KICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIg0KICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyINCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyINCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciDQogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiDQogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSINCiAgIHdpZHRoPSI0OS43OTY4MjJtbSINCiAgIGhlaWdodD0iNDkuNzk2ODIybW0iDQogICB2aWV3Qm94PSIwIDAgMTc2LjQ0NTQzIDE3Ni40NDU0MyINCiAgIGlkPSJzdmcyIg0KICAgdmVyc2lvbj0iMS4xIg0KICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MSByMTM3MjUiDQogICBzb2RpcG9kaTpkb2NuYW1lPSJpY29uX2RlY2xhcmF0aW9uLW1vZGUuc3ZnIj4NCiAgPGRlZnMNCiAgICAgaWQ9ImRlZnM0IiAvPg0KICA8c29kaXBvZGk6bmFtZWR2aWV3DQogICAgIGlkPSJiYXNlIg0KICAgICBwYWdlY29sb3I9IiNmZmZmZmYiDQogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2Ig0KICAgICBib3JkZXJvcGFjaXR5PSIxLjAiDQogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiDQogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiDQogICAgIGlua3NjYXBlOnpvb209IjEuOTc5ODk5Ig0KICAgICBpbmtzY2FwZTpjeD0iMTcuMjkyOTMzIg0KICAgICBpbmtzY2FwZTpjeT0iNDYuODI4NzU0Ig0KICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiDQogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSINCiAgICAgc2hvd2dyaWQ9ImZhbHNlIg0KICAgICBmaXQtbWFyZ2luLXRvcD0iMCINCiAgICAgZml0LW1hcmdpbi1sZWZ0PSIwIg0KICAgICBmaXQtbWFyZ2luLXJpZ2h0PSIwIg0KICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCINCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxOTIwIg0KICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMTM4Ig0KICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiDQogICAgIGlua3NjYXBlOndpbmRvdy15PSItOCINCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgLz4NCiAgPG1ldGFkYXRhDQogICAgIGlkPSJtZXRhZGF0YTciPg0KICAgIDxyZGY6UkRGPg0KICAgICAgPGNjOldvcmsNCiAgICAgICAgIHJkZjphYm91dD0iIj4NCiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ%2BDQogICAgICAgIDxkYzp0eXBlDQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8%2BDQogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPg0KICAgICAgPC9jYzpXb3JrPg0KICAgIDwvcmRmOlJERj4NCiAgPC9tZXRhZGF0YT4NCiAgPGcNCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiDQogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiDQogICAgIGlkPSJsYXllcjEiDQogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNjYuMzQwODMsLTUzLjQ4Njk3NCkiPg0KICAgIDxwYXRoDQogICAgICAgc29kaXBvZGk6dHlwZT0ic3RhciINCiAgICAgICBzdHlsZT0iZmlsbDojMDhjMzAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiDQogICAgICAgaWQ9InBhdGg0MTQzIg0KICAgICAgIHNvZGlwb2RpOnNpZGVzPSIxMiINCiAgICAgICBzb2RpcG9kaTpjeD0iMzU0LjU2MzU0Ig0KICAgICAgIHNvZGlwb2RpOmN5PSIxNDEuNzA5NjkiDQogICAgICAgc29kaXBvZGk6cjE9Ijc3LjY4MDA4NCINCiAgICAgICBzb2RpcG9kaTpyMj0iODguMjcyODI3Ig0KICAgICAgIHNvZGlwb2RpOmFyZzE9IjAuNzQ4OTc3MDMiDQogICAgICAgc29kaXBvZGk6YXJnMj0iMS4wMTA3NzY0Ig0KICAgICAgIGlua3NjYXBlOmZsYXRzaWRlZD0iZmFsc2UiDQogICAgICAgaW5rc2NhcGU6cm91bmRlZD0iMC40Ig0KICAgICAgIGlua3NjYXBlOnJhbmRvbWl6ZWQ9IjAiDQogICAgICAgZD0ibSA0MTEuNDU1MzMsMTk0LjYwMTI3IGMgLTYuNTU2MzksNy4wNTIyNSAtMS44NDI3NiwxNi43ODIwNiAtMTAuMDAwOTksMjEuODk3MDkgLTguMTU4MjQsNS4xMTUwMyAtMTQuODYyNzQsLTMuMzY2NTUgLTI0LjA2Njg2LC0wLjUzNzMyIC05LjIwNDEyLDIuODI5MjMgLTkuOTg2OSwxMy42MTIzMSAtMTkuNjA5NjYsMTMuOTYyOTMgLTkuNjIyNzUsMC4zNTA2MyAtMTEuMTg4MjMsLTEwLjM0Njg4IC0yMC41NzM4NCwtMTIuNDk4NzYgLTkuMzg1NjIsLTIuMTUxODcgLTE1LjQ1NTA3LDYuNzk1MTYgLTIzLjk2MzkzLDIuMjg3NDMgLTguNTA4ODcsLTQuNTA3NzIgLTQuNTE1ODUsLTE0LjU1NDc4IC0xMS41NjgxLC0yMS4xMTExNiAtNy4wNTIyNCwtNi41NTYzOSAtMTYuNzgyMDUsLTEuODQyNzYgLTIxLjg5NzA4LC0xMC4wMDEgLTUuMTE1MDMsLTguMTU4MjMgMy4zNjY1NSwtMTQuODYyNzMgMC41MzczMiwtMjQuMDY2ODUgLTIuODI5MjQsLTkuMjA0MTIgLTEzLjYxMjMxLC05Ljk4NjkgLTEzLjk2Mjk0LC0xOS42MDk2NiAtMC4zNTA2MywtOS42MjI3NSAxMC4zNDY4OSwtMTEuMTg4MjMgMTIuNDk4NzYsLTIwLjU3Mzg1IDIuMTUxODcsLTkuMzg1NjEgLTYuNzk1MTUsLTE1LjQ1NTA2IC0yLjI4NzQzLC0yMy45NjM5MiA0LjUwNzczLC04LjUwODg2NyAxNC41NTQ3OCwtNC41MTU4NTMgMjEuMTExMTcsLTExLjU2ODA5OSA2LjU1NjM4LC03LjA1MjI0NiAxLjg0Mjc1LC0xNi43ODIwNTYgMTAuMDAwOTksLTIxLjg5NzA4NCA4LjE1ODI0LC01LjExNTAzIDE0Ljg2Mjc0LDMuMzY2NTUgMjQuMDY2ODYsMC41MzczMTggOS4yMDQxMSwtMi44MjkyMzIgOS45ODY5LC0xMy42MTIzMDkgMTkuNjA5NjUsLTEzLjk2MjkzNSA5LjYyMjc2LC0wLjM1MDYyNyAxMS4xODgyMywxMC4zNDY4ODYgMjAuNTczODUsMTIuNDk4NzU5IDkuMzg1NjIsMi4xNTE4NzIgMTUuNDU1MDYsLTYuNzk1MTU1IDIzLjk2MzkzLC0yLjI4NzQzIDguNTA4ODYsNC41MDc3MjcgNC41MTU4NSwxNC41NTQ3ODMgMTEuNTY4MDksMjEuMTExMTY4IDcuMDUyMjUsNi41NTYzODQgMTYuNzgyMDYsMS44NDI3NTUgMjEuODk3MDksMTAuMDAwOTkyIDUuMTE1MDMsOC4xNTgyNDEgLTMuMzY2NTUsMTQuODYyNzQxIC0wLjUzNzMyLDI0LjA2Njg1MSAyLjgyOTIzLDkuMjA0MTIgMTMuNjEyMzEsOS45ODY5IDEzLjk2MjkzLDE5LjYwOTY2IDAuMzUwNjMsOS42MjI3NSAtMTAuMzQ2ODgsMTEuMTg4MjMgLTEyLjQ5ODc1LDIwLjU3Mzg1IC0yLjE1MTg4LDkuMzg1NjEgNi43OTUxNSwxNS40NTUwNiAyLjI4NzQyLDIzLjk2MzkzIC00LjUwNzcyLDguNTA4ODYgLTE0LjU1NDc4LDQuNTE1ODUgLTIxLjExMTE2LDExLjU2ODA5IHoiDQogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSI1LjI0NTM5ODgiDQogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSItMy4yODMzMTg2IiAvPg0KICAgIDxjaXJjbGUNCiAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiDQogICAgICAgaWQ9InBhdGg0MTQ1Ig0KICAgICAgIGN4PSIzNTQuNTYzNTQiDQogICAgICAgY3k9IjE0MS43MDk2OSINCiAgICAgICByPSI1MC41MDc2MjkiIC8%2BDQogICAgPGNpcmNsZQ0KICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjcuMDE2MDIxNzM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSINCiAgICAgICBpZD0icGF0aDQxNTAiDQogICAgICAgY3g9IjM1NC41NjM1NCINCiAgICAgICBjeT0iMTQxLjcwOTY5Ig0KICAgICAgIHI9IjYyLjg5OTM2OCIgLz4NCiAgICA8Zw0KICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjQwcHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTpTYW5zO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O2ZpbGw6IzA4YzMwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzA4YzMwMDtzdHJva2Utd2lkdGg6MS4wNTc1NDUxOTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIg0KICAgICAgIGlkPSJ0ZXh0NDEzNiINCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjg5MTE3MjEsMCwwLDEuODkxMTcyMSw2LjExNzM1MzQsLTQ4LjY5NDQ2MikiPg0KICAgICAgPHBhdGgNCiAgICAgICAgIGQ9Im0gMjAwLjM5NzA1LDg1LjI0NTY4OSAwLjczMjQyLDEuMjY5NTMyIHEgLTcuMTUzMzIsNS4wNTM3MTEgLTEzLjI1Njg0LDEyLjc5Mjk2OCAtNi4xMDM1MSw3LjczOTI2MSAtOC44MTM0NywxNS4xNjExMzEgbCAtMS4wNzQyMiwwLjcwODAxIHEgLTEuMzkxNiwwLjkwMzMyIC0yLjM5MjU4LDEuODA2NjQgLTAuMTcwOSwtMC44Nzg5MSAtMC45NTIxNSwtMi44MzIwMyBsIC0wLjU2MTUyLC0xLjM5MTYgcSAtMS44MzEwNiwtNC41MTY2IC0zLjEwMDU5LC02LjI5ODgzIC0xLjI0NTExLC0xLjgwNjY0IC0yLjcwOTk2LC0xLjk1MzEzIDEuOTc3NTQsLTEuODA2NjQgMy40NDIzOSwtMS44MDY2NCAyLjAyNjM2LDAgNC40NDMzNSw1LjQ0NDM0IGwgMC44Nzg5MSwxLjk1MzEzIHEgNC4zMjEyOSwtNy43MzkyNiAxMC40MjQ4MSwtMTQuMjU3ODE3IDYuMTI3OTMsLTYuNTE4NTU1IDEyLjkzOTQ1LC0xMC41OTU3MDQgeiINCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTo1MHB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6J1dpbmdkaW5ncyAyJzstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidXaW5nZGluZ3MgMiwgTm9ybWFsJzt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwOGMzMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwOGMzMDA7c3Ryb2tlLXdpZHRoOjEuMDU3NTQ1MTk7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSINCiAgICAgICAgIGlkPSJwYXRoNDE0MSINCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8%2BDQogICAgPC9nPg0KICA8L2c%2BDQo8L3N2Zz4NCg%3D%3D%29%3B%0Abackground%2Dcolor%3A%20rgba%280%2C255%2C0%2C0%2E2%29%3B%0Apadding%3A%202px%2050px%202px%205px%3B%0Amargin%2Dbottom%3A%200%2E5em%3B%0Abackground%2Drepeat%3A%20no%2Drepeat%3B%0Abackground%2Dsize%3A%2038px%3B%0Abackground%2Dposition%3A%20top%20right%3B%0A%7D%0Apre%20%7B%0Apadding%3A%202px%3B%0Aborder%3A%201px%20solid%20%23EEEEEE%3B%0A%7D%0A%2Eaaux%5Flocked%20%7B%20background%3A%20gray%3B%0Acolor%3A%20white%3B%0A%7D" rel="stylesheet" type="text/css" /> + <link href="data:text/css;charset=utf-8,body%20%7B%0Aheight%3A%20100%25%3B%0Amin%2Dheight%3A%20100%25%3B%0Afont%2Dfamily%3A%20Calibri%2C%20sans%2Dserif%3B%0A%7D%0A%2Esection%2Elevel1%20%7Bpadding%2Dleft%3A336px%7D%0Anav%2C%20%23TOC%20%7B%0Aposition%3A%20fixed%3B%0Awidth%3A%2021em%3B%0Aleft%3A%200px%3B%0Atop%3A%203%2E5em%3B%0Abottom%3A%202em%3B%0Abackground%2Dcolor%3A%20%23eee%3B%0Aoverflow%3A%20scroll%3B%0A%7D%0A%23HEADER%7B%0Atop%3A%200px%3B%0Aleft%3A%201px%3B%0Aborder%2Dbottom%2Dstyle%3A%20solid%3B%0Aborder%2Dbottom%2Dwidth%3A%20thin%3B%0Aborder%2Dbottom%2Dcolor%3A%20%23aaa%3B%0Aheight%3A%202%2E5em%3B%0A%7D%0A%23FOOTER%20%7B%0Aborder%2Dtop%2Dstyle%3A%20solid%3B%0Aborder%2Dtop%2Dwidth%3A%20thin%3B%0Aborder%2Dtop%2Dcolor%3A%20%23aaa%3B%0Abottom%3A%200px%3B%0Aleft%3A%201px%3B%0A%7D%0A%23HEADER%2C%20%23FOOTER%20%7B%0Awidth%3A%20auto%3B%0Aposition%3A%20fixed%3B%0Awidth%3A%2099%25%3B%0Abackground%3A%20white%3B%0Apadding%3A%205px%3B%0A%7D%0Abody%20%3E%20div%3Anot%28%23TOC%29%3Anot%28%23HEADER%29%3Anot%28%23FOOTER%29%20%7B%0Adisplay%3A%20none%3B%0Apadding%2Dleft%3A%2021em%3B%0Apadding%2Dtop%3A%202em%3B%0Apadding%2Dbottom%3A%202em%3B%0Amargin%2Dleft%3A%201em%3B%0Awidth%3A%2050em%3B%0A%7D%0Atable%20%7B%0Aborder%2Dcollapse%3A%20collapse%3B%0Aborder%2Dspacing%3A%200%3B%0A%7D%0Anav%20ul%20%7B%0Aline%2Dheight%3A%201%2E7em%3B%0Alist%2Dstyle%2Dtype%3A%20none%3B%0Alist%2Dstyle%2Dposition%3A%20inside%3B%0A%7D%0Ath%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Ath%2C%20td%20%7B%0Apadding%3A%206px%3B%0Aborder%2Dwidth%3A%201px%3B%0Aborder%2Dstyle%3A%20solid%3B%0Aborder%2Dcolor%3A%20%23aaa%3B%0A%7D%0Ah1%2C%20h2%2C%20h3%20%7B%0Apadding%2Dbottom%3A%203px%3B%0Aborder%2Dbottom%2Dwidth%3A%201px%3B%0Aborder%2Dbottom%2Dstyle%3A%20solid%3B%0Aborder%2Dbottom%2Dcolor%3A%20%23aaa%3B%0A%7D%0Adt%20%7B%0Afont%2Dstyle%3A%20italic%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Eui%2Dresizable%2Dhandle%20%7B%0Aposition%3A%20absolute%3B%0Awidth%3A%2020px%3B%0Acursor%3A%20ew%2Dresize%3B%0Aright%3A%200px%3B%0Aheight%3A%20100%25%3B%0Atop%3A%200px%3B%0A%7D%0Adiv%2Evecto2%20%7B%0Aborder%2Dleft%3A%203px%20solid%20gray%3B%0Apadding%2Dleft%3A%205px%3B%0Amargin%2Dtop%3A%202em%3B%0Abackground%3A%20rgba%28128%2C128%2C128%2C0%2E05%29%3B%0A%7D%0Adiv%2Evecto2%3Abefore%20%7B%0Acontent%3A%20%27Note%3A%20Vecto%202%2E2%21%27%3B%0Abackground%3A%20gray%3B%0Acolor%3A%20white%3B%0Apadding%3A%205px%205px%205px%205px%3B%0Amargin%2Dleft%3A%20%2D8px%3B%0Afont%2Dweight%3A%20bold%3B%0Adisplay%3A%20inline%2Dblock%3B%0Afont%2Dsize%3A%20smaller%3B%0A%7D%0Adiv%2Evecto3%20%7B%0Aborder%2Dleft%3A%203px%20solid%20green%3B%0Apadding%2Dleft%3A%205px%3B%0Amargin%2Dtop%3A%202em%3B%0Abackground%3A%20rgba%280%2C128%2C0%2C0%2E05%29%3B%0A%7D%0Adiv%2Evecto3%3Abefore%20%7B%0Acontent%3A%20%27Note%3A%20Vecto%203%2Ex%21%27%3B%0Abackground%3A%20green%3B%0Acolor%3A%20white%3B%0Apadding%3A%205px%205px%205px%205px%3B%0Amargin%2Dleft%3A%20%2D8px%3B%0Afont%2Dweight%3A%20bold%3B%0Adisplay%3A%20inline%2Dblock%3B%0Afont%2Dsize%3A%20smaller%3B%0A%7D%0Adiv%2Eengineering%7B%0Aborder%2Dright%3A%205px%20solid%20%23d51000%3B%0Amargin%2Dright%3A%20%2D50px%3B%0Abackground%2Dimage%3A%20url%28data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8%2BDQo8IS0tIENyZWF0ZWQgd2l0aCBJbmtzY2FwZSAoaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvKSAtLT4NCg0KPHN2Zw0KICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIg0KICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyINCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyINCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciDQogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiDQogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSINCiAgIHdpZHRoPSI0NS4xNTU1NTZtbSINCiAgIGhlaWdodD0iNDQuMDI2NjY5bW0iDQogICB2aWV3Qm94PSIwIDAgMTYwIDE1Ni4wMDAwMSINCiAgIGlkPSJzdmc0MTY3Ig0KICAgdmVyc2lvbj0iMS4xIg0KICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MSByMTM3MjUiDQogICBzb2RpcG9kaTpkb2NuYW1lPSJpY29uX2VuZ2luZWVyaW5nLW1vZGUuc3ZnIj4NCiAgPGRlZnMNCiAgICAgaWQ9ImRlZnM0MTY5IiAvPg0KICA8c29kaXBvZGk6bmFtZWR2aWV3DQogICAgIGlkPSJiYXNlIg0KICAgICBwYWdlY29sb3I9IiNmZmZmZmYiDQogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2Ig0KICAgICBib3JkZXJvcGFjaXR5PSIxLjAiDQogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiDQogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiDQogICAgIGlua3NjYXBlOnpvb209IjIuOCINCiAgICAgaW5rc2NhcGU6Y3g9IjE4LjI1ODUwNCINCiAgICAgaW5rc2NhcGU6Y3k9Ijk3LjIzNzM3NCINCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4Ig0KICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiDQogICAgIHNob3dncmlkPSJmYWxzZSINCiAgICAgZml0LW1hcmdpbi10b3A9IjAiDQogICAgIGZpdC1tYXJnaW4tbGVmdD0iMCINCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCINCiAgICAgZml0LW1hcmdpbi1ib3R0b209IjAiDQogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCINCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTEzOCINCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii04Ig0KICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiDQogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiIC8%2BDQogIDxtZXRhZGF0YQ0KICAgICBpZD0ibWV0YWRhdGE0MTcyIj4NCiAgICA8cmRmOlJERj4NCiAgICAgIDxjYzpXb3JrDQogICAgICAgICByZGY6YWJvdXQ9IiI%2BDQogICAgICAgIDxkYzpmb3JtYXQ%2BaW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0Pg0KICAgICAgICA8ZGM6dHlwZQ0KICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPg0KICAgICAgICA8ZGM6dGl0bGU%2BPC9kYzp0aXRsZT4NCiAgICAgIDwvY2M6V29yaz4NCiAgICA8L3JkZjpSREY%2BDQogIDwvbWV0YWRhdGE%2BDQogIDxnDQogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIg0KICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIg0KICAgICBpZD0ibGF5ZXIxIg0KICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjM0LjI4NTcxLC0zNDUuNzkwNzgpIj4NCiAgICA8cGF0aA0KICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiDQogICAgICAgZD0ibSAyNTQuMjg1NzEsMzQ1Ljc5MDc4IC0yLDQgMjEsMTIgYyAwLDEwIC00LDE4IC0xMywyMyBsIC0yMSwtMTIgLTEsMiBjIDUsMTUgMTUsMjUgMzUsMjUgNSwwIDIwLDE1IDI4LDIzIGwgMTYsLTE2IGMgLTgsLTggLTI2LC0yNiAtMjYsLTMxIDAsLTE4IC01LC0zMCAtMzcsLTMwIHogbSAxMjUsNSAtMjAsMTQgLTIsOCAtNTgsNTggLTgsLTUgLTQsNCBjIDAsMTIgLTE0LDE4IC0yMCwxOCBsIC0zMywzMyBjIDAsMTAgMTEsMjEgMjEsMjEgbCAzMywtMzMgYyAwLC02IDYsLTIwIDE4LC0yMCBsIDQsLTQgLTUsLTggNTgsLTU4IDgsLTIgMTQsLTIwIC02LC02IHogbSAtNTAsNjggLTE2LDE2IGMgMTIsMTIgMjgsMjggMjgsMzMgMCwxOCA1LDMwIDM3LDMwIGwgMiwtNCAtMjEsLTEyIGMgMCwtMTAgNCwtMTggMTMsLTIzIGwgMjEsMTIgMSwtMiBjIC01LC0xNSAtMTUsLTI1IC0zNSwtMjUgLTUsMCAtMTgsLTEzIC0zMCwtMjUgeiINCiAgICAgICBpZD0iaW1hZ2Vib3RfMy0wIg0KICAgICAgIHN0eWxlPSJmaWxsOiNkNTEwMDA7ZmlsbC1vcGFjaXR5OjEiIC8%2BDQogIDwvZz4NCjwvc3ZnPg0K%29%3B%0Abackground%2Dcolor%3A%20rgba%28255%2C0%2C0%2C0%2E2%29%3B%0Apadding%3A%202px%2050px%202px%205px%3B%0Amargin%2Dbottom%3A%200%2E5em%3B%0Abackground%2Drepeat%3A%20no%2Drepeat%3B%0Abackground%2Dsize%3A%2038px%3B%0Abackground%2Dposition%3A%20top%20right%3B%0A%7D%0Adiv%2Edeclaration%20%7B%0Aborder%2Dright%3A%205px%20solid%20%2308c300%3B%0Amargin%2Dright%3A%20%2D50px%3B%0Abackground%2Dimage%3A%20url%28data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8%2BDQo8IS0tIENyZWF0ZWQgd2l0aCBJbmtzY2FwZSAoaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvKSAtLT4NCg0KPHN2Zw0KICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIg0KICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyINCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyINCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciDQogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiDQogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSINCiAgIHdpZHRoPSI0OS43OTY4MjJtbSINCiAgIGhlaWdodD0iNDkuNzk2ODIybW0iDQogICB2aWV3Qm94PSIwIDAgMTc2LjQ0NTQzIDE3Ni40NDU0MyINCiAgIGlkPSJzdmcyIg0KICAgdmVyc2lvbj0iMS4xIg0KICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MSByMTM3MjUiDQogICBzb2RpcG9kaTpkb2NuYW1lPSJpY29uX2RlY2xhcmF0aW9uLW1vZGUuc3ZnIj4NCiAgPGRlZnMNCiAgICAgaWQ9ImRlZnM0IiAvPg0KICA8c29kaXBvZGk6bmFtZWR2aWV3DQogICAgIGlkPSJiYXNlIg0KICAgICBwYWdlY29sb3I9IiNmZmZmZmYiDQogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2Ig0KICAgICBib3JkZXJvcGFjaXR5PSIxLjAiDQogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiDQogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiDQogICAgIGlua3NjYXBlOnpvb209IjEuOTc5ODk5Ig0KICAgICBpbmtzY2FwZTpjeD0iMTcuMjkyOTMzIg0KICAgICBpbmtzY2FwZTpjeT0iNDYuODI4NzU0Ig0KICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiDQogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSINCiAgICAgc2hvd2dyaWQ9ImZhbHNlIg0KICAgICBmaXQtbWFyZ2luLXRvcD0iMCINCiAgICAgZml0LW1hcmdpbi1sZWZ0PSIwIg0KICAgICBmaXQtbWFyZ2luLXJpZ2h0PSIwIg0KICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCINCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxOTIwIg0KICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMTM4Ig0KICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiDQogICAgIGlua3NjYXBlOndpbmRvdy15PSItOCINCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgLz4NCiAgPG1ldGFkYXRhDQogICAgIGlkPSJtZXRhZGF0YTciPg0KICAgIDxyZGY6UkRGPg0KICAgICAgPGNjOldvcmsNCiAgICAgICAgIHJkZjphYm91dD0iIj4NCiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ%2BDQogICAgICAgIDxkYzp0eXBlDQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8%2BDQogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPg0KICAgICAgPC9jYzpXb3JrPg0KICAgIDwvcmRmOlJERj4NCiAgPC9tZXRhZGF0YT4NCiAgPGcNCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiDQogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiDQogICAgIGlkPSJsYXllcjEiDQogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNjYuMzQwODMsLTUzLjQ4Njk3NCkiPg0KICAgIDxwYXRoDQogICAgICAgc29kaXBvZGk6dHlwZT0ic3RhciINCiAgICAgICBzdHlsZT0iZmlsbDojMDhjMzAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiDQogICAgICAgaWQ9InBhdGg0MTQzIg0KICAgICAgIHNvZGlwb2RpOnNpZGVzPSIxMiINCiAgICAgICBzb2RpcG9kaTpjeD0iMzU0LjU2MzU0Ig0KICAgICAgIHNvZGlwb2RpOmN5PSIxNDEuNzA5NjkiDQogICAgICAgc29kaXBvZGk6cjE9Ijc3LjY4MDA4NCINCiAgICAgICBzb2RpcG9kaTpyMj0iODguMjcyODI3Ig0KICAgICAgIHNvZGlwb2RpOmFyZzE9IjAuNzQ4OTc3MDMiDQogICAgICAgc29kaXBvZGk6YXJnMj0iMS4wMTA3NzY0Ig0KICAgICAgIGlua3NjYXBlOmZsYXRzaWRlZD0iZmFsc2UiDQogICAgICAgaW5rc2NhcGU6cm91bmRlZD0iMC40Ig0KICAgICAgIGlua3NjYXBlOnJhbmRvbWl6ZWQ9IjAiDQogICAgICAgZD0ibSA0MTEuNDU1MzMsMTk0LjYwMTI3IGMgLTYuNTU2MzksNy4wNTIyNSAtMS44NDI3NiwxNi43ODIwNiAtMTAuMDAwOTksMjEuODk3MDkgLTguMTU4MjQsNS4xMTUwMyAtMTQuODYyNzQsLTMuMzY2NTUgLTI0LjA2Njg2LC0wLjUzNzMyIC05LjIwNDEyLDIuODI5MjMgLTkuOTg2OSwxMy42MTIzMSAtMTkuNjA5NjYsMTMuOTYyOTMgLTkuNjIyNzUsMC4zNTA2MyAtMTEuMTg4MjMsLTEwLjM0Njg4IC0yMC41NzM4NCwtMTIuNDk4NzYgLTkuMzg1NjIsLTIuMTUxODcgLTE1LjQ1NTA3LDYuNzk1MTYgLTIzLjk2MzkzLDIuMjg3NDMgLTguNTA4ODcsLTQuNTA3NzIgLTQuNTE1ODUsLTE0LjU1NDc4IC0xMS41NjgxLC0yMS4xMTExNiAtNy4wNTIyNCwtNi41NTYzOSAtMTYuNzgyMDUsLTEuODQyNzYgLTIxLjg5NzA4LC0xMC4wMDEgLTUuMTE1MDMsLTguMTU4MjMgMy4zNjY1NSwtMTQuODYyNzMgMC41MzczMiwtMjQuMDY2ODUgLTIuODI5MjQsLTkuMjA0MTIgLTEzLjYxMjMxLC05Ljk4NjkgLTEzLjk2Mjk0LC0xOS42MDk2NiAtMC4zNTA2MywtOS42MjI3NSAxMC4zNDY4OSwtMTEuMTg4MjMgMTIuNDk4NzYsLTIwLjU3Mzg1IDIuMTUxODcsLTkuMzg1NjEgLTYuNzk1MTUsLTE1LjQ1NTA2IC0yLjI4NzQzLC0yMy45NjM5MiA0LjUwNzczLC04LjUwODg2NyAxNC41NTQ3OCwtNC41MTU4NTMgMjEuMTExMTcsLTExLjU2ODA5OSA2LjU1NjM4LC03LjA1MjI0NiAxLjg0Mjc1LC0xNi43ODIwNTYgMTAuMDAwOTksLTIxLjg5NzA4NCA4LjE1ODI0LC01LjExNTAzIDE0Ljg2Mjc0LDMuMzY2NTUgMjQuMDY2ODYsMC41MzczMTggOS4yMDQxMSwtMi44MjkyMzIgOS45ODY5LC0xMy42MTIzMDkgMTkuNjA5NjUsLTEzLjk2MjkzNSA5LjYyMjc2LC0wLjM1MDYyNyAxMS4xODgyMywxMC4zNDY4ODYgMjAuNTczODUsMTIuNDk4NzU5IDkuMzg1NjIsMi4xNTE4NzIgMTUuNDU1MDYsLTYuNzk1MTU1IDIzLjk2MzkzLC0yLjI4NzQzIDguNTA4ODYsNC41MDc3MjcgNC41MTU4NSwxNC41NTQ3ODMgMTEuNTY4MDksMjEuMTExMTY4IDcuMDUyMjUsNi41NTYzODQgMTYuNzgyMDYsMS44NDI3NTUgMjEuODk3MDksMTAuMDAwOTkyIDUuMTE1MDMsOC4xNTgyNDEgLTMuMzY2NTUsMTQuODYyNzQxIC0wLjUzNzMyLDI0LjA2Njg1MSAyLjgyOTIzLDkuMjA0MTIgMTMuNjEyMzEsOS45ODY5IDEzLjk2MjkzLDE5LjYwOTY2IDAuMzUwNjMsOS42MjI3NSAtMTAuMzQ2ODgsMTEuMTg4MjMgLTEyLjQ5ODc1LDIwLjU3Mzg1IC0yLjE1MTg4LDkuMzg1NjEgNi43OTUxNSwxNS40NTUwNiAyLjI4NzQyLDIzLjk2MzkzIC00LjUwNzcyLDguNTA4ODYgLTE0LjU1NDc4LDQuNTE1ODUgLTIxLjExMTE2LDExLjU2ODA5IHoiDQogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSI1LjI0NTM5ODgiDQogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSItMy4yODMzMTg2IiAvPg0KICAgIDxjaXJjbGUNCiAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiDQogICAgICAgaWQ9InBhdGg0MTQ1Ig0KICAgICAgIGN4PSIzNTQuNTYzNTQiDQogICAgICAgY3k9IjE0MS43MDk2OSINCiAgICAgICByPSI1MC41MDc2MjkiIC8%2BDQogICAgPGNpcmNsZQ0KICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjcuMDE2MDIxNzM7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSINCiAgICAgICBpZD0icGF0aDQxNTAiDQogICAgICAgY3g9IjM1NC41NjM1NCINCiAgICAgICBjeT0iMTQxLjcwOTY5Ig0KICAgICAgIHI9IjYyLjg5OTM2OCIgLz4NCiAgICA8Zw0KICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjQwcHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTpTYW5zO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O2ZpbGw6IzA4YzMwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzA4YzMwMDtzdHJva2Utd2lkdGg6MS4wNTc1NDUxOTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIg0KICAgICAgIGlkPSJ0ZXh0NDEzNiINCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjg5MTE3MjEsMCwwLDEuODkxMTcyMSw2LjExNzM1MzQsLTQ4LjY5NDQ2MikiPg0KICAgICAgPHBhdGgNCiAgICAgICAgIGQ9Im0gMjAwLjM5NzA1LDg1LjI0NTY4OSAwLjczMjQyLDEuMjY5NTMyIHEgLTcuMTUzMzIsNS4wNTM3MTEgLTEzLjI1Njg0LDEyLjc5Mjk2OCAtNi4xMDM1MSw3LjczOTI2MSAtOC44MTM0NywxNS4xNjExMzEgbCAtMS4wNzQyMiwwLjcwODAxIHEgLTEuMzkxNiwwLjkwMzMyIC0yLjM5MjU4LDEuODA2NjQgLTAuMTcwOSwtMC44Nzg5MSAtMC45NTIxNSwtMi44MzIwMyBsIC0wLjU2MTUyLC0xLjM5MTYgcSAtMS44MzEwNiwtNC41MTY2IC0zLjEwMDU5LC02LjI5ODgzIC0xLjI0NTExLC0xLjgwNjY0IC0yLjcwOTk2LC0xLjk1MzEzIDEuOTc3NTQsLTEuODA2NjQgMy40NDIzOSwtMS44MDY2NCAyLjAyNjM2LDAgNC40NDMzNSw1LjQ0NDM0IGwgMC44Nzg5MSwxLjk1MzEzIHEgNC4zMjEyOSwtNy43MzkyNiAxMC40MjQ4MSwtMTQuMjU3ODE3IDYuMTI3OTMsLTYuNTE4NTU1IDEyLjkzOTQ1LC0xMC41OTU3MDQgeiINCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTo1MHB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6J1dpbmdkaW5ncyAyJzstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidXaW5nZGluZ3MgMiwgTm9ybWFsJzt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwOGMzMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwOGMzMDA7c3Ryb2tlLXdpZHRoOjEuMDU3NTQ1MTk7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSINCiAgICAgICAgIGlkPSJwYXRoNDE0MSINCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8%2BDQogICAgPC9nPg0KICA8L2c%2BDQo8L3N2Zz4NCg%3D%3D%29%3B%0Abackground%2Dcolor%3A%20rgba%280%2C255%2C0%2C0%2E2%29%3B%0Apadding%3A%202px%2050px%202px%205px%3B%0Amargin%2Dbottom%3A%200%2E5em%3B%0Abackground%2Drepeat%3A%20no%2Drepeat%3B%0Abackground%2Dsize%3A%2038px%3B%0Abackground%2Dposition%3A%20top%20right%3B%0A%7D%0Apre%20%7B%0Apadding%3A%202px%3B%0Aborder%3A%201px%20solid%20%23EEEEEE%3B%0A%7D%0A%2Eaaux%5Flocked%20%7B%20background%3A%20gray%3B%0Acolor%3A%20white%3B%0A%7D" rel="stylesheet" type="text/css" /> <link href="data:text/css;charset=utf-8,%40media%20print%20%7B%0A%23CONTENT%20%7B%0Adisplay%3A%20none%3B%0A%7D%0A%23HEADER%20%7B%0Adisplay%3A%20none%3B%0A%7D%0Abody%20%3E%20div%20%7B%0Adisplay%3A%20block%3B%0Apadding%2Dleft%3A%202em%3B%0A%7D%0A%2Esection%2Elevel2%20%7B%0Apage%2Dbreak%2Dbefore%3A%20always%3B%0A%7D%0Aa%2C%20a%3Avisited%2C%20a%3Alink%20%7B%0Acolor%3A%20blue%3B%0A%7D%0A%7D" rel="stylesheet" type="text/css" /> - <script src="data:application/x-javascript;base64,dmFyIGZpbGVyZWY9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0JykNCmZpbGVyZWYuc2V0QXR0cmlidXRlKCJ0eXBlIiwidGV4dC9qYXZhc2NyaXB0IikNCmZpbGVyZWYuc2V0QXR0cmlidXRlKCJzcmMiLCAiaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbWF0aGpheC8yLjcuMS9NYXRoSmF4LmpzP2NvbmZpZz1UZVgtQU1TLU1NTF9IVE1Mb3JNTUwiKQ0KZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoImhlYWQiKVswXS5hcHBlbmRDaGlsZChmaWxlcmVmKQ==" type="text/javascript"></script> <script type="text/javascript">/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */ !function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=Array.isArray(d)))?(e?(e=!1,f=c&&Array.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e);return!1}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}return!1}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,N,e),g(f,c,O,e)):(f++,j.call(a,g(f,c,N,e),g(f,c,O,e),g(f,c,N,c.notifyWith))):(d!==N&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S), a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},U=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function V(){this.expando=r.expando+V.uid++}V.uid=1,V.prototype={cache:function(a){var b=a[this.expando];return b||(b={},U(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){Array.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(L)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var W=new V,X=new V,Y=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function $(a){return"true"===a||"false"!==a&&("null"===a?null:a===+a+""?+a:Y.test(a)?JSON.parse(a):a)}function _(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Z,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c=$(c)}catch(e){}X.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return X.hasData(a)||W.hasData(a)},data:function(a,b,c){return X.access(a,b,c)},removeData:function(a,b){X.remove(a,b)},_data:function(a,b,c){return W.access(a,b,c)},_removeData:function(a,b){W.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=X.get(f),1===f.nodeType&&!W.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),_(f,d,e[d])));W.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){X.set(this,a)}):T(this,function(b){var c;if(f&&void 0===b){if(c=X.get(f,a),void 0!==c)return c;if(c=_(f,a),void 0!==c)return c}else this.each(function(){X.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=W.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var aa=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ba=new RegExp("^(?:([+-])=|)("+aa+")([a-z%]*)$","i"),ca=["Top","Right","Bottom","Left"],da=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ea=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function fa(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&ba.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ga={};function ha(a){var b,c=a.ownerDocument,d=a.nodeName,e=ga[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ga[d]=e,e)}function ia(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=W.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&da(d)&&(e[f]=ha(d))):"none"!==c&&(e[f]="none",W.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ia(this,!0)},hide:function(){return ia(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){da(this)?r(this).show():r(this).hide()})}});var ja=/^(?:checkbox|radio)$/i,ka=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c<d;c++)W.set(a[c],"globalEval",!b||W.get(b[c],"globalEval"))}var pa=/<|&#?\w+;/;function qa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(pa.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ka.exec(f)||["",""])[1].toLowerCase(),i=ma[h]||ma._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g,h=[],i=b.delegateCount,j=a.target;if(i&&j.nodeType&&!("click"===a.type&&a.button>=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c<i;c++)d=b[c],e=d.selector+" ",void 0===g[e]&&(g[e]=d.needsContext?r(e,this).index(j)>-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i<b.length&&h.push({elem:j,handlers:b.slice(i)}),h},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==xa()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===xa()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&B(this,"input"))return this.click(),!1},_default:function(a){return B(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?va:wa,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:wa,isPropagationStopped:wa,isImmediatePropagationStopped:wa,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=va,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=va,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=va,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&sa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ta.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return ya(this,a,b,c,d)},one:function(a,b,c,d){return ya(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=wa),this.each(function(){r.event.remove(this,a,c,b)})}});var za=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/<script|<style|<link/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,Ca=/^true\/(.*)/,Da=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}X.hasData(a)&&(h=X.access(a),i=r.extend({},h),X.set(b,i))}}function Ia(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ja.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ja(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,na(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ga),l=0;l<i;l++)j=h[l],la.test(j.type||"")&&!W.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Da,""),k))}return a}function Ka(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(na(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&oa(na(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(za,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d<e;d++)Ia(f[d],g[d]);if(b)if(c)for(f=f||na(a),g=g||na(h),d=0,e=f.length;d<e;d++)Ha(f[d],g[d]);else Ha(a,h);return g=na(h,"script"),g.length>0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(na(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ja(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(na(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var La=/^margin/,Ma=new RegExp("^("+aa+")(?!px)[a-z%]+$","i"),Na=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",ra.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,ra.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Oa(a,b,c){var d,e,f,g,h=a.style;return c=c||Na(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ma.test(g)&&La.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Pa(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Qa=/^(none|table(?!-c[ea]).+)/,Ra=/^--/,Sa={position:"absolute",visibility:"hidden",display:"block"},Ta={letterSpacing:"0",fontWeight:"400"},Ua=["Webkit","Moz","ms"],Va=d.createElement("div").style;function Wa(a){if(a in Va)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ua.length;while(c--)if(a=Ua[c]+b,a in Va)return a}function Xa(a){var b=r.cssProps[a];return b||(b=r.cssProps[a]=Wa(a)||a),b}function Ya(a,b,c){var d=ba.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Za(a,b,c,d,e){var f,g=0;for(f=c===(d?"border":"content")?4:"width"===b?1:0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+ca[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+ca[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+ca[f]+"Width",!0,e))):(g+=r.css(a,"padding"+ca[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+ca[f]+"Width",!0,e)));return g}function $a(a,b,c){var d,e=Na(a),f=Oa(a,b,e),g="border-box"===r.css(a,"boxSizing",!1,e);return Ma.test(f)?f:(d=g&&(o.boxSizingReliable()||f===a.style[b]),"auto"===f&&(f=a["offset"+b[0].toUpperCase()+b.slice(1)]),f=parseFloat(f)||0,f+Za(a,b,c||(g?"border":"content"),d,e)+"px")}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Oa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=Ra.test(b),j=a.style;return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:j[b]:(f=typeof c,"string"===f&&(e=ba.exec(c))&&e[1]&&(c=fa(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(j[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i?j.setProperty(b,c):j[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b),i=Ra.test(b);return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Oa(a,b,d)),"normal"===e&&b in Ta&&(e=Ta[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Qa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?$a(a,b,d):ea(a,Sa,function(){return $a(a,b,d)})},set:function(a,c,d){var e,f=d&&Na(a),g=d&&Za(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=ba.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ya(a,c,g)}}}),r.cssHooks.marginLeft=Pa(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Oa(a,"marginLeft"))||a.getBoundingClientRect().left-ea(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+ca[d]+b]=f[d]||f[d-2]||f[0];return e}},La.test(a)||(r.cssHooks[a+b].set=Ya)}),r.fn.extend({css:function(a,b){return T(this,function(a,b,c){var d,e,f={},g=0;if(Array.isArray(b)){for(d=Na(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&da(a),q=W.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],cb.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=W.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ia([a],!0),j=a.style.display||j,k=r.css(a,"display"),ia([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=W.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ia([a],!0),m.done(function(){p||ia([a]),W.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=hb(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],Array.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=kb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=ab||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(i||h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:ab||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);f<g;f++)if(d=kb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,hb,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j}r.Animation=r.extend(kb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return fa(c.elem,a,ba.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(L);for(var c,d=0,e=a.length;d<e;d++)c=a[d],kb.tweeners[c]=kb.tweeners[c]||[],kb.tweeners[c].unshift(b)},prefilters:[ib],prefilter:function(a,b){b?kb.prefilters.unshift(a):kb.prefilters.push(a)}}),r.speed=function(a,b,c){var d=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off?d.duration=0:"number"!=typeof d.duration&&(d.duration in r.fx.speeds?d.duration=r.fx.speeds[d.duration]:d.duration=r.fx.speeds._default),null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){r.isFunction(d.old)&&d.old.call(this),d.queue&&r.dequeue(this,d.queue)},d},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(da).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=kb(this,r.extend({},a),f);(e||W.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=W.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&db.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=W.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),r.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(ab=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),ab=void 0},r.fx.timer=function(a){r.timers.push(a),r.fx.start()},r.fx.interval=13,r.fx.start=function(){bb||(bb=!0,eb())},r.fx.stop=function(){bb=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var lb,mb=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return T(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b), @@ -87,12 +86,15 @@ code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Inf showContent($("#user-manual")); } + $("#TOC").resizable(); + $("#TOC").resizable({ handles: "e", resize: function(event, ui) { $("body > div:not(#TOC):not(#HEADER):not(#FOOTER)").css("padding-left", ui.size.width); } }); + $("#TOC").scroll(function() { $(".ui-resizable-handle").css('top', $("#TOC").scrollTop()); }); @@ -2758,10 +2760,10 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge <p>This pedal release decision is based on an estimation of kinetical and potential (height) energy gain versus the expected dissipated energy tue to vehicle resistances during the route section ahead.</p> <p>For an upcoming target speed change the energy level after the speed change is compared to the vehicle’s current energy level (kinetic and potential energy). The difference of those energy levels is used to estimate the average deceleration force to reach the next target speed. Coasting starts if the vehicle’s (estimated) average resistance force during coasting multiplied by a speed dependent ‘Decision Factor’ becomes smaller than the average deceleration force. (For details on the equations please see the ACEA White Book 2016, Section 8)</p> <p>The <em>Decision Factor (DF)</em> depends on the next target speed and the speed change:</p> -<p><span class="math inline">\(DF_{Coasting} = 2.5 - 1.5 * DF_{vel} * DF_{vdrop}\)</span></p> -<p>whereas <span class="math inline">\(DF_{vel}\)</span> and <span class="math inline">\(DF_{vdrop}\)</span> are speed dependent and speed change dependent lookup curves, giving a value from 0 and 1.</p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="DF_{Coasting} = 2.5 - 1.5 * DF_{vel} * DF_{vdrop}" title="DF_{Coasting} = 2.5 - 1.5 * DF_{vel} * DF_{vdrop}" /></p> +<p>whereas <img style="vertical-align:middle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAARCAIAAAAt9wkYAAAABmJLR0QA/wD/AP+gvaeTAAADbUlEQVRIibWWT0gqXRjGX52xTCNwyrAW0SYSipDIxlCLwsD+QLVoZRQkBK0CV5K0aNUuaFGbQNpFUcvQCizoD5jQUGQRhjGBksxIZWmSzcxdzPfZNFPfd5N7n9U7z/nNO8+cczgzMo7jAAAAWJbNZDIgUUlJCYIgIvM7mJdKpZLL5d+Nfic0X8Xj8aWlpePj41QqZbfbeZOiqFgs5nA4HA6H8LYvYQCIRqORSGRxcdFkMv00CnCf1dfX19PTI3T29/dxHF9ZWeEkksIcxw0PD4dCISn8v/o0jel0Oh6P19fXC82Ojo7GxsbV1VXRO3wJA4BOp2tpafnxlAB8iuL3+wHAaDSKIIPBQFHU9fX1f8DRaJQvNBpNATnEUY6OjliWFa49r8fHR4ZhcrncdzDLsh6Ph/dnZ2cLi4IKLy4vLysrKzEME0E3NzcIgpSWlorgsrKyzc1NADg7O1Or1YUlyGQyp6enMpnsI0oikUgmkxaLRYQyDEOSZHl5eW1trQhuamrS6/UAQBBEa2trYVECgcDCwgKO4x8LdHBwwDCMtOP29vbT09PQ0JDQ5GGbzWa1Wq1Wq0Kh6OzsLCxKf38/iqJms/kjSjAYRBBE2nF9fV2r1TqdTqEpgmdmZurq6qSPIQgilUrxdX5fA0A4HCYIgq/j8fjz87PJZJILhzEM0+l0wl7z8/NXV1dut7uoqEjoi+CKigppDp/PR9P0yMgIH31ychIAUqnU9PQ0SZK3t7derxcAAoEAhmEajUaej0ZRlPCQyGQyHo/H7/fPzc2JpkoKfymKomia5mscxw0GA8uyExMTdru9t7cXRf/ZpsFgsKGhAQDQt7c3t9v98PCgUCiSyaTL5QKAXC5H07TZbN7a2lIoFPnuQjgWi7lcrvb29sHBwS+jjI6Ojo2NdXV18Zd6vX5nZ+f+/j6RSCwvL1dVVY2PjwNAJBKZmpoCkBz8f1Cvr69tbW0kSXIcFwqFTk5OvF6v0+kUMnd3dxaL5fz8/OXl5cffz9/X+/t7NputqakBgIuLC6PRWF1drVQq+VGapn0+3+HhoVarDYfDn86VPy61Wt3c3Ly2tpbNZm02GwB0d3fv7e1tbGwgCCKTyQYGBkiS3N3dTafTKpVKxv37v/I3xHFcOp0uLi7ObzjeUSqV+W2bzWZRFEVR9Bf42HusWic7MgAAAABJRU5ErkJggg==" alt="DF_{vel}" title="DF_{vel}" /> and <img style="vertical-align:middle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD8AAAARCAIAAADlm+POAAAABmJLR0QA/wD/AP+gvaeTAAAE2klEQVRIic2WbUhTbRjHr53tHHKroebmYuIbZaXlLG0KtbmFOYcaLgiigTGi/C6ig/VCBBmI7tP8LCQGoWjJarEgSzYWBlMp19gbO7mNWGtr6tCNnT0fjo8ez+yhpyfj+X26z//8L+7/fd/XOdyMTCYDAABAEEQikYAscnJymEwmTfyRmYTNZiMI8qO3vxHW1igYDA4PD1ut1ng83tLSQorhcDgQCKjVarVaTS3b1QwAXq/X5XIZDIaGhoY/kB4yO2ltbVUqlVRlZmamvr5+ZGQkk0W2OZPJXL58eW5uLtu8F+w437W1tWAwePToUarY2Nh44sSJx48f05a9qxkABAJBXV3dXmx0NjvSm0wmADhz5gzNVFNTEw6HnU7nP5i9Xi85yMvL+5mJnU7n3bt3Ozs7fyn2JjvSWywWgiCofUwSi8XS6XQqlfqRmSAInU5H6vfu3fuZicvKygoKCsLh8K9np361ALC0tMTn8/Pz82kmt9vNZDL3799PM3O53ImJCQBYWFjgcDj/amIMw3AcP378+C/F3mQ7/ZcvXyKRyLlz52iOdDrt9/sPHjxYWlpKM1dXVx87dgwA7Ha7WCymFa6srExOTubl5bW3twcCgUePHmm1WgDAcfzFixeHDh369OnTtWvXAMBms9lsto6Ojvfv3yMIcunSJQAIBALPnj1jsVi1tbWnT58mZ5mdnb148eKHDx/8fr9CodjunNnZ2XQ6nR3i5cuX379/V6lUVJE0NzU1SSQSiUSCoqhcLqcVTkxMiMXigYEBcgusVisAfP78Wa/XazSa8vLyUCikVCoBwOFwBIPBBw8esNlsg8FABr1z505nZ+eNGzfu37+/trYGAPPz8+vr67du3RKLxc3NzQ8fPtxO/+7dOyaTmR3iyZMnPB7v+vXrVJFmvn379pEjR2iF5eXlT58+JQ+nuLi4ra0NAHp7exsbGzEMc7vdAoGAw+H4/X65XO7xeGQy2YULF8bGxkhbT08P2Y0Yhn379i0ej586dcrhcNTW1vL5/H379uE4vp3+48eP+fn5AoGAmmBoaMjhcGi1WgzDqDrNXFBQAFlIpVKLxSKVSgGAIAgURZeXlz0eD7kMi8VSUVEBACUlJcXFxV6vt6WlBUXRwsJCs9kMAOSyCYLw+XwMBoPL5YpEIpfLRW6Z2Ww+cODAZvpgMBgOh6k/70QiodPpTCZTf38/7UCyzbuysrKC4/jVq1cBYHx8XKVSuVwuoVDIYrEAYGlpqaGhYWpqCgCMRiOPx9v6WySTycOHDzMYDACYnp4uKioSCoUAYLfbAUAkEgHAmzdvFAoFK5lMarXaaDSKomgkEunu7gaAVCr19evXs2fPGo1GFEW3AlHNgUCgu7tbKpV2dHTsmh5F0ZycHARBcBzHMCw3N7e6uprNZgOAzWaLRqNSqfT169fkY1VV1VZhZWXl6OgoAIRCoampqcHBQXIlb9++LSwsZDAYi4uLPB7v5s2bjMzft7S9YHx8PB6P8/n85uZmsvfGxsZSqdTJkycdDkcmk1GpVBwOR6/Xnz9/ntxUklevXvl8vo2NjStXrmy1pUajEQqFVVVVsVisq6sLQRD6Ped/SzKZlMlkdrudKv6Je+x/J5lM9vX1ra6uPn/+nKrvbef8RlZXVwEAQRDyyyH5C0CEe8mufaWDAAAAAElFTkSuQmCC" alt="DF_{vdrop}" title="DF_{vdrop}" /> are speed dependent and speed change dependent lookup curves, giving a value from 0 and 1.</p> <p>For the look ahead coasting target speed changes within the preview distance are considered.</p> -<p><span class="math inline">\(preview distance [m] = 10 * vehicle speed [km/h]\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWkAAAAUCAIAAADA0luyAAAABmJLR0QA/wD/AP+gvaeTAAAV3ElEQVR4nO1ce1RTR7efcCChiWCQioJvAyhtQZ7q0vtJQYKlgGhBJNLKSwQBAS2+MBRUbFEEF4qIj4ptFQJCW2pDoYhiV1EhQEXbskgDUUAKBQkEiSTmJPeP8U7TkwSsYq3f9fdf5rFnz9579uzZMzkkpVIJXuGFAsdxiUQCAMAwjEqlPgUFqVQqk8kAAGQymUKhjDN/fwc4jgMAMAx7gTy8pHhRSpRKpU8+nKqt6j5Prl4M4PQMDAxeNCNPiqKiopycHENDQzMzs1OnTj0FhaNHj165cmVkZGTBggWZmZnjzuGTIzk5GQCQmpo6jjSHhoaoVOoz+iOJRIJh2It1rBqBGNu1a1dTU5O+vr6Li0tCQgJqIJVKcRx/uk1lTPB4vMzMzIKCAkK5tkVUVVWVlZUFAw6d58HQmMBxPCws7Pjx4+NOOTU11dfX19nZWSwWo8K0tLTY2Ngx+0IljTtLY0KhUNjb23O53KdzHACAhIQELpcbGho6XvwLBAIWizU8PIxKZDJZWlpaaGhoaGhoWloa3CERurq6eDweAECpVNJoNAAAj8fr6up6RjYKCgqCg4OdnZ2Lioq0tRlTuQ0NDdHR0S4uLrt27XpGfsYXBMZwHA8NDeVyuchxjIyMxMTEeHh4+Pn5PSceSkpKbGxsCIUaFxGEu7s7l8vlcDhyufzF+A65XN7X1zd79uxxp8xms19//XVDQ0NowRCdnZ2mpqZj9g0ICNizZ8+4s/RyoaSkJCYmJikpqbm5WdUTRUZGtra25ubm5ubmtra2RkZGqva6d+/e1q1bExMTLSwsTE1NExMTt27deu/evWdkhsViubq6KhQKR0dHbW3GVK6Dg8OWLVukUimDwXhGfsYXYzKmr6+fnZ2NYdiTWO9TAMfxuro6dcfEZrNnzpxJWETqeDFnFgqFUlpa+jwo4zguEAgYDIZqiJudnT1mR5FIJBQK16xZ8zy4eong5eW1atUqDofT3NyMCmtraxsbGy9cuEAmkwEA27dvX7NmTW1t7aJFi2ADJyenioqK7OzsS5cuAQBsbGwqKirGJcxuaGig0+lz587V1uBJlPv9998DANzd3Z+dn/HFmIyJRKLe3t5Vq1Y9j9HLyspMTEwsLCzUq/h8PmERqePFxB3PD0KhcGBgwN7e/u925HK5JBLJw8PjeXD1EoFCoahbTGlpqeoCnjt3Lp1OJ3j/W7duNTU1YRiGYVhTU9OtW7fGhZ+WlpYxjXhMNDY2ju6AXhTGZIzL5YLn5vW++eYbZ2dn9XKRSNTd3T3mIvoz7sjNzb13797GjRuNjY2PHz/e1dUVEBDg5OQEACgvL//+++9ZLJa9vX1RUVFDQ8PatWthFQBAIpF8/vnnAoFgypQp0dHRcLc5efJke3v7Rx99BHeqnJycuXPnvvPOOwCAwsLCn3/+eePGjTNmzECj83i8b775RiKRrFmzZvHixQAAoVB49OhRd3d32AsA0NHRAQCYMWOGUCg8depUSkoKJA4AKCsru3z5srm5uUKhACqybmhoyM/PRxOBaGxsLC0tHR4e9vPzW7x4cWNjo0AgKC8vnzhxYmVlJQDA19cXGqtMJjt79iyfz3dzc3NxcdHV1YXlSFZmZmZQIKpzh8BxvKKioqqqasKECSEhIeiAplFcBMC5Ozg4BAYG3rlzJy8v78GDB1AyHR0dRUVFXV1d9vb2gYGBo2t3vNDW1kYmk9ECxjCMTCa3tbWhBuXl5fv379++fbtIJMIwzNDQcNu2bbt370a6A2oKJSgRiYtKpYaFhUFxQSP29PQsKChQF7JG5SLxmpqabtq0iUqlagxF1e0NqKgb9YWF+/btMzQ0jIuL6+rqysvLUygUqtarkXOgXdFIg5GRkeqMEcDj8ZBz4fF4hYWF7u7u7u7uqlzJ5fLjx4///vvvdnZ2AQEBOI7DWZiYmMTHx6M1QoBEIuHz+RkZGepV0GH95z//ycjIQGTVmXwcd9TU1HR0dIhEos2bN7PZ7KVLl27YsCE+Pv769esSiaS4uPiNN96Ij4+HSZ2pU6fCcxocxtvbW6FQsNlsExOT8PBwAMCRI0emTZvW1dW1d+9eAMDw8PDZs2ezsrJg1YQJE0Qi0Y4dO5DCQkNDs7KyVq5cGRUVlZ6eXltb297efurUqaCgoKSkJJSxi4mJOXz4MAAgLy+vrKyspKQEdS8vL2ez2Y8ePeJwOEjW3333XU1NzVtvvRUfHw+5hYWZmZnr169ns9mffvppbW3twMAAAKCzs1PVlwEA4BFGJpOx2eyKigoPDw+YDUGySkhI+OijjwAAycnJ7e3tcO5oUuvXry8vL4+KigoICNi6deso4lJHRkbGunXr0tPTDx48eOrUqfXr12/YsCE2Nra4uDg3N3fZsmUbNmzIysq6ePGixu4IHA4ndixwOJzRiQAA+vv7Ry9kMpmXLl3y9vZubGz85ZdfvL29L126xGQyUQN1haoqUSgUenl51dTUREVFeXp6btq0CYkLAPDrr7+qC1mjcoVCoZ+f38DAAJvNNjc3hzlUQiiq0d4AADiOh4SEUCiU5OTkRYsWofxrZmamo6NjZWVlREQE1IW5uXlQUBC8qhyFc42K5nK5sbGxVlZWUVFRe/fuHTNGRmFXdnZ2Q0PD1KlTU1JShoeHEVeJiYlwwbLZ7HPnzn3yySd79uyZPn06m82+fPlySkqKNsqff/65paWloaGhehWPx3vttddOnz6NyKanp6s3e+w7Lly4kJCQMDIy8scff6Smpi5evNjKyopGoxUWFn755Zeurq5kMlkikTg7O7NYrMHBQVtbWwqFcv369ZSUlODg4KioKDqdvnTp0qGhIbFYLBAIPD09+/r6oJXQaLTg4GCFQqFaBQMEAEBkZGRXV9eZM2ecnJwYDIaRkdH9+/dzc3NDQkLa29vlcjnM2IlEort378KcGZvNNjIygt0TEhK6uroOHz5Mp9MjIiJwHEeO/Ouvv46Oju7p6VF9w5Kbm8tkMhkMhp6e3u3bt+/fv+/q6spkMgcGBjw8PPz9/f39/TEMk8lkmzZtmjVrVkxMDKTc398/f/58JCsdHZ22tjZvb28Wi2VgYODk5CQUCkdGRqB1BgcHT5o06ciRIwwGo6CgoLOzUy6XaxSXukpEIpGenh7MnzU3N+/fv5/BYFhZWU2cOPGLL75ITk52cnKCP+vq6kYxOwDA/Pnz/2cswEk9I9D1p6Wl5fTp04Ha2UddoUiJEokkLCzM3NwcztTJyQnHcblcDgDg8Xh6enpBQUHqQlZXrlAoDAsLY7FYO3fupNPpZ8+e7e3tBWo5BY32BgCoqKj4448/goKCDAwMKisr+/r6YPvW1lYvLy+ZTPbw4UPI4erVq/v7+0tLS7Vxrk3RAoEgJSXF19f33XffZTAYb7zxBhgr2QHPDtCQIiMjBwcH7e3taTRaa2urj4+PUqlsaGiAC5ZOp1tYWJSVlYWEhLz77rt0Ot3S0lI1aUVAdXW1j4+PxqqWlhYKhZKWlobI3rx5U73Z4zOLnZ2doaGhQCCwsrJCwZVSqVQqlRQKxdPTc9euXSYmJp6engCAffv2wQZpaWlkMllPT6+oqGhgYKC6unrTpk1tbW0ffPABjB127twJW/r7+/P5fFgFPUhYWBgA4OLFi42NjcuWLfv6668BADdu3KBQKCtWrOjt7bWwsEhOTp43bx50jar5CDKZbG1t/c4779TU1Pzwww8RERHQTNvb24eHh6Ejl0qlLi4uGIZdu3btzTffRBf7IyMjn332WU9Pj4uLS2VlJbzBVk92ZGRk9PT0HD16FP6sr69HDezs7IyMjPh8vq2tLQp3GxoaDAwM9PX1Yd/m5mZ0rRgeHr5q1SoajaZRXOoquXv37rp16yBLiYmJyIx6e3u3b98OQ1D4ExrfKLC1tbW1tR29zfgiKipKY/m8efMICkVKTE1N7e/vt7S0LCoqwnH88uXLLi4uMMPf0tJiY2OjLmSNyk1MTFQqlevWrYONk5KSJk+eDP6aU9BmbwCAwcHB3t7e0NBQJpMZHx8PV4FUKl2+fDmMXFAeHfo+hUKhjXNtik5KSpowYQKLxYJ0WltbnyTZwefzly9fDm0PLj3IFbSBiIgItGD5fP7ChQvNzc3RTysrK42UhUJhd3e3amCIAB1WeHi4KlmNdB7HHUFBQYTQDnKmo6OzZs0aKpXa0tJC6C8Wi+/evTt37lwdHR0AwKxZs/Ly8jw8PGxtbZ2cnL766isjIyOUhy8vL1+4cCGsysnJIZPJQUFBAICqqioSiYRu4KKjo48dO4ZhWFBQkFgs5vP5KJfD4/FMTExQuPHw4UMjI6OioiISiRQQEAALVXcYCoUSEBAAXVhISAhiOzY2ViaTcTic8PBw5BoIxAEAV69eVU1BqzYICgqC8nVxcYG1OI7fvn3bwcFBY98ZM2bY29trE5e6SqCU4IiICMG7FRYW6unpQVf+D4BEIj1hoTaoKxT8nxJ/+uknIyOjKVOmAAAwDMvMzIRHY0LGTlXI6soViUTNzc0LFixAwY69vf2MGTMIyQ5t9gYA8PX1tbe3b2pqOnDggK+vb09PDxqIELnAJa2jo6ORc22KJnCoMQtDAI/Hgws4Nzd38+bN6E0N5AqaBDJ+KK6FCxfCnwKBoLu7e/ny5RopFxYWLlmyRONLOUJ2dhQ6f+ZKCQIqLCwkkUjQ10K21q9fr95/xYoV/v7+6uVNTU3W1tZILjdu3Dh48CAAAMfx6upqR0dHKpUqFAqVSuXkyZM1UuZyuXK5HImGz+fPmzcPzcfExAQWTp48Ga15tMMIhcI5c+YAAM6fPz916tRFixbBkoqKCiaT6ebmduvWrczMTC6X++GHH1IoFFXPKBQKjY2Nu7u7ly1bhpiBDWQyWV9fn5mZGWEl19fX9/f3+/j4dHR0UKlUQt8nEZc6CM6a4N2qq6sZDIahoSGaqUZwOJxr166NPtCSJUuQkLXBysrq5s2bOI4ju5fJZH83oiEotLa2Fm65OI5bW1uri4VgxKpCNjMzwzBMVbk3btwAAKg/A0E7ItSdNnvr6Ojo7e09c+bMwMBAfn5+Xl4eh8PZvn07rCXchly9epVKpfr4+OTl5WnkHGhSdHl5uSqHiDE0HXUi0AaysrJaWlrWrl1bUlLCYrGQxgkmQbDJ4uJiKpXKZDI1Wsi1a9d2796tPiL4a3Z2dDp/3tESBHTlyhVbW9slS5aoswWBYZienp7q5iOTydBOjuM42jMFAoGBgQH0oPX19d3d3YGBgQKB4MyZMxMmTCCwnp+fDxP4CoWCTqfD+HZ4eLi3txf5juLi4uDgYADAxIkTVUeHjlwsFkM2pFJpfX093OgOHjxYVla2c+fOy5cvUygUJycnDw8PY2NjCoUiFou7u7uhUmtqaoqLiykUCpVKRVNraWmBDYqKiq5evaquNhhkOTo6pqenYxhmZGRE2JOzsrIUCsUo4iKAsIeAv7oSeOhzdnaGMtRIAWK88h1ubm4DAwPolaFYLB4YGHBzcxuzoypUFQoA+Oqrr9auXQsA0NfXVxeXXC4nGLGqkEdGRgjKdXR0JJFI6uKFeVB3d/czZ87cvHlTm71t3rwZvqOn0+kwSYHOg4QAQSKR/PLLLywWi0qlauRcm6LhRFA5dCXu7u4ZGRmq73cRVMMu+DZMoVCoanz03QWe5nR1deGerQqBQPDgwQNtz+0Il+Kj0NFRFdDIyIhAIMBxPDU1dWhoCD2yVA/pAQA0Gm3JkiXXr1/HcRzH8Rs3bkRFRXl5ecFaY2PjpqYmKOvs7OykpCRY3tbW9tprr7311lunT58OCQkJCwt78OBBS0sLAGBoaCgpKamvrw9K2dzcfHBwEFaVlJSQyeT29nY4t8HBQeiYYBJLJpNJJJJt27bJZDJzc/PCwkJXV1cAgFQqffjwobOz8/nz55cuXQoAsLOzg2e8O3fuVFRUoHQDiUQyNzcXCATFxcVxcXHQuTx48AAK+sCBAyQSicFg1NXVwWMCQW2dnZ3W1tZCoZBGo9Hp9Pfee6+jowNGmK2trXFxcZaWlnQ6fRRxEUBw1gRX0tLSguP42rVroQw1UoCwtbX1HwuE8EEqlQ4NDd25cwcA0NTUNDQ0hOO4h4eHqakpSranp6ebmpr+3bcwUKECgQAAcPHixenTp0NFw1wYvLZA4tLV1SUYsaqQaTQaQbkWFhZ2dnY///wzAEBVvDo6OjQabebMmbdu3Vq+fLk2e9PX19+yZQvs+9lnn5mYmKDZwQCht7dXIpFIJJLw8PD58+fDtI5GzrUp2tHR0dTUVCQSQf1WVlbSaLQpU6ZIpVKNlx2qYRfcpx0cHDgczsqVK9VNAvzVJqVSaX9/v7Ozc0FBAbR8VZw+fdrNzU1jpEM4J45OhwTT1AKBwM/Pb/Xq1Z2dnTiOz5s3b8uWLehmGAolOjqa0Fkmk6WkpHR3d9NotNmzZ6MrcQBAR0fHoUOHHj16RCaT4+LiULQjk8mioqIoFIqPjw+US3l5eUlJCYVCIZPJ/v7+KDEGAMjPz//222/pdLqNjc2KFSvYbPbEiRMnTZqEno0AALKzsxsbGw0NDQMDA+/fv19YWMhgMNhsNqz9+OOPf/vtt0WLFsE31MePH//111+VSqWurm5gYCB6FwAvwKZNm5aYmIhu9bdt2/bo0aNJkyZFRESUlpbyeDx3d/fAwECpVBoQELBjxw7EKo/Hy8nJMTMzS05OhoxBrvT19Y2NjdGdvzZxnT9/vq6uDt5hQ5w4ceL27dvoxWRDQ8PevXsLCgqQeHfs2CEWi1euXKm6gNXpPAVKSkquX78ul8sVCgV86PX+++/b2toKhcLdu3fD1PLQ0ND+/ftHOStpQ35+flVVFYVCsbGxUX3VnpOT09jYSCaTkbigkDdu3IgmqC5kgnKRyjAMQ+KVyWTwWAqfRQAt9iYUCmGwQyKRZs6cGRcXhwwsJyfn5MmTMTEx8Fjk6uqK0rEaOQfaFS0UCvfv308mk+fMmRMREbF79254MQztMC4ubuHChejNzokTJ+rq6k6ePAkX+bFjx+rr69FkCSahbpPnzp2rqqpycHCIiYlRVQGO40wm88SJExqfk0KyR48enTlz5ih0xGKxn5/f48uUY8eOLViwgM/nK1/hH8e5c+diY2P/PXRGgVgsFovFz3WIfxvCwsKcnZ3lcvnzHig2NvbcuXPPe5Qff/zR29v7GYkMDg4ymczHudJ/7aPdV/hX4SX6ssG44EluQ14unD17drz+eKEjlUoTEhLgEXrHjh3oid4rvML/c9y8eTMhIWFoaKinp+fQoUMvmp1xgFQq5fP54/VXBl34CBf9/hd+HOW/HvClgJeXl6mp6dN9wuPQoUPV1dUjIyPq32J4haeGtbU1/FMF+Ee+hIZhWF5eXkFBwdtvv6367Z9xxJUrV6ZNm6YxNfuEqKyshHdJGIY9zpW+wgvEf9M3B1/hqfEPKBE+mX8W4qq2+r/qJKp5AgeSJAAAAABJRU5ErkJggg==" alt="preview distance [m] = 10 * vehicle speed [km/h]" title="preview distance [m] = 10 * vehicle speed [km/h]" /></p> <dl> <dt>Parameters in <a href="#job-file">Job File</a>:</dt> <dd><ul> @@ -2837,7 +2839,7 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge <h3>Speed dependent correction (User-defined)</h3> <p>The base C<sub>d</sub>A value (see <a href="#vehicle-file">Vehicle File</a>) is corrected with a user-defined speed dependent scaling function. A <a href="#speed-dependent-cross-wind-correction-input-file-.vcdv">vcdv-File</a> is needed for this calculation.</p> <p>The C<sub>d</sub>A value given in the vehicle configuration is corrected depending on the vehicle’s speed and the C<sub>d</sub> scaling factor from the input file as follows:</p> -<p><span class="math inline">\(C_dA_{effective} = C_dA * C_d(v_{veh})\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOQAAAAUCAIAAAASpwbDAAAABmJLR0QA/wD/AP+gvaeTAAAReklEQVRoge1afzyU2fe/Y2aMQZORkV+l0kaoUFIqSlhqZf1KsapdLSX0Q0pRKtFqk9hKImy1CtX6md+bXzWx+gwjjN+TavwcxIQZZp7vH8/n+3ye1xitsd/d/X72te+/nnvOueee5z7n3nvOuQ8GgiDwD/5G4PF4kpKSf/QofD4fAIDFYv/QUYTeRWKqxMjISExMjJ+fn5+fX1lZGQBAIBBkZWXNYrDz588/e/Zs1rb+PcDj8UpLSwMCAvz8/G7cuMHlcgEARUVFHA5nFtpevHgRGBg4HTcjI2PPnj2/qWR8fDwvL+/YsWN+fn53796dmJgAAKSnp8/QBh6PFxwc3NvbO0P5WSMtLS0tLQ1p4tC80dHRs2fPdnR02NraXrhwAYvFxsfH02i0trY2JSUlGxsbsUb617/+lZOTIykpuWXLlv8b2/8LkZaW9tNPP61atWr//v3q6uqVlZVnzpwxNDT88ccfs7OzxdUmEAjCw8MnJyenspKTk+3t7fF4vIyMDACgqqpKSkpq5cqVQmJ8Pj8hISErK2vTpk1HjhxRVlYuKCg4c+aMpqZmYWHhl19+ORMzPD09vby8lJWVxbVfXLi6up44cQKDwTg6OgIAAPS/6Onpsba2DggIGB0dhVAIDg7W09MrLy+HxMHk5OT+/fv19PS+++47sTr+nRAUFGRlZdXS0oImvn792tDQ0NvbexYKExISDA0Nt2/fPpXl7Ozs4OBQVlbm7+8fEhKyZcuW/Px8IZnJyUkvLy9HR0cWi4WmFxYWGhgYnD9/fiY23Lx5MzAwcBbGzw5sNnvHjh0DAwMQBP07DOjr69u3b5+KisqlS5eIRCLau83MzCQlJTdu3CjWmkhPT1dTU8NgMG/fvp15r8nJyebm5ql0DofT2dkplgF/Oc6dO1dcXBwXF7d06VI0XUdHR05Obu3ateIqHBsbq66uVlJSGhwcFAgEQtyHDx/6+vqmp6fX19dTKJSsrCxLS0u0gEAgOHz4cENDQ1JSktCmaGxsTCQSN23a9Js2jI+PP3nyZP/+/eIaP2vIy8uvWLEiKioKIDFrUFAQm82+cOHCVGl1dfUlS5aINcDY2FheXl5wcLCsrOzQ0NDMe/n4+JSXl9+5cwdNb2xsPH/+fGJiIpVKnbkNIyMjXV1dSLO1tdXc3PxPCLNg5OfnZ2VlOTo6qqmpTeWSyWQzMzNxdYaGhrq7uy9btgw++oS4lZWViYmJAoGARCIVFRUlJSWNj4+jBe7fv//8+XNPT084TkBDWlqaRCLNJFp78uQJmUxetGiRuMb/Hjg7O5eWlv57Z62urq6urjYyMlJRUZkqisPhVq9eLZb227dvzyTMF0JcXBwEQSUlJXC8j+DatWuKiorPnz+XkBCRDk6H0NDQiIgIpEkikby8vBQVFcW1ana4fv06kUj08PAQydXQ0FBVVRVLIYPBwOPxBgYGAAAMBjPVWYODg83MzA4dOqSurv7DDz+UlZXdv38f4fJ4vMTExHnz5u3atUukfj09vZmYUVJSoqurK0TMz8/38PDIzc2Fm0lJSadPn55q4ayhpaUlEAhevnyJg7ULBAJbW1uRoqqqqsePH5+56u7u7q6uLvhMkZWVffPmzQw7NjQ0KCkpnTt3Dk2EIIjJZNrY2Pj7+8/cBljbzp07kaaioqK9vb1YGmDU1dWJPHDQMDEx8fHxQZqlpaXv379fu3atrKysSPmwsDBxzYiLizt79iwAYN68eRAE5efnb9++HS2Ql5cHALh3715LS4uSklJKSgqam5aWNjQ0JNRlFib19fUJuXVFRUVjY6Orq2twcLC1tTUAoKSkpLa29sKFCzgcbho14gGPx0tJSXV0dOAAAE1NTXg8fuvWrWKpoNPpycnJbW1t6OICACA8PBxxOAqFMjUMoNFopaWlEhISZmZm8DLt7++/du1aXV0dn8+/c+eOu7s7IpmWltbT01NRUYHD4aysrAAAEASlpqYODAyMjY15e3vDdbhHjx719/eTyWQDA4M3b9788ssvb9++ra2t/fjxo6enZ1lZWUVFhZ2d3fLly3t7e3Nzc4eHh318fNhsdmBg4K1btwAAbW1tjx8/njNnjra2tqmpKWKtlpYWHDB9AkJO+eLFC4FAsG7dOrHmEwAQEhLS1NTk4uKybds2ND0tLc3AwGDu3LkAgMWLF0MQxOPxRGpYu3atyLiruroagqDNmzeLZQ+Xyw0JCWltbfXz8zM0NAQAsFisDRs2oGUePnwYGRkZGhqKnHsRERHbtm3DYDBijfVpLF26tLa2Fjc8PNzf379gwQKRQhMTE+np6U5OTlNZWlpaysrKdDodTUxPT29tbb106RLcZLFYfD6fw+EgnzM7O7u4uPj777/HYDC+vr43btwAAMydO9fd3T07O/vixYvS0tLoIXR0dH799Vd/f3+YDkGQv7+/sbHxwYMHU1NTHz9+vHv37uDgYDKZfOTIkYsXLz5//jw8PLyrq6u6ujogIACPx7e3t3M4nO7u7ry8vOXLl2dnZ5uYmLi4uHh5eREIhI6ODgBAZWVlfHz8jRs3JCUlDx48iHZWPB4vMjr6BOrr6wEARkZGIrnp6ekWFhZTA0cAgLe3t4WFBYVCQRM5HE5cXJy+vn5dXR0AAA7EBwcHRSrX1NTU1NScSofT1umcNSUlZefOnVPdi0AguLm57dq1a+HChTAFg8EI3Th89dVXOByutLQUUS4nJ7dmzRqx7gt6e3tLSkpevnx55coVkcGehIQEBEE4GRkZOTm56bSUlZV1d3eLZElKSjKZTC0tLYQyOTmZmZl59+5dPB4PUy5fvpyRkdHa2gqfHRwOJywsLD4+vqGhISsrC0kq8Xg8g8FQUFBQVFRETxmRSGxra1u4cOG8efNgSmpqaktLy6lTp4qLi+l0elBQUHFxcWVlJXwIampq7tixg0gk0ul0TU1NuFdzc7OxsfHly5ddXV0BADo6Oo8ePdLU1MRisbKysg4ODnw+Pygo6NixY0wmMyMjY3bRAhrq6up1dXUigzY+n19QUDBdObO1tZVIJK5YsQJNjIiIOHnyJOL6nZ2du3fvbmpqEsskNTW1d+/eiWRxOBwqlers7CySy2AwKBTK/Pnz4SZcTkILrFu3rqio6MOHD0g03NbWhnyvmeP169dVVVWfEMBgMDgsFquioiIyTZ6YmMjMzLx69aoQva2traioSFVVlcFgfP311wg9JiZm7969ZDIZoZDJZPRCycnJkZGRYbFYEhISAQEB6MVHp9PJZPLUxd3a2oosawBAbm7uokWLaDSakpJSSEgIBoPJyMjQ19eHucgJwGAwkLlbs2ZNSkqKtLQ0/L2NjIzCwsLs7OwAAHw+H4/HV1dXczgcPB7/5s0bb29vocrdq1evzpw584lJBACYmpqePHkSaa5YseLp06e9vb3a2tpCkrGxsfDQaPD5/Pj4eBKJ1NjYqK6uLiUlhbA6Ozt5PB46QlNRUREr0YShqalZVVX1/v17dXV1IVZ0dDT6I8Lg8XixsbEKCgqVlZXorVpOTq6qqkroverq6ohEIiKWlJQ0XWY5HRQVFWVkZDQ0NKZ7NSaTaWlpKQEA+OabbwYGBgoKCoQkoqKidu3aJbSft7e3X79+3d3dXUFBob+/H44jAQC1tbUMBgN9gCJASkgYDGbZsmXm5uZmZmZYLBa9PXR1dWloaEztOzAwILTT2NjYmJub6+rqYjCY5uZmDAYDh1MwmpqauFwui8WysLCora2Fj86ff/7ZysoqNTUVAMDlcjs7O2GPefr0qbm5uUAgWLx4sbm5uYWFBZFIhGv4iMLVq1c//S2gPRW2UFlZ+cGDB0LvUl5ezuVyLSws0EQ+n3/ixImNGzfu3r2bRqOh0xeYderUKbQ8vJ6Hh4enztUn4ObmRiKRYmNjhegZGRnz589ftWoVmsjj8Y4dO2Zvb+/g4FBTU7N+/XqERaFQPnz4MFW/goIC/MBkMrFYLFLbmpiYSElJgR1gdHS0sLAQpk9OTubm5j548ACp/NDpdB0dnczMzKkXexAEjY+PL168WAIAsHXr1j179kREROTm5sI315WVlUFBQevXr0cbCuPw4cP29vY4HO7du3eKiookEonNZoeFhR09erSjowOxBgCQkJAAb+yPHj1KSEgAAJiamrLZbJhbUVExMDCACLe1tYnMSLq7u9H1vw0bNtBoNADA2NjYkydP5s6du3Tp0sbGRniKMzIyiERiQ0ODvLw8hUKh0WhwAtfb22tnZwfXHSUkJOCtq6+vb2RkZMGCBXp6elwuF541Go3GZDJ/Z3IgIyNz9erV9vb20NBQ+Mjq6emJjIyk0WhHjx4VEo6Ojh4fH9fR0QEADA0NIav93r17bm5u7e3tMTExiHB5eTlcj2tubo6MjEQXkj8NCoUSFhZGpVJjYmLgaX///n1YWNjg4CCSziIIDg6mUCiqqqpcLpfD4cA5PgxjY2N4/tGwsLAYHBzMzMykUqm3b9/29vZGWCkpKUpKSp6engCAmpoa2Pi+vr7jx49TKBRDQ8OLFy8CACYnJ5lMpkAg2Lx5c0lJSWJiIlp/T08PbMZ/KnZNTU2JiYkcDkdaWlpfX9/JyWlq6eHFixenT58uKirC4XDHjx+HICgiIoLL5TIYDFhAQUEBqSAyGAzY9QEABAIBjm6fPXvW0tJCJpO1tbXhLwQA4HK5JiYmhYWFJBIJPVxJSUl4eDhSwIMl7969SyKRIAiysrKSk5Pj8/nXrl1TU1Pj8/mWlpbwEo+KiqJQKNbW1nBMcuvWLXl5eVtbWwKBAADIyMhgsVjKyspIolNTU1NeXj5//nwNDQ1xi8rT4ePHj8nJyZWVlbKysioqKvv27RNZ5bW2tvbw8LCzs6PRaL6+vsXFxXAG09LSMjo6CgDAYrFIabOnpwedQixbtkwoaPk0hoaGEhMTGxsbpaWlP/vsMxcXF3TMhmDjxo1RUVGrV6/OzMy8efMmnA/AYLFYrq6uWVlZQgWQ/v7+e/fuSUpKurq6IilQb28vjUaj0WjNzc0JCQkQBIWEhAQGBjo5Ofn7+69fvz4vL4/JZB44cIBKpQYEBBQWFkpKSsJ/HaBDr+jo6Pr6+tjY2P/8GzATJCQk7Nu3D37etm3bgwcPCgoKfsfFL8ThcDw8PLKzs52cnND0lpaWAwcOREZG/pnX0H8+RkZGjI2N4Rupq1evurm50Wi03t7ev9Ckzs5OU1NTHo8HQdDJkyd9fX2FPrGfn9/t27dnrtDGxiY5ORmCIB6Pl5SUlJ+fv2HDhocPH8bExGRlZcEy4eHhe/bsgZ+3b98Oy8MQCAQ7duxoaGiAkH8DZghtbW14u6XRaH19fZaWliwWSywNQnj79m1PT09VVdW3336LpldUVGCx2ObmZi8vr9+j//85ZGVl5eTkiETi2NgYlUpduXJlTU2NvLz8X2jSggULpKWl8Xj8wMAAnU43NDQU+isjNDQ0JydnhhFIR0cHm83+/PPPAQBUKlVfX7+np0dDQ8PZ2fnAgQNffPEFLEan0+Esub6+ns1mOzg41NbWwqzo6GgjI6Ply5cDALBCN0afhpqaGpVKZbFYUlJSGAwG9tc5c+bMXIMQFBQUlixZYmBgIBSw6urqSklJOTo6ilvj/K8DHo/Py8tjsVhbt25lMBi6urpCP778+RgfHy8rKxsaGlqzZk1TU5ORkRG6DA9fv8fHx5uYmPxmXYLJZObk5MC/mBUXF1tbW7PZ7NevX8PXpcPDw5mZmTo6OleuXDl06JCSktLNmzcJBMKSJUtGRkbU1dVfvXrV2Nh46tQpOIsQccv8D/7Bb4LJZBKJRKT+Oh0EAsHevXttbW0/fPhgY2OjqKgIQVBQUJCuri6BQODz+Q4ODq2trT4+PpmZmQQCIS0traKiwsjIyMXFBQBQVVVlaGiI5Lv/OOs/+GMhEAhGR0elpKSQfB2CoI8fPxIIBOTyiMvlwrkvAAAWFrln/w+LmUUB8NjQzwAAAABJRU5ErkJggg==" alt="C_dA_{effective} = C_dA * C_d(v_{veh})" title="C_dA_{effective} = C_dA * C_d(v_{veh})" /></p> <div class="figure"> <img src="data:image/png;base64,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" /> @@ -2847,7 +2849,7 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge <h3>Correction using Vair & Beta Input</h3> <p>The actual (measured) air speed and direction can be used to correct cross-wid influence if available. A <a href="#vair-beta-cross-wind-correction-input-file-.vcdb">vcdb-File</a> is needed for this calculation. This file defines a ΔC<sub>d</sub>A value in [m²] depending on the wind angle. The <a href="#driving-cycles">driving cycle</a> must include the air speed relative to the vehicle v<sub>air</sub> (<vair_res>) and the wind yaw angle (<vair_beta>).</p> <p>The C<sub>d</sub>A value given in the vehicle configuration is corrected depending on the wind speed and wind angle (given in the driving cycle) using the input file as follows:</p> -<p><span class="math inline">\(C_dA_{effective} = C_dA + {\Delta}C_d(\beta)\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="C_dA_{effective} = C_dA + {\Delta}C_d(\beta)" title="C_dA_{effective} = C_dA + {\Delta}C_d(\beta)" /></p> <div class="figure"> <img src="data:image/png;base64,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" /> @@ -2857,7 +2859,7 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge <div id="rolling-resistance-coefficient" class="section level2"> <h2>Rolling Resistance Coefficient</h2> <p>The rolling resistance is calculated using a speed-independent rolling resistance coefficient (RRC). In order to consider that the RRC depends on the vehicle weight it is modelled as a function of the total vehicle mass. The total RRC is calculated in VECTO using the following equation (the index i refers to the vehicle’s axle (truck and trailer)):</p> -<p><span class="math inline">\(RRC = \sum_{i=1}^{n} s_{(i)} \cdot RRC_{ISO(i)} \cdot \left( \frac{s_{(i)} \cdot m \cdot g }{w_{(i)} \cdot F_{zISO(i)} } \right)^{\beta-1}\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="RRC = \sum_{i=1}^{n} s_{(i)} \cdot RRC_{ISO(i)} \cdot \left( \frac{s_{(i)} \cdot m \cdot g }{w_{(i)} \cdot F_{zISO(i)} } \right)^{\beta-1}" title="RRC = \sum_{i=1}^{n} s_{(i)} \cdot RRC_{ISO(i)} \cdot \left( \frac{s_{(i)} \cdot m \cdot g }{w_{(i)} \cdot F_{zISO(i)} } \right)^{\beta-1}" /></p> <p>with:</p> <table> <colgroup> @@ -2942,7 +2944,7 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge <div id="engine-transient-full-load" class="section level2"> <h2>Engine: Transient Full Load</h2> <p>The engine implements a PT1 behaviour to model transient torque build up:</p> -<p><span class="math inline">\(P_{fld\ dyn_{i}} = \frac{1}{T(n_{i})+1} \cdot \left(P_{fld\ stat}(n_{i})+T(n_{i}) \cdot P_{act_{i-1}}\right)\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="P_{fld\ dyn_{i}} = \frac{1}{T(n_{i})+1} \cdot \left(P_{fld\ stat}(n_{i})+T(n_{i}) \cdot P_{act_{i-1}}\right)" title="P_{fld\ dyn_{i}} = \frac{1}{T(n_{i})+1} \cdot \left(P_{fld\ stat}(n_{i})+T(n_{i}) \cdot P_{act_{i-1}}\right)" /></p> <p>with:</p> <ul> <li>n<sub>i</sub> … current engine speed</li> @@ -2951,10 +2953,10 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge <li>P<sub>act i-1</sub> … Engine power in previous time step</li> </ul> <p>Vecto 3.x uses basically the same PT1 behavior to model transient torque build up. However, due to the dynamic time steps the formula is implemented as follows:</p> -<p><span class="math inline">\(P_{fld\ dyn_{i}} = P_{fld\ stat}(n_i) \cdot \left(1 - e^{-\frac{t_i^*}{\mathit{PT1}}}\right)\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQ0AAAAjCAIAAAABocitAAAABmJLR0QA/wD/AP+gvaeTAAAS3ElEQVR4nO2deVRTR9vABwOJhCMHWYRKDYIICmJA0UIpECt6AA+IqFVaauEUPVVxaQE3rJ5XERdwAaHqsSoYJBY9VoWwqcUFBAkgIkYRMATLjiyhN+TGe8n3x7zf9TaBkKCi7ZvfX+HJM3Nn5s4zyzPPBC2ZTAY0aFATsVhMp9M/dCnePUPVa8zoF0XDP53Y2Njk5OQPXQq1EQqFw+okJyfHxsYqyjV2okE9YmJiEASJior60AVRAxRFcRzPy8sDAIjFYiWaUVFRCILExMTIybU06y4NqpOZmZmSksLhcKhU6ocuixoUFBTcvHlTW1ubSqWampqGhYUpUZZKpUFBQSEhIX5+foRQM59oUJXGxsYjR45ERUX9g4yktLQUAODh4TFt2jQej9ff3//1118rT0KlUqOioo4cOdLY2EgINXaiQVXi4+MdHBxcXFw+dEFU5cGDB8eOHQMAFBQUmJiYBAQEhISEpKWlDZvQxcXFwcEhPj6ekGi/x2Jq+BchEAjKyspU6WQfCX19fTdv3pw2bRqKol5eXgCAK1euWFtbW1tbq5J88+bNwcHBAoHA0tISaOaTfwdJSUmqOHMGJScnJycnZ1i1U6dOMRgMKyurkT1llMFx/Pbt20VFRWZmZvX19VDY1tZ26tQpFXOwsrJiMBiE/pv5RCKRREZGdnZ29vT0fPLJJ3p6egAAsViMoqivr+8333zzTivy0cHhcAoLC+vr62k02qRJk6CwubnZ1tZ23bp1hOQjJDY2lsFgWFhYjCy5j4/P9u3bBwYGFi1aNJQOiqL37t0LDg4eaRlHGwqFsnDhwuPHj3/33Xc0Gg0KXV1djYyMVM/E09MzLS0NRVEajQZkf2fDhg1MJrOkpAT+iWHY1atXHR0dExMTZf92urq6mEzmihUrCIlIJFqyZMm8efMQBPmABVNCVlZWSEjIW2aCIEhAQIBQKBxKgcvlOjs79/b2vuWDRpOSkhLyq6yqqnr48KFaOfT29jo7O3O5XJlMJr/uev78OZ1Od3R0JOxy8eLFJiYm2dnZ78TQP2a4XC4AgMlkEpJx48YFBgZ2dXVdu3btw5VrSHAcT0pK+uGHH94yHzqd7uLiQt62ylFYWGhoaKivr/+WDxpNCgoKmExmaWnpixcvBAJBfX39rl27EARRPQd9fX1DQ8PCwkIgtz/p7u5ubW1lMBjEVAUAQBCkq6trYGBAMaPy8vLU1FS4MsZxvL6+/saNG3I6fX19eXl5zc3NislxHO/p6cnIyMBxXPXSvz94PB4A4MsvvyQL+Xz+oMpSqfTSpUvEyl4sFitWE0XRQdvkXZGdna2jo/PZZ5+9fVZr164tKysTiUSDfvvkyRNbW9u3f8po8tdff02YMOHJkydWVlZ8Ph+Wf+zYsWplYmtr++TJEyBnJ4oDKgDg999/xzBs3rx5clkIBII9e/Y0NzcfOnQIAFBQULBp06bjx4+TdVAU3bVr19atWysrKxUL8fjx440bN8bFxUkkErVK/56oqakhz6UAABzHKyoq6HT64sWL5ZSjoqKampqOHTtWV1eHYVhsbKxiNbOyshTbZFBOnjxZUVGhXKexsXH//v1kyfXr1x0cHOTUKioq8vLy4NDT0NCQkZEB7V85+vr6xsbG6enpil/hON7b2/uPs5Ndu3YZGRnBffWiRYuuXbvm6upKoVDUysTW1ra3txfH8b/5hRUH1Lq6ujNnztjZ2f30009yWZw+fdrCwsLAwGD27NkAAC8vr4sXL5qampJ1aDTa+vXrCwsLPT09FQvh6Ojo4uLS09MDfQZvT2Vl5fPnz5Xr2NjYkC2BAM6l06ZNI+ZSHMf379/f1dW1e/duudg4BEGKioq+//779vZ2S0tLCoUSEhKSl5cnV82lS5fm5OTItYkiOI5fvHiRwWAoV8vKyiouLiZLhEIhi8UiSwQCwS+//NLf35+dnT116tTW1taZM2cePHjQxsZm0LAlMpaWlk+fPlWUIwjS09NjYGCgPPnHBpVKDQgIgJ9xHC8uLj5w4ACXy1XirlDEwMCgp6cHQZC/2UlNTY2WltbFixcvXboEAGhvb3/9+vXq1atXrFihaIgvXrxgMplr164lilJXVxcYGEgowKCa/Px8wntGRiwWUyiUiooKYkQUi8U0Gk3uQYQQhuUoj1F99uzZ/fv3ldd8YGBgUDuBc2lfX19kZCRUa2homDRpUkZGxuTJk+WUq6urqVSqra0t0fkUq9nX10elUuXaBILjOIxLhZUVCAQIgsjZGGwf8gKY3Fbg/9fDcqcBp0+f3rp1a1JSUlFR0Zw5c8LDwwEAUqn0xIkT//XbDI2ZmVlJSQm5ALDl29vbAQAqHjt8nEgkkoGBgZqampkzZ6qVENa6vb39jZ0QA+qePXsI4bhx4xQTC4XCQ4cO1dXVjR07NiYmZufOnUDhZefk5Dx69MjS0jI3N1dxbZCUlDR27Fgcx2tra2E3un//fn19fU5ODpvNBgCsWbMmOjq6s7OTz+ffvXs3ICAAw7CbN2/6+fn5+PgMVauVK1euXLlSrYYggHPpli1bZs2aBSVUKnXQjpWcnJyfn0+lUiMiIkJDQ+F0Su7EUqk0Li7O3Ny8o6ND0QBgy9jb23d2ds6fP//8+fM8Hk9PT2/r1q1ubm5BQUHk9ikpKfn555+7u7vPnj1bWVk5Y8aM8PDw+Ph4+C2GYdOnTydnTqPRrKysGhoarK2tCTcun8/X09OTqwuKotra2uRRicFgFBQUEK0RHh4+Y8aMM2fOPHjwAAAg96B/Fnp6env37qVQKOqe/8BaP3jw4M3+hNicjCMxaGILC4uYmBgcxxMTE6GRgL8PqDk5OZcvX962bduyZctEIpGbmxs5eWxsLIIgYWFhLBZLLBZ7enriOM7n821sbBoaGjAMEwgEVVVVpqamjx49cnNzq66utre3DwwMNDc3z83NJfI5ceKE6sdGwwI3Jy4uLkTdhxp9169fb2Fh4eTklJSUBI0EzqWwmjiOh4aGzps3LyQkRFdXV26SwXE8ISEhLCzMz88vOzu7urp6586dJiYmbm5uSUlJ0EjI7VNdXW1qajp79uwff/xRS0srOTkZmtBQtdi9e7dEImlqanJ3dyeE1dXViqcrQUFBhw8fVt4msn9RjKyjo6PieK06b+aTQb09Q5Gbm2tiYkJ2FBIDKuwKcMZXXFEIBIKsrCzY3W/dugW7EY7jvr6+iYmJ9vb2NBqNMLmFCxdyuVwzM7MpU6bAtOS1vuKx0Yj3J4qbE+XU1taSD17J1eRwOH19fZ9//jksj9y7wTBMJBIFBwfPmjVr3759NjY2cuvVQdsHDLauAwBoaWm1t7fLuWvv3LmDYdjChQvhn3V1dY2NjWvWrMFxnDx7rF27Vm6i6+3t1dLSgp/nzJlTUFCgYmu8b1avXt3S0qIoZ7FYcJE8CryxE0VvjxIeP35saGhI/Alf9pIlS3AcF4lEr169gv4x+HbJ49+9e/eMjY3hq4WmhWGYtra2qalpaWkp9BYQJmdhYUF8RlGUz+evXr0a6j9+/BgAIHdMPuL9yaCOvqFAEKSjo2Pq1KmEBFYT9qrS0lJivIAGAAsMNbW1tRMSElJTU+/cudPQ0JCenk7YGOzHQ7UP0Q5Ebvr6+iYmJg8ePJDbORQWFhoYGBALjMuXL9Pp9AULFuzevXvLli2EUS1YsECuXjU1NWSn1sdzXTEhIWHQkwMYtszhcIqKit7+KcQSelD++/7UHVDb29vhGA+BL/vTTz+9ceOGkZHR+PHj4cgH3256enpgYCCUtLS0wMAyohulpKSEhYXBXamHhwd5fCV/zs/Pp9FoTk5ObDabxWLV19efPXuWw+GQh9gR70/UmktbWlq0tLRmzJhBSGA1YUU6OzvhgQZsky+++ILNZoeGhsLqLF26dPny5UlJSWlpaRkZGYA0UaSmpq5cuXLQ9gkNDYWfxWLxlStXiI2HoaHhy5cv5Yr35MmTKVOmEFNHZWXl9OnT4VEVNBKhUHjr1q329vZt27aRE7a1tak4Uowyyi02KCgIrlffK2MkEkl4eHhERISZmRkAIDw8vLy8fNhkQqGQvOt49eqVoaHho0eP3N3dZ86cqaurK5VK79+/39HRMX369P7+fqI3s1gsGAOSmZkplUqZTKaOjg4AgEKhUKlUHMdzcnKINQx5PcPj8RwcHHJzcz09PUd8bKQIh8MJDw8XCoVmZmapqamKF9kUuX//vtwSCEEQYiRmMpnd3d1SqTQzM9PQ0JDP59vZ2cGvMAwzNTWFY4FQKISuwr6+PktLS6FQqK+vT6PRBm0fDMOkUqmbm9vly5fJ3jNPT0+5ExuJREJM5hB/f/+enp7o6OiIiAgoyc/Pt7Oz++OPP8gJURR9+fLlsmXLFOs7d+5cAMCgLmOCCxcuDHv+808E1nru3Lkjuc8oEom8vLwKCgrIfYXNZhsZGfn6+gIAeDxeWVnZrFmzJkyYkJWV5e/vT95HcjgcqVTKYrGePn3a2dn51VdfUalUFEUrKysrKirq6upqa2uvX78OAGhsbORyubA/SaXSX3/9dfbs2XC0PnDggEwm2759+1s3hdps3rxZT09v3759hEQgEGRmZgYEBDAYDKlUmpKSAgNeMjIyjI2NyQ66pqamu3fv9vT0zJ07F87ysF6WlpaE2qDtk5ub29bWxmKxyC0pFot9fX3PnTsHpyBCKDcAk13MKIpWV1enpqYCABITEwmdtLQ0LpfL4XAU6ysSiTw8PKKiohRjYZubmzkcTkNDw7179wZVGE3u3bvX1tamo6MzZswYAICdnR1c8rx8+ZLH4+no6Lx+/RoAAD9MnToVrmPr6uqUuLwvXLgQFxd39+5d+ThI5QiFQn9//4yMjJUrV6qVUDkYhvn4+Bw8eBDDMG9v76ysrGH1/f39+Xz+sJrvlv379+/fv3/x4sVEnOgHJzExcfv27WolkUgkrq6u5CpgGLZixYri4uJB9TEM8/T0TE5OVvyqqamptLS0vb2dyWSmpaWpVYx3DoIgXl5eKSkpIpGou7s7IiICBu/u3bu3uLhYJBKtW7duw4YNIpHo6tWrbDa7oqLi3Llz3t7eSvJMTk729PTEMEy9+yctLS10Or28vHzTpk1vZfsKWFtbf/vtt/Hx8e7u7sOemBLHRqPs1K+trTUyMjI3N38nIVXvhHXr1rW2tsqd0yvn0qVL+vr6NjY2RODZyZMnlVxUpFAo+vr6z549U/xq4sSJc+bM+UjcYiiKdnZ2+vv7jxs3zsDAYObMmTk5OSKRyMDAALr76+vr4QcPDw8KheLk5BQYGKg8tvDZs2f6+voUCkW9+UQmkz18+LCxsXHkVj8ECIJcu3ZNIBCoXoyqqqp3XgzlIAhSUFCAYdgoP1c5KIru2LHjzz//VFF/48aNsbGx58+fh3HyN27cSEhIUJ5kx44dSsbd3t7edzifSCSS3Nzc3377Td27DGw2e+HChfAziqJLly5NTExsbW1FUVQmk3V1dTk6OnZ1dclkMkLY29u7YMECJXl6e3vv2LFDJpOpfe9XRcexutDpdH9//w9eDOXQ6XS5eKqPASqVSg6hGBZvb++ysrIpU6ZA95e7uzu8FqsENze3vLw8kUj0vkPrjx8/fvv2bTjqBwcHHz58mLz1Ug6PxzM0NIShnEKhMDIykjxDcrncCRMmjB8/HgAwbMQdRCQSdXR0QH+V5n78vwG1wmB9fHzIrgVVVk3z58+PiYlJT09/+7suSoiNjc3Ozmaz2dA2+Hx+SUmJ6nZSU1OzatWqoX5OhcfjqbtKT09Pp1Kp8+fPBxo70aAK0GF9+/Zttexk2PAIcmwEj8e7cuWKn5+fsbFxX1/f9evXm5qaFK8zDEV3d3dbW5uS2D9oRaoXHgBw+/ZtFosFxxGNnWhQibCwMPLvj6jCsOER5NgIeM2pu7v7P//5DwDAxsaGzWarHhPA5XJNTEzgskoReIyuaEU4jsuGOBcRCASNjY1EPLjGTjSohJWVlbOz89GjR8mnLspRKzwCQRADA4PDhw+re5UKAPDw4cOmpqbZs2fn5uZ6e3uTv8IwLCMjo7e318PDg8vl2tvbOzk5EalKSkrs7e3T0tLmzZtnbm5OTnj06FFnZ2ci/EdjJxpUJTIyctWqVcXFxa6uru888zFjxlCpVLKRlJaWmpuby3XfQXFyciJ6vxza2tpD7ViUpCouLq6qqjp//vyb4g1bCA0aIAwGIyIiIj4+XiqVkuUoigIA4Gn3iFm+fDmCIMSPZHO53GvXrpmYmLxNniNDKpXGx8dHRESQb5hqfodbg3rExMT09/fDsJ3y8vJz5851dXV1dXXp6uqam5sTV81GQGxsbHV19cSJE/v7+ydPnrxp06YP8kPG0dHRurq6xMUqiMZONKjNvn374I9Vv/OcURSVSqXEjejRJy4uTiqVRkdHy8k1dqJhJPyv/T+t/wOHto3T5kbjrQAAAABJRU5ErkJggg==" alt="P_{fld\ dyn_{i}} = P_{fld\ stat}(n_i) \cdot \left(1 - e^{-\frac{t_i^*}{\mathit{PT1}}}\right)" title="P_{fld\ dyn_{i}} = P_{fld\ stat}(n_i) \cdot \left(1 - e^{-\frac{t_i^*}{\mathit{PT1}}}\right)" /></p> <p>where t* is computed from the dynamic full-load power in the previous simulation interval:</p> -<p><span class="math inline">\(t_i^* = t_{i-1}^* + dt\)</span></p> -<p><span class="math inline">\(t_{i-1}^* = \mathit{PT1} \cdot ln\left(\frac{1}{1 - \frac{P_{eng_{i - 1}}}{P_{fld\ stat}(n_i)}}\right)\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="t_i^* = t_{i-1}^* + dt" title="t_i^* = t_{i-1}^* + dt" /></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="t_{i-1}^* = \mathit{PT1} \cdot ln\left(\frac{1}{1 - \frac{P_{eng_{i - 1}}}{P_{fld\ stat}(n_i)}}\right)" title="t_{i-1}^* = \mathit{PT1} \cdot ln\left(\frac{1}{1 - \frac{P_{eng_{i - 1}}}{P_{fld\ stat}(n_i)}}\right)" /></p> </div> <div id="engine-whtc-correction" class="section level2"> <h2>Engine: WHTC Correction</h2> @@ -2964,7 +2966,7 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge <p>Based on the target engine operation points of the particular engine in WHTC the fuel consumption is interpolated from the steady state fuel map (“backward calculationâ€) in each of the three parts of the WHTC separately. The measured specific fuel consumption per WHTC part in [g/kWh] is then divided by the interpolated specific fuel consumption to obtain the “WHTC correction factors†CF<sub>urb</sub> (Urban), CF<sub>rur</sub> (Rural), CF<sub>mot</sub> (Motorway). For the interpolation the same method as for interpolation in VECTO is applied (Delauney triangulation).</p> <p>All calculations regarding the brake specific fuel consumption from the interpolation as well as from the measurement and the three correction factors CF<sub>urb</sub>, CF<sub>rur</sub>, CF<sub>mot</sub> are fully implemented in the VECTO-Engine evaluation tool.</p> <p>The total correction factor CF<sub>total</sub> depends on the mission profile and is produced in VECTO by mission profile specific weighting factors listed in the table below.</p> -<p><span class="math inline">\(CF_{total} = CF_{urb} \cdot WF_{urb} + CF_{rur} \cdot WF_{rur} + CF_{mot} \cdot WF_{mot}\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="CF_{total} = CF_{urb} \cdot WF_{urb} + CF_{rur} \cdot WF_{rur} + CF_{mot} \cdot WF_{mot}" title="CF_{total} = CF_{urb} \cdot WF_{urb} + CF_{rur} \cdot WF_{rur} + CF_{mot} \cdot WF_{mot}" /></p> <p>with the correction factor CF<sub>urb</sub>, CF<sub>rur</sub>, CF<sub>mot</sub> coming from the <a href="#engine-file">Engine</a>, and weighting factors WF<sub>urb</sub>, WF<sub>rur</sub>, WF<sub>mot</sub> predefined in the declaration data:</p> <table> <thead> @@ -3026,18 +3028,18 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge </tr> </tbody> </table> -<p>In order to balance the trade-off between emissions and fuel consumption during cold and hot starting conditions an additional balancing factor <span class="math inline">\(CF_{C/H}\)</span> is determined from the overall specific fuel consumption over the cold start and hot start WHTC test. This value is part of the output from the engine component tool.</p> -<p>The WHTC-corrected fuel consumption is then calculated with: <span class="math inline">\(FC_{whtc} = FC \cdot CF_{total} \cdot CF_{C/H}\)</span></p> +<p>In order to balance the trade-off between emissions and fuel consumption during cold and hot starting conditions an additional balancing factor <img style="vertical-align:middle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAATCAIAAABDZPnGAAAABmJLR0QA/wD/AP+gvaeTAAAE70lEQVRIicWWb0gTfxzHv7s23bQ2RzujVoqmEyEt7Uwp0Rmz7IER9UDQqTBFIaT2SDKfCBLYEGFD8kEUi3qiD1KkB9sCNXQQzLYhlhv+vTnLpqa7a56t7a4H1+86vhu/In7+fD/7vO79vXt/v/f5fu8EDMOAGEUikb29PQRBkpKSOCIUCmOdByI4x8LCwsDAQCAQOHnyZDQaRRCko6PDZrORJKnT6TibwWDw+/3hcDghIYGbTCQSCYfDBQUFra2t+5ua4clkMl29enV0dJQjOzs79fX1GIZ5PB6+k6bp/v7+goICs9kc/Udra2u3b9/W6XTMPuvXShsMhtevX5vNZqVSyUGZTJaWlra6upqdnc2fqkAgwHEcQZCysjIEQVh44sSJuro6i8Wyv8sMwM/nvXjxYmho6M6dO/zErAoLCzMyMrhknObm5uRyeUZGBh/SNK1QKP4ih9vt9nq9f2gWAgBIkhwYGEhLS6uuro5rKiwshMjW1tb6+vqFCxfYcnx8XCQSlZaW5uTkyOVyvpOm6WfPnrndbnZbt7e3v3nzRqPRcFucVWdn58OHD7lyZGTE6XTSNI0giEajCQaDDoeDLdVqNWAYpru7Oz8//+nTp3EbyO/3+3w+CL58+ZIb8v3799raWofDETvW4/HcunXr/v376+vrDMN8/vz53r17169fh2xer/fatWs0TXMkGAx2d3dfvHhxY2ODoiiCIHp6ekpKSj5+/Li7uysEALx9+1YoFN68eTPuMsc2DADAbrcjCOJwOGZmZra3t3EcP3v2LOTx+/0tLS2tra21tbUsSU1NVavVkUgEcg4NDZWUlAgEAo5IpVKPx5Odnc02m1gs/vDhQ2Zm5vHjxwEAQoqivnz5olQqZTJZ3NAbGxsoikLQ6/WiKPro0SMAAEmSbW1tIpGIb6BpWq/XYxjGJWalUCgqKiqgu01NTfX390NweXm5pqaGK3Ec57pXyL4O6JGcbDabz+drbm7mQ4IgPn36VFxczE2gqqoKGvju3buVlRWj0Qjx8+fPQ2RyclIqlWZlZfGhy+WiKMrn8xkMBgDA7u4uSZLl5eU/QyclJaEoyn81fFmt1q6uLgiOjY1Fo9GioiK2xDAMwzDI8+rVq6NHj8ZtLUijo6NcGk4TExNSqbSpqenQoUMAgMHBweTk5DNnzrBXEQBAaWkpjuPb29vQSLPZfOnSpSNHjkDcbrfTNF1ZWfkvUXZ2diQSCQQZhnG5XHwSCoWmp6fr6uogp9PpPHXqVG5urkqlUqlUS0tLSqVSLBb/Cn337t309HS9Xv/t2zeWhsPh3t5ekUgE7c6vX79ubW25XK7Dhw+LxeLYeXJSq9UURUHQYrFAS2CxWDIzM1NSUiDn4uIi/5xdWFg4d+4cVwoBAImJic+fPzeZTA0NDSiKymSyhIQErVZ7+vRp6F7Dw8Pz8/NsNxuNRolE0tHRETd0dXX1kydPDAZDe3s7AIBhGKvVKhaLod612Wyxb8xut+/t7V25coUtp6enQ6HQ5cuXOYOAifeX959oc3PzwYMH7OGTlZWVl5dXVlbGNwQCAa1WOzIywv/Q9PX1eTwegiCOHTvW1NQ0MTHx/v37YDCYmpra2NjI7uN9DP1bPX78eHZ2NvaE+a3gP4r/U+Pj4zdu3PiLgQcWmiCIQCAQ+6H5Ex1ke1AUFXss/ol+AAla9B2Fj8I5AAAAAElFTkSuQmCC" alt="CF_{C/H}" title="CF_{C/H}" /> is determined from the overall specific fuel consumption over the cold start and hot start WHTC test. This value is part of the output from the engine component tool.</p> +<p>The WHTC-corrected fuel consumption is then calculated with: <img style="vertical-align:middle" src="data:image/png;base64,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" alt="FC_{whtc} = FC \cdot CF_{total} \cdot CF_{C/H}" title="FC_{whtc} = FC \cdot CF_{total} \cdot CF_{C/H}" /></p> </div> <div class="engineering"> <p>In engineering mode a single correction is applied by Vecto. The fuel consumption interpolated from the FC map is multiplied by the engineering correction factor.</p> -<p><span class="math inline">\(FC_{whtc} = FC \cdot CF_{Engineering}\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="FC_{whtc} = FC \cdot CF_{Engineering}" title="FC_{whtc} = FC \cdot CF_{Engineering}" /></p> </div> </div> <div id="transmission-losses" class="section level2"> <h2>Transmission Losses</h2> <p>Every transmission component uses the following formula for calculating the torques at input and output side of the component:</p> -<p><span class="math inline">\(T_{output} = (T_{input} - T_{loss}) * r_{gear}\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="T_{output} = (T_{input} - T_{loss}) * r_{gear}" title="T_{output} = (T_{input} - T_{loss}) * r_{gear}" /></p> <p>with:</p> <ul> <li>T<sub>output</sub> … Output torque</li> @@ -3080,15 +3082,15 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge </div> <div id="power-shift-loss-computation" class="section level4"> <h4>Power-shift loss computation</h4> -<p>Model parameters: shift time (<span class="math inline">\(t_s\)</span>), inertia factor (<span class="math inline">\(f_I\)</span>)</p> +<p>Model parameters: shift time (<img style="vertical-align:middle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAARCAIAAACNaGH2AAAABmJLR0QA/wD/AP+gvaeTAAABcElEQVQokY2SvYrCQBRGb8wWMjamEVGwMJUgJIUglhb2YmOXzk6w8CFS2PoGQoqUAUHJC4iWgiBYaSNREpLoiMPItciuCrtmPdXAfFzO/REQEX6glBJC4D2JxysIgnq9PplMPkpblsUYq1arH6UXi0Umk5EkKSb9BQDT6dT3/eVymc1mTdOUJKnRaPxd+3a7hWFIKXVdt1gsxhQGAEBERByNRqqquq6LsSQ+l352uV6vS6XSPxpRl57n7fd7TdMAgDF2PB5zuVz0vdvt5vP55XIpl8uqqgIiGoahKEokrev6bDaLLDnn7Xbb933OuaZpp9Pp2ySVShFCxuMxIj4WZNv2drtdrVbn8zmfzyeTSQERGWP9fp9zrihKp9MRRTFKU0pbrZbjOISQwWBQq9Xg3bA458PhkFK62WyazWav13tO8De2bZum6TiOLMuFQqFSqQCA8HqxrzDGDMNIp9OHw+F6vXa73bh0RBiGoig+jv4O+dj8oUqg308AAAAASUVORK5CYII=" alt="t_s" title="t_s" />), inertia factor (<img style="vertical-align:middle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAVCAIAAADEqSm4AAAABmJLR0QA/wD/AP+gvaeTAAABsElEQVQ4jY2UP6/5UBzGz22vVoQQk8HCKKIiBjaJ1WSXWMRs8Aa8AonZSxADXUxNziZShBYJ1XDSpLFxBmlKf0N/cake9z7T9/z55DnP95ycL8uywJsMw7jf716v933J1vf71GAw4Hle1/VyuVypVFwxyjHWNK3VatXrdYQQxpjkBqxXdTqdYrFomuZisbDIcrpNp9NIJELTdDKZJFo9H3Kz2UAIT6cTTdMQwsPh8CfseDxKkoQQCgaDsizruv4Be8kGIeQ4brfbfUjlkm0ymQQCgWg0+snHcUgAgKZpoVCIYZhfsZfrVlWVZHU+nxVFsetwOPyCIYQKhYIrtlqteJ4fDoelUimXy/20ZD6fp9NpURRJbWi32/l83tmS8Xjs9/s5jiPlEUUxHo/bNQUAEARBVVVJkhKJBEU5340twzD2+30mk/mPXS6XZrPZ7/cVRanVaiSr9XqNMX4kp1iWTaVSy+WyWq1ms1kSJgiCz+d7uH0zDNPtdkm7H5rNZrFY7DF0T+LQ7XbbbrfP3fod6/V6jUYDYyzL8mg0sie/XP+SZ12vV9M07ZplWY/HAwD4B5KUMZuvEKdaAAAAAElFTkSuQmCC" alt="f_I" title="f_I" />)</p> <div class="figure"> <img src="data:image/png;base64,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" alt="Engine speed, clutch speed during power-shift" /> <p class="caption">Engine speed, clutch speed during power-shift</p> </div> -<p><span class="math inline">\(T_{PS,loss} = |(T_{GBX,in} + T_{inertia}) * \Delta\omega_F| * t_s / dt\)</span></p> -<p><span class="math inline">\(T_{inertia} = f_I * I_{engine} * \Delta\omega_I / dt\)</span></p> -<p><span class="math inline">\(\Delta\omega_I = \omega_{engine,1} - \omega_{engine,2}\)</span></p> -<p><span class="math inline">\(\Delta\omega_F = (\omega_{engine,1} - \omega_{engine,1^*}) / 2\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="T_{PS,loss} = |(T_{GBX,in} + T_{inertia}) * \Delta\omega_F| * t_s / dt" title="T_{PS,loss} = |(T_{GBX,in} + T_{inertia}) * \Delta\omega_F| * t_s / dt" /></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="T_{inertia} = f_I * I_{engine} * \Delta\omega_I / dt" title="T_{inertia} = f_I * I_{engine} * \Delta\omega_I / dt" /></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="\Delta\omega_I = \omega_{engine,1} - \omega_{engine,2}" title="\Delta\omega_I = \omega_{engine,1} - \omega_{engine,2}" /></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="\Delta\omega_F = (\omega_{engine,1} - \omega_{engine,1^*}) / 2" title="\Delta\omega_F = (\omega_{engine,1} - \omega_{engine,1^*}) / 2" /></p> </div> </div> </div> @@ -3206,8 +3208,8 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge <li><strong>Input Torque</strong> (T<sub>ref(ν)</sub>) is the input torque (over ν) for a specific reference engine speed (see below).</li> </ul> <p>The Input Torque at  reference engine speed is needed to calculate the actual engine torque using this formula:</p> -<p><span class="math inline">\(T_{in} = T_{ref}(v) \cdot ( \frac{n_{in}}{n_{ref}} )^{2}\)</span></p> -<p><span class="math inline">\(μ(ν) = \frac{T_{out}}{T_{in}}\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="T_{in} = T_{ref}(v) \cdot ( \frac{n_{in}}{n_{ref}} )^{2}" title="T_{in} = T_{ref}(v) \cdot ( \frac{n_{in}}{n_{ref}} )^{2}" /></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="\mu(\nu) = \frac{T_{out}}{T_{in}}" title="\mu(\nu) = \frac{T_{out}}{T_{in}}" /></p> <p>with:</p> <ul> <li>T<sub>in</sub> = engine torque [Nm]</li> @@ -3220,8 +3222,8 @@ Example: “Gears\Gear1.vtlm†points to the “Gears†subdirectory of the Ge <div class="declaration"> <p>In declaration mode, the torque converter for drag points is automatically appended by VECTO. Input data with a speed ratio ≥ 1 are skipped.</p> <p>For Power Split transmissions, where the torque converter characteristics already contains the gearbox losses and transmission ratio, the generic drag points are adapted according to the following equations:</p> -<p><span class="math inline">\(ν_{PS} = ν / ratio_i\)</span></p> -<p><span class="math inline">\(μ_{PS} = μ \cdot ratio_i\)</span></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="\nu_{PS} = \nu / ratio_i" title="\nu_{PS} = \nu / ratio_i" /></p> +<p><img style="vertical-align:middle" src="data:image/png;base64,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" alt="\mu_{PS} = \mu \cdot ratio_i" title="\mu_{PS} = \mu \cdot ratio_i" /></p> </div> <div class="engineering"> <p>In engineering mode the drag points for the torque converter can be specified. If so, the input data has to cover at least the speed ratio up to 2.2.</p> @@ -5299,7 +5301,7 @@ CycleTime,UnknownCycleName,3600</code></pre> <h2>Modal Results (.vmod)</h2> <p>Modal results are only created if enabled in the <a href="#main-form">Options</a> tab. One file is created for each calculation and stored in the same directory as the .vecto file.</p> <p>In Vecto 3 the structure of the modal data output has been revised and re-structured. Basically for every powertrain component the .vmod file contains the power at the input shaft and the individual power losses for every component. For the engine the power, torque and engine speed at the output shaft is given along with the internal power and torque used for computing the fuel consumption. See <a href="#powertrain-and-components-structure">Powertrain and Components Structure</a> for schematics how the powertrain looks like and which positions in the powertrain the values represent.</p> -<p>Every line in the .vmod file represents the simulation interval from time - dt/2 to time + dt/2. All values represent the average power/torque/angular velocity during this simulation interval. If a certain power value can be described as function of the vehicle’s acceleration the average power is calculated by <span class="math inline">\(P_{avg} = \frac{1}{simulation interval} \int{P(t) dt}\)</span>. <strong>Note:</strong> Columns for the torque converter operating point represent the torque/angular speed at the end of the simulation interval!</p> +<p>Every line in the .vmod file represents the simulation interval from time - dt/2 to time + dt/2. All values represent the average power/torque/angular velocity during this simulation interval. If a certain power value can be described as function of the vehicle’s acceleration the average power is calculated by <img style="vertical-align:middle" src="data:image/png;base64,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" alt="P_{avg} = \frac{1}{simulation interval} \int{P(t) dt}" title="P_{avg} = \frac{1}{simulation interval} \int{P(t) dt}" />. <strong>Note:</strong> Columns for the torque converter operating point represent the torque/angular speed at the end of the simulation interval!</p> <p>The following table lists the columns in the .vmod file:</p> <p><strong><em>Quantities:</em></strong></p> <table style="width:94%;"> @@ -6220,7 +6222,7 @@ CycleTime,UnknownCycleName,3600</code></pre> </div> <div id="FOOTER"> <a target="mainframe" href="mailto:vecto@jrc.ec.europa.eu">Contact</a> -<span style="text-align:right; float:right">Print View: <a href="javascript:$('div').show().not('.vecto2').not('.vecto3').css({'padding-left':'0px'}).filter('#CONTENT,#TOC,#HEADER,#FOOTER,#MathJax_Message').hide();">All</a>, <a href="javascript:$('div').not('.vecto2').not('.vecto3').css({'padding-left':'0px'}).filter('#TOC,#HEADER,#FOOTER,#MathJax_Message').hide();$('#CONTENT').css({'display':'inline'});">Current</a> +<span style="text-align:right; float:right">Print View: <a href="javascript:$('div').show().not('.vecto2').not('.vecto3').css({'padding-left':'0px'}).filter('#CONTENT,#TOC,#HEADER,#FOOTER,#MathJax_Message').hide();void(0);">All</a>, <a href="javascript:$('div').not('.vecto2').not('.vecto3').css({'padding-left':'0px'}).filter('#TOC,#HEADER,#FOOTER,#MathJax_Message').hide();$('#CONTENT').css({'display':'inline'});void(0);">Current</a> </div> </body> </html> diff --git a/Documentation/User Manual/includes/footer.html b/Documentation/User Manual/includes/footer.html index ce4cf4d509c527a6b426b641265b7abc4d903cb3..b216dfa00695b2045a47631ae876b3922dbb29c0 100644 --- a/Documentation/User Manual/includes/footer.html +++ b/Documentation/User Manual/includes/footer.html @@ -1,4 +1,4 @@ -<div id="FOOTER"> -<a target="mainframe" href="mailto:vecto@jrc.ec.europa.eu">Contact</a> -<span style="text-align:right; float:right">Print View: <a href="javascript:$('div').show().not('.vecto2').not('.vecto3').css({'padding-left':'0px'}).filter('#CONTENT,#TOC,#HEADER,#FOOTER,#MathJax_Message').hide();">All</a>, <a href="javascript:$('div').not('.vecto2').not('.vecto3').css({'padding-left':'0px'}).filter('#TOC,#HEADER,#FOOTER,#MathJax_Message').hide();$('#CONTENT').css({'display':'inline'});">Current</a> +<div id="FOOTER"> +<a target="mainframe" href="mailto:vecto@jrc.ec.europa.eu">Contact</a> +<span style="text-align:right; float:right">Print View: <a href="javascript:$('div').show().not('.vecto2').not('.vecto3').css({'padding-left':'0px'}).filter('#CONTENT,#TOC,#HEADER,#FOOTER,#MathJax_Message').hide();void(0);">All</a>, <a href="javascript:$('div').not('.vecto2').not('.vecto3').css({'padding-left':'0px'}).filter('#TOC,#HEADER,#FOOTER,#MathJax_Message').hide();$('#CONTENT').css({'display':'inline'});void(0);">Current</a> </div> \ No newline at end of file diff --git a/Documentation/User Manual/includes/include.js b/Documentation/User Manual/includes/include.js index 67e8a54dc9bdd5a7c6f779179e88e883de07c73d..0b3eda04ec7f075d6ae40329e78ef841d1e4eada 100644 --- a/Documentation/User Manual/includes/include.js +++ b/Documentation/User Manual/includes/include.js @@ -1,46 +1,49 @@ -<script type="text/javascript"> -$(function(){ - var OnClick = function() { - showContent($($(this).attr("href").replace(".", "\\."))); - }; - - var showContent = function(element){ - $("#CONTENT").html(element.html()); - $("#CONTENT > a").click(OnClick); - $("#CONTENT").show(); - window.scrollTo(0, 0); - }; - - - $("body > div:not(#TOC):not(#HEADER):not(#FOOTER):not(.vecto2):not(.vecto3)").hide(); - $("body > div:not(#TOC):not(#HEADER):not(#FOOTER) > div:not(.vecto2):not(.vecto3)").hide(); - - window.onhashchange=function(){showContent($(window.location.hash.replace(".", "\\.")));}; - if (window.location.hash) { - showContent($(window.location.hash.replace(".", "\\."))); - } else { - showContent($("#user-manual")); - } - - $("#TOC").resizable({ - handles: "e", - resize: function(event, ui) { - $("body > div:not(#TOC):not(#HEADER):not(#FOOTER)").css("padding-left", ui.size.width); - } - }); - $("#TOC").scroll(function() { - $(".ui-resizable-handle").css('top', $("#TOC").scrollTop()); - }); - - -/* hide some items from TOC */ - -$("#TOC li a[href='#electrical-auxiliaries-editor']").parent().hide() -$("#TOC li a[href='#combined-alternator-map-file-.aalt']").parent().hide() -$("#TOC li a[href='#pneumatic-auxiliaries-editor']").parent().hide() -$("#TOC li a[href='#hvac-auxiliaries-editor']").parent().hide() -/*-------------------------*/ - - $("td[align=left").filter(function() {return $(this).text().indexOf("Locked default")===0 || $(this).text().indexOf("Locked Calc") === 0; }).addClass("aaux_locked") -}); +<script type="text/javascript"> +$(function(){ + var OnClick = function() { + showContent($($(this).attr("href").replace(".", "\\."))); + }; + + var showContent = function(element){ + $("#CONTENT").html(element.html()); + $("#CONTENT > a").click(OnClick); + $("#CONTENT").show(); + window.scrollTo(0, 0); + }; + + + $("body > div:not(#TOC):not(#HEADER):not(#FOOTER):not(.vecto2):not(.vecto3)").hide(); + $("body > div:not(#TOC):not(#HEADER):not(#FOOTER) > div:not(.vecto2):not(.vecto3)").hide(); + + window.onhashchange=function(){showContent($(window.location.hash.replace(".", "\\.")));}; + if (window.location.hash) { + showContent($(window.location.hash.replace(".", "\\."))); + } else { + showContent($("#user-manual")); + } + + $("#TOC").resizable(); + + $("#TOC").resizable({ + handles: "e", + resize: function(event, ui) { + $("body > div:not(#TOC):not(#HEADER):not(#FOOTER)").css("padding-left", ui.size.width); + } + }); + + $("#TOC").scroll(function() { + $(".ui-resizable-handle").css('top', $("#TOC").scrollTop()); + }); + + +/* hide some items from TOC */ + +$("#TOC li a[href='#electrical-auxiliaries-editor']").parent().hide() +$("#TOC li a[href='#combined-alternator-map-file-.aalt']").parent().hide() +$("#TOC li a[href='#pneumatic-auxiliaries-editor']").parent().hide() +$("#TOC li a[href='#hvac-auxiliaries-editor']").parent().hide() +/*-------------------------*/ + + $("td[align=left").filter(function() {return $(this).text().indexOf("Locked default")===0 || $(this).text().indexOf("Locked Calc") === 0; }).addClass("aaux_locked") +}); </script> \ No newline at end of file diff --git a/Documentation/User Manual/includes/mathjax.js b/Documentation/User Manual/includes/mathjax.js deleted file mode 100644 index c6ae0ca48b0337c4c6a0e08f985b150a055240da..0000000000000000000000000000000000000000 --- a/Documentation/User Manual/includes/mathjax.js +++ /dev/null @@ -1,4 +0,0 @@ -var fileref=document.createElement('script') -fileref.setAttribute("type","text/javascript") -fileref.setAttribute("src", "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML") -document.getElementsByTagName("head")[0].appendChild(fileref) \ No newline at end of file diff --git a/Documentation/User Manual/includes/style.css b/Documentation/User Manual/includes/style.css index 5f2db1ecd9df0be7c38551cecb04f1752f120bba..0446214ffc5f566fb28d04b8bd232e139d264d77 100644 --- a/Documentation/User Manual/includes/style.css +++ b/Documentation/User Manual/includes/style.css @@ -4,6 +4,8 @@ body { font-family: Calibri, sans-serif; } +.section.level1 {padding-left:336px} + nav, #TOC { position: fixed; width: 21em; diff --git a/VECTO/GUI/GearboxForm.Designer.vb b/VECTO/GUI/GearboxForm.Designer.vb index c89fef41700568bacdd8c8c0bd8077b3dfeb9100..6f80f975570445064d248f5c1693c91365da8dae 100644 --- a/VECTO/GUI/GearboxForm.Designer.vb +++ b/VECTO/GUI/GearboxForm.Designer.vb @@ -100,6 +100,19 @@ Partial Class GearboxForm Me.OpenWithToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem() Me.ShowInFolderToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem() Me.gbTC = New System.Windows.Forms.GroupBox() + Me.pnTcEngineering = New System.Windows.Forms.Panel() + Me.Label26 = New System.Windows.Forms.Label() + Me.TBTCShiftPolygon = New System.Windows.Forms.TextBox() + Me.tbTCmaxSpeed = New System.Windows.Forms.TextBox() + Me.TbTCrefrpm = New System.Windows.Forms.TextBox() + Me.Label27 = New System.Windows.Forms.Label() + Me.Label14 = New System.Windows.Forms.Label() + Me.BtTCShiftFileBrowse = New System.Windows.Forms.Button() + Me.Label1 = New System.Windows.Forms.Label() + Me.TbTCinertia = New System.Windows.Forms.TextBox() + Me.Label15 = New System.Windows.Forms.Label() + Me.Label18 = New System.Windows.Forms.Label() + Me.LblTCShiftFile = New System.Windows.Forms.Label() Me.BtTCfileOpen = New System.Windows.Forms.Button() Me.TbTCfile = New System.Windows.Forms.TextBox() Me.BtTCfileBrowse = New System.Windows.Forms.Button() @@ -125,19 +138,6 @@ Partial Class GearboxForm Me.lblGbxInfo = New System.Windows.Forms.Label() Me.btnExportXML = New System.Windows.Forms.Button() Me.btnExportAxlGearXML = New System.Windows.Forms.Button() - Me.pnTcEngineering = New System.Windows.Forms.Panel() - Me.Label26 = New System.Windows.Forms.Label() - Me.TBTCShiftPolygon = New System.Windows.Forms.TextBox() - Me.tbTCmaxSpeed = New System.Windows.Forms.TextBox() - Me.TbTCrefrpm = New System.Windows.Forms.TextBox() - Me.Label27 = New System.Windows.Forms.Label() - Me.Label14 = New System.Windows.Forms.Label() - Me.BtTCShiftFileBrowse = New System.Windows.Forms.Button() - Me.Label1 = New System.Windows.Forms.Label() - Me.TbTCinertia = New System.Windows.Forms.TextBox() - Me.Label15 = New System.Windows.Forms.Label() - Me.Label18 = New System.Windows.Forms.Label() - Me.LblTCShiftFile = New System.Windows.Forms.Label() Me.ToolStrip1.SuspendLayout() Me.StatusStrip1.SuspendLayout() CType(Me.PictureBox1, System.ComponentModel.ISupportInitialize).BeginInit() @@ -147,12 +147,12 @@ Partial Class GearboxForm Me.GroupBox2.SuspendLayout() Me.CmOpenFile.SuspendLayout() Me.gbTC.SuspendLayout() + Me.pnTcEngineering.SuspendLayout() Me.GroupBox4.SuspendLayout() Me.PnInertiaTI.SuspendLayout() CType(Me.PicBox, System.ComponentModel.ISupportInitialize).BeginInit() Me.gbPowershiftLosses.SuspendLayout() Me.gbTCAccMin.SuspendLayout() - Me.pnTcEngineering.SuspendLayout() Me.SuspendLayout() ' 'ToolStrip1 @@ -711,6 +711,132 @@ Partial Class GearboxForm Me.gbTC.TabStop = False Me.gbTC.Text = "Torque Converter" ' + 'pnTcEngineering + ' + Me.pnTcEngineering.Controls.Add(Me.Label26) + Me.pnTcEngineering.Controls.Add(Me.TBTCShiftPolygon) + Me.pnTcEngineering.Controls.Add(Me.tbTCmaxSpeed) + Me.pnTcEngineering.Controls.Add(Me.TbTCrefrpm) + Me.pnTcEngineering.Controls.Add(Me.Label27) + Me.pnTcEngineering.Controls.Add(Me.Label14) + Me.pnTcEngineering.Controls.Add(Me.BtTCShiftFileBrowse) + Me.pnTcEngineering.Controls.Add(Me.Label1) + Me.pnTcEngineering.Controls.Add(Me.TbTCinertia) + Me.pnTcEngineering.Controls.Add(Me.Label15) + Me.pnTcEngineering.Controls.Add(Me.Label18) + Me.pnTcEngineering.Controls.Add(Me.LblTCShiftFile) + Me.pnTcEngineering.Location = New System.Drawing.Point(7, 63) + Me.pnTcEngineering.Name = "pnTcEngineering" + Me.pnTcEngineering.Size = New System.Drawing.Size(399, 93) + Me.pnTcEngineering.TabIndex = 3 + ' + 'Label26 + ' + Me.Label26.AutoSize = True + Me.Label26.Location = New System.Drawing.Point(1, 29) + Me.Label26.Name = "Label26" + Me.Label26.Size = New System.Drawing.Size(64, 13) + Me.Label26.TabIndex = 50 + Me.Label26.Text = "Max. Speed" + ' + 'TBTCShiftPolygon + ' + Me.TBTCShiftPolygon.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _ + Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.TBTCShiftPolygon.Location = New System.Drawing.Point(4, 70) + Me.TBTCShiftPolygon.Name = "TBTCShiftPolygon" + Me.TBTCShiftPolygon.Size = New System.Drawing.Size(349, 20) + Me.TBTCShiftPolygon.TabIndex = 49 + ' + 'tbTCmaxSpeed + ' + Me.tbTCmaxSpeed.Location = New System.Drawing.Point(75, 26) + Me.tbTCmaxSpeed.Name = "tbTCmaxSpeed" + Me.tbTCmaxSpeed.Size = New System.Drawing.Size(57, 20) + Me.tbTCmaxSpeed.TabIndex = 52 + ' + 'TbTCrefrpm + ' + Me.TbTCrefrpm.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.TbTCrefrpm.Location = New System.Drawing.Point(296, 0) + Me.TbTCrefrpm.Name = "TbTCrefrpm" + Me.TbTCrefrpm.Size = New System.Drawing.Size(57, 20) + Me.TbTCrefrpm.TabIndex = 46 + ' + 'Label27 + ' + Me.Label27.AutoSize = True + Me.Label27.Location = New System.Drawing.Point(138, 29) + Me.Label27.Name = "Label27" + Me.Label27.Size = New System.Drawing.Size(30, 13) + Me.Label27.TabIndex = 51 + Me.Label27.Text = "[rpm]" + ' + 'Label14 + ' + Me.Label14.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.Label14.AutoSize = True + Me.Label14.Location = New System.Drawing.Point(357, 3) + Me.Label14.Name = "Label14" + Me.Label14.Size = New System.Drawing.Size(40, 13) + Me.Label14.TabIndex = 41 + Me.Label14.Text = "[1/min]" + ' + 'BtTCShiftFileBrowse + ' + Me.BtTCShiftFileBrowse.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.BtTCShiftFileBrowse.Image = Global.TUGraz.VECTO.My.Resources.Resources.Open_icon + Me.BtTCShiftFileBrowse.Location = New System.Drawing.Point(354, 68) + Me.BtTCShiftFileBrowse.Name = "BtTCShiftFileBrowse" + Me.BtTCShiftFileBrowse.Size = New System.Drawing.Size(24, 24) + Me.BtTCShiftFileBrowse.TabIndex = 47 + Me.BtTCShiftFileBrowse.TabStop = False + Me.BtTCShiftFileBrowse.UseVisualStyleBackColor = True + ' + 'Label1 + ' + Me.Label1.AutoSize = True + Me.Label1.Location = New System.Drawing.Point(138, 3) + Me.Label1.Name = "Label1" + Me.Label1.Size = New System.Drawing.Size(36, 13) + Me.Label1.TabIndex = 43 + Me.Label1.Text = "[kgm²]" + ' + 'TbTCinertia + ' + Me.TbTCinertia.Location = New System.Drawing.Point(75, 0) + Me.TbTCinertia.Name = "TbTCinertia" + Me.TbTCinertia.Size = New System.Drawing.Size(57, 20) + Me.TbTCinertia.TabIndex = 45 + ' + 'Label15 + ' + Me.Label15.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.Label15.AutoSize = True + Me.Label15.Location = New System.Drawing.Point(213, 3) + Me.Label15.Name = "Label15" + Me.Label15.Size = New System.Drawing.Size(77, 13) + Me.Label15.TabIndex = 42 + Me.Label15.Text = "Reference rpm" + ' + 'Label18 + ' + Me.Label18.AutoSize = True + Me.Label18.Location = New System.Drawing.Point(1, 3) + Me.Label18.Name = "Label18" + Me.Label18.Size = New System.Drawing.Size(36, 13) + Me.Label18.TabIndex = 44 + Me.Label18.Text = "Inertia" + ' + 'LblTCShiftFile + ' + Me.LblTCShiftFile.AutoSize = True + Me.LblTCShiftFile.Location = New System.Drawing.Point(1, 55) + Me.LblTCShiftFile.Name = "LblTCShiftFile" + Me.LblTCShiftFile.Size = New System.Drawing.Size(207, 13) + Me.LblTCShiftFile.TabIndex = 48 + Me.LblTCShiftFile.Text = "Torque converter shift polygons file (.vgbs)" + ' 'BtTCfileOpen ' Me.BtTCfileOpen.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) @@ -951,132 +1077,6 @@ Partial Class GearboxForm Me.btnExportAxlGearXML.Text = "Exp. AxlGear as XML" Me.btnExportAxlGearXML.UseVisualStyleBackColor = True ' - 'pnTcEngineering - ' - Me.pnTcEngineering.Controls.Add(Me.Label26) - Me.pnTcEngineering.Controls.Add(Me.TBTCShiftPolygon) - Me.pnTcEngineering.Controls.Add(Me.tbTCmaxSpeed) - Me.pnTcEngineering.Controls.Add(Me.TbTCrefrpm) - Me.pnTcEngineering.Controls.Add(Me.Label27) - Me.pnTcEngineering.Controls.Add(Me.Label14) - Me.pnTcEngineering.Controls.Add(Me.BtTCShiftFileBrowse) - Me.pnTcEngineering.Controls.Add(Me.Label1) - Me.pnTcEngineering.Controls.Add(Me.TbTCinertia) - Me.pnTcEngineering.Controls.Add(Me.Label15) - Me.pnTcEngineering.Controls.Add(Me.Label18) - Me.pnTcEngineering.Controls.Add(Me.LblTCShiftFile) - Me.pnTcEngineering.Location = New System.Drawing.Point(7, 63) - Me.pnTcEngineering.Name = "pnTcEngineering" - Me.pnTcEngineering.Size = New System.Drawing.Size(399, 93) - Me.pnTcEngineering.TabIndex = 3 - ' - 'Label26 - ' - Me.Label26.AutoSize = True - Me.Label26.Location = New System.Drawing.Point(1, 29) - Me.Label26.Name = "Label26" - Me.Label26.Size = New System.Drawing.Size(64, 13) - Me.Label26.TabIndex = 50 - Me.Label26.Text = "Max. Speed" - ' - 'TBTCShiftPolygon - ' - Me.TBTCShiftPolygon.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _ - Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) - Me.TBTCShiftPolygon.Location = New System.Drawing.Point(4, 70) - Me.TBTCShiftPolygon.Name = "TBTCShiftPolygon" - Me.TBTCShiftPolygon.Size = New System.Drawing.Size(349, 20) - Me.TBTCShiftPolygon.TabIndex = 49 - ' - 'tbTCmaxSpeed - ' - Me.tbTCmaxSpeed.Location = New System.Drawing.Point(75, 26) - Me.tbTCmaxSpeed.Name = "tbTCmaxSpeed" - Me.tbTCmaxSpeed.Size = New System.Drawing.Size(57, 20) - Me.tbTCmaxSpeed.TabIndex = 52 - ' - 'TbTCrefrpm - ' - Me.TbTCrefrpm.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) - Me.TbTCrefrpm.Location = New System.Drawing.Point(296, 0) - Me.TbTCrefrpm.Name = "TbTCrefrpm" - Me.TbTCrefrpm.Size = New System.Drawing.Size(57, 20) - Me.TbTCrefrpm.TabIndex = 46 - ' - 'Label27 - ' - Me.Label27.AutoSize = True - Me.Label27.Location = New System.Drawing.Point(138, 29) - Me.Label27.Name = "Label27" - Me.Label27.Size = New System.Drawing.Size(30, 13) - Me.Label27.TabIndex = 51 - Me.Label27.Text = "[rpm]" - ' - 'Label14 - ' - Me.Label14.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) - Me.Label14.AutoSize = True - Me.Label14.Location = New System.Drawing.Point(357, 3) - Me.Label14.Name = "Label14" - Me.Label14.Size = New System.Drawing.Size(40, 13) - Me.Label14.TabIndex = 41 - Me.Label14.Text = "[1/min]" - ' - 'BtTCShiftFileBrowse - ' - Me.BtTCShiftFileBrowse.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) - Me.BtTCShiftFileBrowse.Image = Global.TUGraz.VECTO.My.Resources.Resources.Open_icon - Me.BtTCShiftFileBrowse.Location = New System.Drawing.Point(354, 68) - Me.BtTCShiftFileBrowse.Name = "BtTCShiftFileBrowse" - Me.BtTCShiftFileBrowse.Size = New System.Drawing.Size(24, 24) - Me.BtTCShiftFileBrowse.TabIndex = 47 - Me.BtTCShiftFileBrowse.TabStop = False - Me.BtTCShiftFileBrowse.UseVisualStyleBackColor = True - ' - 'Label1 - ' - Me.Label1.AutoSize = True - Me.Label1.Location = New System.Drawing.Point(138, 3) - Me.Label1.Name = "Label1" - Me.Label1.Size = New System.Drawing.Size(36, 13) - Me.Label1.TabIndex = 43 - Me.Label1.Text = "[kgm²]" - ' - 'TbTCinertia - ' - Me.TbTCinertia.Location = New System.Drawing.Point(75, 0) - Me.TbTCinertia.Name = "TbTCinertia" - Me.TbTCinertia.Size = New System.Drawing.Size(57, 20) - Me.TbTCinertia.TabIndex = 45 - ' - 'Label15 - ' - Me.Label15.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) - Me.Label15.AutoSize = True - Me.Label15.Location = New System.Drawing.Point(213, 3) - Me.Label15.Name = "Label15" - Me.Label15.Size = New System.Drawing.Size(77, 13) - Me.Label15.TabIndex = 42 - Me.Label15.Text = "Reference rpm" - ' - 'Label18 - ' - Me.Label18.AutoSize = True - Me.Label18.Location = New System.Drawing.Point(1, 3) - Me.Label18.Name = "Label18" - Me.Label18.Size = New System.Drawing.Size(36, 13) - Me.Label18.TabIndex = 44 - Me.Label18.Text = "Inertia" - ' - 'LblTCShiftFile - ' - Me.LblTCShiftFile.AutoSize = True - Me.LblTCShiftFile.Location = New System.Drawing.Point(1, 55) - Me.LblTCShiftFile.Name = "LblTCShiftFile" - Me.LblTCShiftFile.Size = New System.Drawing.Size(207, 13) - Me.LblTCShiftFile.TabIndex = 48 - Me.LblTCShiftFile.Text = "Torque converter shift polygons file (.vgbs)" - ' 'GearboxForm ' Me.AcceptButton = Me.ButOK @@ -1125,6 +1125,8 @@ Partial Class GearboxForm Me.CmOpenFile.ResumeLayout(False) Me.gbTC.ResumeLayout(False) Me.gbTC.PerformLayout() + Me.pnTcEngineering.ResumeLayout(False) + Me.pnTcEngineering.PerformLayout() Me.GroupBox4.ResumeLayout(False) Me.GroupBox4.PerformLayout() Me.PnInertiaTI.ResumeLayout(False) @@ -1134,8 +1136,6 @@ Partial Class GearboxForm Me.gbPowershiftLosses.PerformLayout() Me.gbTCAccMin.ResumeLayout(False) Me.gbTCAccMin.PerformLayout() - Me.pnTcEngineering.ResumeLayout(False) - Me.pnTcEngineering.PerformLayout() Me.ResumeLayout(False) Me.PerformLayout() diff --git a/VECTO/GUI/GearboxForm.vb b/VECTO/GUI/GearboxForm.vb index 3e3e89ec900952ab14c86b4eec290ae6d0b47b01..e7444abdc5ac65f7600b80ec8b50e088306854f6 100644 --- a/VECTO/GUI/GearboxForm.vb +++ b/VECTO/GUI/GearboxForm.vb @@ -13,11 +13,8 @@ Imports System.Drawing.Imaging Imports System.Globalization Imports System.IO Imports System.Linq -Imports System.Text.RegularExpressions Imports System.Windows.Forms.DataVisualization.Charting Imports System.Xml.Linq -Imports Microsoft.WindowsAPICodePack.Dialogs -Imports TUGraz.IVT.VectoXML.Writer Imports TUGraz.VECTO.Input_Files Imports TUGraz.VectoCommon.InputData Imports TUGraz.VectoCommon.Models @@ -132,7 +129,7 @@ Public Class GearboxForm Private Sub ToolStripBtOpen_Click(sender As Object, e As EventArgs) Handles ToolStripBtOpen.Click If GearboxFileBrowser.OpenDialog(_gbxFile) Then Try - OpenGbx(GearboxFileBrowser.Files(0)) + OpenGbx(GearboxFileBrowser.Files(0), VehicleCategory.RigidTruck) Catch ex As Exception MsgBox("Failed to open Gearbox File: " + ex.Message) End Try @@ -234,7 +231,7 @@ Public Class GearboxForm End Sub 'Open file - Public Sub OpenGbx(file As String) + Public Sub OpenGbx(file As String, vehicleCategory As VehicleCategory) If ChangeCheckCancel() Then Exit Sub @@ -243,6 +240,8 @@ Public Class GearboxForm Dim gearbox As IGearboxEngineeringInputData = inputData.GearboxInputData Dim axlegear As IAxleGearInputData = inputData.AxleGearInputData + _vehicleCategory = vehicleCategory + If Cfg.DeclMode <> gearbox.SavedInDeclarationMode Then Select Case WrongMode() Case 1 @@ -524,7 +523,8 @@ Public Class GearboxForm If LvGears.Items.Count > 2 Then Dim ratio1 As Double = LvGears.Items.Item(1).SubItems(GearboxTbl.Ratio).Text.ToDouble(0) Dim ratio2 As Double = LvGears.Items.Item(2).SubItems(GearboxTbl.Ratio).Text.ToDouble(0) - If ratio1 / ratio2 >= DeclarationData.Gearbox.TorqueConverterSecondGearThreshold Then + + If ratio1 / ratio2 >= DeclarationData.Gearbox.TorqueConverterSecondGearThreshold(_vehicleCategory) Then text = "Torque converter is used in 1st and 2nd gear" Else text = "Torque converter is used in 1st gear only" @@ -696,6 +696,7 @@ Public Class GearboxForm #Region "Open File Context Menu" Private _contextMenuFiles As String() + Private _vehicleCategory As VehicleCategory Private Sub OpenFiles(ParamArray files() As String) @@ -965,7 +966,7 @@ Public Class GearboxForm ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu. End Sub - Private Sub BtTCShiftFileBrowse_Click(sender As Object, e As EventArgs) + Private Sub BtTCShiftFileBrowse_Click(sender As Object, e As EventArgs) Handles BtTCShiftFileBrowse.Click If TorqueConverterShiftPolygonFileBrowser.OpenDialog(FileRepl(TBTCShiftPolygon.Text, GetPath(_gbxFile))) Then TBTCShiftPolygon.Text = GetFilenameWithoutDirectory(TorqueConverterShiftPolygonFileBrowser.Files(0), GetPath(_gbxFile)) @@ -973,35 +974,35 @@ Public Class GearboxForm End Sub Private Sub btnExportXML_Click(sender As Object, e As EventArgs) Handles btnExportXML.Click - Dim dialog As CommonOpenFileDialog = New CommonOpenFileDialog() - dialog.IsFolderPicker = True - If (dialog.ShowDialog() = CommonFileDialogResult.Cancel) Then + If Not FolderFileBrowser.OpenDialog("") Then Exit Sub End If + Dim filePath As String = FolderFileBrowser.Files(0) + Dim data As Gearbox = FillGearboxData(_gbxFile) If (Cfg.DeclMode) Then Dim export As XDocument = New XMLDeclarationWriter(data.Manufacturer).GenerateVectoComponent(data, data) - export.Save(Path.Combine(dialog.FileName, data.ModelName + ".xml")) + export.Save(Path.Combine(filePath, data.ModelName + ".xml")) Else Dim export As XDocument = New XMLEngineeringWriter(_gbxFile, True, data.Manufacturer).GenerateVectoComponent(data, data) - export.Save(Path.Combine(dialog.FileName, data.ModelName + ".xml")) + export.Save(Path.Combine(filePath, data.ModelName + ".xml")) End If End Sub Private Sub btnExportAxlGearXML_Click(sender As Object, e As EventArgs) Handles btnExportAxlGearXML.Click - Dim dialog As CommonOpenFileDialog = New CommonOpenFileDialog() - dialog.IsFolderPicker = True - If (dialog.ShowDialog() = CommonFileDialogResult.Cancel) Then + If Not FolderFileBrowser.OpenDialog("") Then Exit Sub End If + Dim filePath As String = FolderFileBrowser.Files(0) + Dim data As Gearbox = FillGearboxData(_gbxFile) If (Cfg.DeclMode) Then Dim export As XDocument = New XMLDeclarationWriter(data.Manufacturer).GenerateVectoComponent(data) - export.Save(Path.Combine(dialog.FileName, data.ModelName + ".xml")) + export.Save(Path.Combine(filePath, data.ModelName + ".xml")) Else Dim export As XDocument = New XMLEngineeringWriter(_gbxFile, True, data.Manufacturer).GenerateVectoComponent(data) - export.Save(Path.Combine(dialog.FileName, data.ModelName + ".xml")) + export.Save(Path.Combine(filePath, data.ModelName + ".xml")) End If End Sub End Class diff --git a/VECTO/GUI/MainForm.Designer.vb b/VECTO/GUI/MainForm.Designer.vb index 74c4c9b3838a7b7c3d2d38c03c2a89a1caec507d..bea024c9f0a7009523dd6109cb5d464aacace9b0 100644 --- a/VECTO/GUI/MainForm.Designer.vb +++ b/VECTO/GUI/MainForm.Designer.vb @@ -114,6 +114,7 @@ Partial Class MainForm Me.OpenInGraphWindowToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem() Me.ShowInFolderToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem() Me.ToolTip1 = New System.Windows.Forms.ToolTip(Me.components) + Me.cbActVmod = New System.Windows.Forms.CheckBox() Me.StatusBAR.SuspendLayout() Me.TabControl1.SuspendLayout() Me.TabPageGEN.SuspendLayout() @@ -383,10 +384,11 @@ Partial Class MainForm ' 'GroupBox3 ' + Me.GroupBox3.Controls.Add(Me.cbActVmod) Me.GroupBox3.Controls.Add(Me.cbValidateRunData) Me.GroupBox3.Location = New System.Drawing.Point(3, 177) Me.GroupBox3.Name = "GroupBox3" - Me.GroupBox3.Size = New System.Drawing.Size(173, 64) + Me.GroupBox3.Size = New System.Drawing.Size(173, 110) Me.GroupBox3.TabIndex = 18 Me.GroupBox3.TabStop = False Me.GroupBox3.Text = "Misc" @@ -680,52 +682,52 @@ Partial Class MainForm ' Me.GENEditorToolStripMenuItem1.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_VECTO Me.GENEditorToolStripMenuItem1.Name = "GENEditorToolStripMenuItem1" - Me.GENEditorToolStripMenuItem1.Size = New System.Drawing.Size(170, 22) + Me.GENEditorToolStripMenuItem1.Size = New System.Drawing.Size(151, 22) Me.GENEditorToolStripMenuItem1.Text = "Job Editor" ' 'VEHEditorToolStripMenuItem ' Me.VEHEditorToolStripMenuItem.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_VEH Me.VEHEditorToolStripMenuItem.Name = "VEHEditorToolStripMenuItem" - Me.VEHEditorToolStripMenuItem.Size = New System.Drawing.Size(170, 22) + Me.VEHEditorToolStripMenuItem.Size = New System.Drawing.Size(151, 22) Me.VEHEditorToolStripMenuItem.Text = "Vehicle Editor" ' 'EngineEditorToolStripMenuItem ' Me.EngineEditorToolStripMenuItem.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_ENG Me.EngineEditorToolStripMenuItem.Name = "EngineEditorToolStripMenuItem" - Me.EngineEditorToolStripMenuItem.Size = New System.Drawing.Size(170, 22) + Me.EngineEditorToolStripMenuItem.Size = New System.Drawing.Size(151, 22) Me.EngineEditorToolStripMenuItem.Text = "Engine Editor" ' 'GearboxEditorToolStripMenuItem ' Me.GearboxEditorToolStripMenuItem.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_GBX Me.GearboxEditorToolStripMenuItem.Name = "GearboxEditorToolStripMenuItem" - Me.GearboxEditorToolStripMenuItem.Size = New System.Drawing.Size(170, 22) + Me.GearboxEditorToolStripMenuItem.Size = New System.Drawing.Size(151, 22) Me.GearboxEditorToolStripMenuItem.Text = "Gearbox Editor" ' 'GraphToolStripMenuItem ' Me.GraphToolStripMenuItem.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_Graph Me.GraphToolStripMenuItem.Name = "GraphToolStripMenuItem" - Me.GraphToolStripMenuItem.Size = New System.Drawing.Size(170, 22) + Me.GraphToolStripMenuItem.Size = New System.Drawing.Size(151, 22) Me.GraphToolStripMenuItem.Text = "Graph" ' 'ToolStripSeparator6 ' Me.ToolStripSeparator6.Name = "ToolStripSeparator6" - Me.ToolStripSeparator6.Size = New System.Drawing.Size(167, 6) + Me.ToolStripSeparator6.Size = New System.Drawing.Size(148, 6) ' 'OpenLogToolStripMenuItem ' Me.OpenLogToolStripMenuItem.Name = "OpenLogToolStripMenuItem" - Me.OpenLogToolStripMenuItem.Size = New System.Drawing.Size(170, 22) + Me.OpenLogToolStripMenuItem.Size = New System.Drawing.Size(151, 22) Me.OpenLogToolStripMenuItem.Text = "Open Log" ' 'SettingsToolStripMenuItem ' Me.SettingsToolStripMenuItem.Name = "SettingsToolStripMenuItem" - Me.SettingsToolStripMenuItem.Size = New System.Drawing.Size(170, 22) + Me.SettingsToolStripMenuItem.Size = New System.Drawing.Size(151, 22) Me.SettingsToolStripMenuItem.Text = "Settings" ' 'ToolStripDrDnBtInfo @@ -801,6 +803,15 @@ Partial Class MainForm Me.ShowInFolderToolStripMenuItem.Size = New System.Drawing.Size(173, 22) Me.ShowInFolderToolStripMenuItem.Text = "Show in Folder" ' + 'cbActVmod + ' + Me.cbActVmod.Location = New System.Drawing.Point(6, 41) + Me.cbActVmod.Name = "cbActVmod" + Me.cbActVmod.Size = New System.Drawing.Size(161, 63) + Me.cbActVmod.TabIndex = 18 + Me.cbActVmod.Text = "Output values in vmod at beginning and end of simulation interval (EXPERT!)" + Me.cbActVmod.UseVisualStyleBackColor = True + ' 'MainForm ' Me.AcceptButton = Me.btStartV3 @@ -930,5 +941,6 @@ Partial Class MainForm Friend WithEvents ShowInFolderMenuItem As System.Windows.Forms.ToolStripMenuItem Friend WithEvents GroupBox3 As System.Windows.Forms.GroupBox Friend WithEvents cbValidateRunData As System.Windows.Forms.CheckBox + Friend WithEvents cbActVmod As System.Windows.Forms.CheckBox End Class diff --git a/VECTO/GUI/MainForm.vb b/VECTO/GUI/MainForm.vb index 9b9b7d3b381dddfe6db2d36fb579d4b1bfd4cf76..57879211bbf75bc316787681377b3c3fd0406db0 100644 --- a/VECTO/GUI/MainForm.vb +++ b/VECTO/GUI/MainForm.vb @@ -341,7 +341,7 @@ Imports TUGraz.VectoCore.OutputData.FileIO GearboxForm.BringToFront() End If Try - GearboxForm.OpenGbx(file) + GearboxForm.OpenGbx(file, VehicleCategory.RigidTruck) Catch ex As Exception MsgBox("Failed to open Gearbox File: " + ex.Message) End Try @@ -970,6 +970,7 @@ Imports TUGraz.VectoCore.OutputData.FileIO runsFactory.WriteModalResults = Cfg.ModOut runsFactory.ModalResults1Hz = Cfg.Mod1Hz runsFactory.Validate = cbValidateRunData.Checked + runsFactory.ActualModalData = cbActVmod.Checked For Each runId As Integer In jobContainer.AddRuns(runsFactory) fileWriters.Add(runId, fileWriter) diff --git a/VECTO/GUI/VectoJobForm.vb b/VECTO/GUI/VectoJobForm.vb index ba1a4fc34c90668aba3c5713d010bb9b89658b17..18bd338ee58e8a67da2967b6ff8302c114d6b7bf 100644 --- a/VECTO/GUI/VectoJobForm.vb +++ b/VECTO/GUI/VectoJobForm.vb @@ -296,8 +296,20 @@ Public Class VectoJobForm If GearboxForm.WindowState = FormWindowState.Minimized Then GearboxForm.WindowState = FormWindowState.Normal GearboxForm.BringToFront() End If + Dim vehicleType As VehicleCategory Try - If Not Trim(f) = "" Then GearboxForm.OpenGbx(f) + If Not Trim(f) = "" Then + Dim vehInput As IVehicleDeclarationInputData = + CType(JSONInputDataFactory.ReadComponentData(FileRepl(TbVEH.Text, GetPath(VectoFile))), + IEngineeringInputDataProvider).VehicleInputData + vehicleType = vehInput.VehicleCategory + End If + + Catch ex As Exception + vehicleType = VehicleCategory.RigidTruck + End Try + Try + If Not Trim(f) = "" Then GearboxForm.OpenGbx(f, vehicleType) Catch ex As Exception MsgBox("Failed to open Gearbox File: " + ex.Message) End Try @@ -680,7 +692,8 @@ Public Class VectoJobForm CbEngOnly.Checked = False - RdOff.Checked = True + 'RdOff.Checked = True + RdOverspeed.Checked = True CbLookAhead.Checked = True 'TbAlookahead.Text = "-0.5" TbOverspeed.Text = DeclarationData.Driver.OverSpeedEcoRoll.OverSpeed.AsKmph.ToGUIFormat() diff --git a/VECTO/GUI/VehicleForm.Designer.vb b/VECTO/GUI/VehicleForm.Designer.vb index 434ffb244dd4b7cf63ca4b8d08389bc58cd12eb2..0db5e85b16b9d50c2221c4ac5fa06fbc802ca8c8 100644 --- a/VECTO/GUI/VehicleForm.Designer.vb +++ b/VECTO/GUI/VehicleForm.Designer.vb @@ -85,6 +85,7 @@ Partial Class VehicleForm Me.ColumnHeader1 = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader) Me.ColumnHeader3 = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader) Me.ColumnHeader4 = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader) + Me.ColumnHeader10 = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader) Me.ButAxlAdd = New System.Windows.Forms.Button() Me.PnWheelDiam = New System.Windows.Forms.Panel() Me.CbAxleConfig = New System.Windows.Forms.ComboBox() @@ -95,9 +96,6 @@ Partial Class VehicleForm Me.StatusStrip1 = New System.Windows.Forms.StatusStrip() Me.LbStatus = New System.Windows.Forms.ToolStripStatusLabel() Me.TbHDVclass = New System.Windows.Forms.TextBox() - Me.Label11 = New System.Windows.Forms.Label() - Me.TbLoadingMax = New System.Windows.Forms.TextBox() - Me.Label22 = New System.Windows.Forms.Label() Me.GroupBox1 = New System.Windows.Forms.GroupBox() Me.PnLoad = New System.Windows.Forms.Panel() Me.GrAirRes = New System.Windows.Forms.GroupBox() @@ -131,6 +129,11 @@ Partial Class VehicleForm Me.ToolTip1 = New System.Windows.Forms.ToolTip(Me.components) Me.TabControl1 = New System.Windows.Forms.TabControl() Me.TabPage1 = New System.Windows.Forms.TabPage() + Me.GroupBox4 = New System.Windows.Forms.GroupBox() + Me.Panel1 = New System.Windows.Forms.Panel() + Me.tbVehIdlingSpeed = New System.Windows.Forms.TextBox() + Me.Label18 = New System.Windows.Forms.Label() + Me.Label19 = New System.Windows.Forms.Label() Me.TabPage2 = New System.Windows.Forms.TabPage() Me.TabPage3 = New System.Windows.Forms.TabPage() Me.lvTorqueLimits = New System.Windows.Forms.ListView() @@ -139,12 +142,6 @@ Partial Class VehicleForm Me.Label17 = New System.Windows.Forms.Label() Me.btDelMaxTorqueEntry = New System.Windows.Forms.Button() Me.btAddMaxTorqueEntry = New System.Windows.Forms.Button() - Me.ColumnHeader10 = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader) - Me.GroupBox4 = New System.Windows.Forms.GroupBox() - Me.Panel1 = New System.Windows.Forms.Panel() - Me.tbVehIdlingSpeed = New System.Windows.Forms.TextBox() - Me.Label18 = New System.Windows.Forms.Label() - Me.Label19 = New System.Windows.Forms.Label() Me.GroupBox6.SuspendLayout() Me.ToolStrip1.SuspendLayout() Me.GroupBox7.SuspendLayout() @@ -166,10 +163,10 @@ Partial Class VehicleForm CType(Me.PicVehicle, System.ComponentModel.ISupportInitialize).BeginInit() Me.TabControl1.SuspendLayout() Me.TabPage1.SuspendLayout() - Me.TabPage2.SuspendLayout() - Me.TabPage3.SuspendLayout() Me.GroupBox4.SuspendLayout() Me.Panel1.SuspendLayout() + Me.TabPage2.SuspendLayout() + Me.TabPage3.SuspendLayout() Me.SuspendLayout() ' 'Label1 @@ -239,7 +236,7 @@ Partial Class VehicleForm 'ButOK ' Me.ButOK.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) - Me.ButOK.Location = New System.Drawing.Point(431, 557) + Me.ButOK.Location = New System.Drawing.Point(431, 532) Me.ButOK.Name = "ButOK" Me.ButOK.Size = New System.Drawing.Size(75, 23) Me.ButOK.TabIndex = 5 @@ -250,7 +247,7 @@ Partial Class VehicleForm ' Me.ButCancel.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) Me.ButCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel - Me.ButCancel.Location = New System.Drawing.Point(512, 557) + Me.ButCancel.Location = New System.Drawing.Point(512, 532) Me.ButCancel.Name = "ButCancel" Me.ButCancel.Size = New System.Drawing.Size(75, 23) Me.ButCancel.TabIndex = 6 @@ -298,7 +295,7 @@ Partial Class VehicleForm ' Me.TbCdFile.Anchor = System.Windows.Forms.AnchorStyles.None Me.TbCdFile.Enabled = False - Me.TbCdFile.Location = New System.Drawing.Point(6, 68) + Me.TbCdFile.Location = New System.Drawing.Point(9, 65) Me.TbCdFile.Name = "TbCdFile" Me.TbCdFile.Size = New System.Drawing.Size(210, 20) Me.TbCdFile.TabIndex = 1 @@ -308,7 +305,7 @@ Partial Class VehicleForm Me.BtCdFileBrowse.Anchor = System.Windows.Forms.AnchorStyles.None Me.BtCdFileBrowse.Enabled = False Me.BtCdFileBrowse.Image = Global.TUGraz.VECTO.My.Resources.Resources.Open_icon - Me.BtCdFileBrowse.Location = New System.Drawing.Point(222, 65) + Me.BtCdFileBrowse.Location = New System.Drawing.Point(225, 62) Me.BtCdFileBrowse.Name = "BtCdFileBrowse" Me.BtCdFileBrowse.Size = New System.Drawing.Size(24, 24) Me.BtCdFileBrowse.TabIndex = 2 @@ -323,7 +320,7 @@ Partial Class VehicleForm Me.GroupBox6.Controls.Add(Me.TbCdFile) Me.GroupBox6.Location = New System.Drawing.Point(290, 70) Me.GroupBox6.Name = "GroupBox6" - Me.GroupBox6.Size = New System.Drawing.Size(281, 109) + Me.GroupBox6.Size = New System.Drawing.Size(281, 96) Me.GroupBox6.TabIndex = 5 Me.GroupBox6.TabStop = False Me.GroupBox6.Text = "Cross Wind Correction" @@ -333,7 +330,7 @@ Partial Class VehicleForm Me.BtCdFileOpen.Anchor = System.Windows.Forms.AnchorStyles.None Me.BtCdFileOpen.Enabled = False Me.BtCdFileOpen.Image = Global.TUGraz.VECTO.My.Resources.Resources.application_export_icon_small - Me.BtCdFileOpen.Location = New System.Drawing.Point(246, 65) + Me.BtCdFileOpen.Location = New System.Drawing.Point(249, 62) Me.BtCdFileOpen.Name = "BtCdFileOpen" Me.BtCdFileOpen.Size = New System.Drawing.Size(24, 24) Me.BtCdFileOpen.TabIndex = 3 @@ -343,7 +340,7 @@ Partial Class VehicleForm 'LbCdMode ' Me.LbCdMode.AutoSize = True - Me.LbCdMode.Location = New System.Drawing.Point(6, 48) + Me.LbCdMode.Location = New System.Drawing.Point(6, 47) Me.LbCdMode.Name = "LbCdMode" Me.LbCdMode.Size = New System.Drawing.Size(59, 13) Me.LbCdMode.TabIndex = 28 @@ -548,7 +545,7 @@ Partial Class VehicleForm Me.GroupBox8.Controls.Add(Me.ButAxlRem) Me.GroupBox8.Controls.Add(Me.LvRRC) Me.GroupBox8.Controls.Add(Me.ButAxlAdd) - Me.GroupBox8.Location = New System.Drawing.Point(7, 185) + Me.GroupBox8.Location = New System.Drawing.Point(6, 172) Me.GroupBox8.Name = "GroupBox8" Me.GroupBox8.Size = New System.Drawing.Size(564, 151) Me.GroupBox8.TabIndex = 2 @@ -624,6 +621,11 @@ Partial Class VehicleForm ' Me.ColumnHeader4.Text = "Inertia" ' + 'ColumnHeader10 + ' + Me.ColumnHeader10.Text = "Axle Type" + Me.ColumnHeader10.Width = 130 + ' 'ButAxlAdd ' Me.ButAxlAdd.Image = Global.TUGraz.VECTO.My.Resources.Resources.plus_circle_icon @@ -693,7 +695,7 @@ Partial Class VehicleForm 'StatusStrip1 ' Me.StatusStrip1.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.LbStatus}) - Me.StatusStrip1.Location = New System.Drawing.Point(0, 583) + Me.StatusStrip1.Location = New System.Drawing.Point(0, 558) Me.StatusStrip1.Name = "StatusStrip1" Me.StatusStrip1.Size = New System.Drawing.Size(599, 22) Me.StatusStrip1.SizingGrip = False @@ -716,33 +718,6 @@ Partial Class VehicleForm Me.TbHDVclass.TabStop = False Me.TbHDVclass.TextAlign = System.Windows.Forms.HorizontalAlignment.Center ' - 'Label11 - ' - Me.Label11.AutoSize = True - Me.Label11.Location = New System.Drawing.Point(89, 57) - Me.Label11.Name = "Label11" - Me.Label11.Size = New System.Drawing.Size(71, 13) - Me.Label11.TabIndex = 31 - Me.Label11.Text = "Max. Loading" - ' - 'TbLoadingMax - ' - Me.TbLoadingMax.Location = New System.Drawing.Point(166, 54) - Me.TbLoadingMax.Name = "TbLoadingMax" - Me.TbLoadingMax.ReadOnly = True - Me.TbLoadingMax.Size = New System.Drawing.Size(57, 20) - Me.TbLoadingMax.TabIndex = 2 - Me.TbLoadingMax.TabStop = False - ' - 'Label22 - ' - Me.Label22.AutoSize = True - Me.Label22.Location = New System.Drawing.Point(225, 57) - Me.Label22.Name = "Label22" - Me.Label22.Size = New System.Drawing.Size(25, 13) - Me.Label22.TabIndex = 24 - Me.Label22.Text = "[kg]" - ' 'GroupBox1 ' Me.GroupBox1.Controls.Add(Me.PnLoad) @@ -751,7 +726,7 @@ Partial Class VehicleForm Me.GroupBox1.Controls.Add(Me.Label14) Me.GroupBox1.Location = New System.Drawing.Point(6, 6) Me.GroupBox1.Name = "GroupBox1" - Me.GroupBox1.Size = New System.Drawing.Size(278, 120) + Me.GroupBox1.Size = New System.Drawing.Size(278, 104) Me.GroupBox1.TabIndex = 0 Me.GroupBox1.TabStop = False Me.GroupBox1.Text = "Weight / Loading" @@ -762,11 +737,8 @@ Partial Class VehicleForm Me.PnLoad.Controls.Add(Me.Label31) Me.PnLoad.Controls.Add(Me.TbLoad) Me.PnLoad.Controls.Add(Me.TbMassExtra) - Me.PnLoad.Controls.Add(Me.TbLoadingMax) Me.PnLoad.Controls.Add(Me.Label50) Me.PnLoad.Controls.Add(Me.Label46) - Me.PnLoad.Controls.Add(Me.Label22) - Me.PnLoad.Controls.Add(Me.Label11) Me.PnLoad.Location = New System.Drawing.Point(6, 43) Me.PnLoad.Name = "PnLoad" Me.PnLoad.Size = New System.Drawing.Size(256, 75) @@ -1048,7 +1020,7 @@ Partial Class VehicleForm Me.TabControl1.Location = New System.Drawing.Point(6, 173) Me.TabControl1.Name = "TabControl1" Me.TabControl1.SelectedIndex = 0 - Me.TabControl1.Size = New System.Drawing.Size(587, 376) + Me.TabControl1.Size = New System.Drawing.Size(587, 355) Me.TabControl1.TabIndex = 40 ' 'TabPage1 @@ -1062,11 +1034,57 @@ Partial Class VehicleForm Me.TabPage1.Location = New System.Drawing.Point(4, 22) Me.TabPage1.Name = "TabPage1" Me.TabPage1.Padding = New System.Windows.Forms.Padding(3) - Me.TabPage1.Size = New System.Drawing.Size(579, 350) + Me.TabPage1.Size = New System.Drawing.Size(579, 329) Me.TabPage1.TabIndex = 0 Me.TabPage1.Text = "General" Me.TabPage1.UseVisualStyleBackColor = True ' + 'GroupBox4 + ' + Me.GroupBox4.Controls.Add(Me.Panel1) + Me.GroupBox4.Location = New System.Drawing.Point(6, 116) + Me.GroupBox4.Name = "GroupBox4" + Me.GroupBox4.Size = New System.Drawing.Size(278, 50) + Me.GroupBox4.TabIndex = 2 + Me.GroupBox4.TabStop = False + Me.GroupBox4.Text = "Vehicle Idling Speed" + ' + 'Panel1 + ' + Me.Panel1.Controls.Add(Me.tbVehIdlingSpeed) + Me.Panel1.Controls.Add(Me.Label18) + Me.Panel1.Controls.Add(Me.Label19) + Me.Panel1.Dock = System.Windows.Forms.DockStyle.Fill + Me.Panel1.Location = New System.Drawing.Point(3, 16) + Me.Panel1.Name = "Panel1" + Me.Panel1.Size = New System.Drawing.Size(272, 31) + Me.Panel1.TabIndex = 0 + ' + 'tbVehIdlingSpeed + ' + Me.tbVehIdlingSpeed.Location = New System.Drawing.Point(169, 3) + Me.tbVehIdlingSpeed.Name = "tbVehIdlingSpeed" + Me.tbVehIdlingSpeed.Size = New System.Drawing.Size(57, 20) + Me.tbVehIdlingSpeed.TabIndex = 0 + ' + 'Label18 + ' + Me.Label18.AutoSize = True + Me.Label18.Location = New System.Drawing.Point(229, 6) + Me.Label18.Name = "Label18" + Me.Label18.Size = New System.Drawing.Size(30, 13) + Me.Label18.TabIndex = 24 + Me.Label18.Text = "[rpm]" + ' + 'Label19 + ' + Me.Label19.AutoSize = True + Me.Label19.Location = New System.Drawing.Point(69, 6) + Me.Label19.Name = "Label19" + Me.Label19.Size = New System.Drawing.Size(94, 13) + Me.Label19.TabIndex = 8 + Me.Label19.Text = "Engine Idle Speed" + ' 'TabPage2 ' Me.TabPage2.Controls.Add(Me.gbPTO) @@ -1147,64 +1165,13 @@ Partial Class VehicleForm Me.btAddMaxTorqueEntry.TabIndex = 4 Me.btAddMaxTorqueEntry.UseVisualStyleBackColor = True ' - 'ColumnHeader10 - ' - Me.ColumnHeader10.Text = "Axle Type" - Me.ColumnHeader10.Width = 130 - ' - 'GroupBox4 - ' - Me.GroupBox4.Controls.Add(Me.Panel1) - Me.GroupBox4.Location = New System.Drawing.Point(6, 129) - Me.GroupBox4.Name = "GroupBox4" - Me.GroupBox4.Size = New System.Drawing.Size(278, 50) - Me.GroupBox4.TabIndex = 2 - Me.GroupBox4.TabStop = False - Me.GroupBox4.Text = "Vehicle Idling Speed" - ' - 'Panel1 - ' - Me.Panel1.Controls.Add(Me.tbVehIdlingSpeed) - Me.Panel1.Controls.Add(Me.Label18) - Me.Panel1.Controls.Add(Me.Label19) - Me.Panel1.Dock = System.Windows.Forms.DockStyle.Fill - Me.Panel1.Location = New System.Drawing.Point(3, 16) - Me.Panel1.Name = "Panel1" - Me.Panel1.Size = New System.Drawing.Size(272, 31) - Me.Panel1.TabIndex = 0 - ' - 'tbVehIdlingSpeed - ' - Me.tbVehIdlingSpeed.Location = New System.Drawing.Point(169, 3) - Me.tbVehIdlingSpeed.Name = "tbVehIdlingSpeed" - Me.tbVehIdlingSpeed.Size = New System.Drawing.Size(57, 20) - Me.tbVehIdlingSpeed.TabIndex = 0 - ' - 'Label18 - ' - Me.Label18.AutoSize = True - Me.Label18.Location = New System.Drawing.Point(229, 6) - Me.Label18.Name = "Label18" - Me.Label18.Size = New System.Drawing.Size(30, 13) - Me.Label18.TabIndex = 24 - Me.Label18.Text = "[rpm]" - ' - 'Label19 - ' - Me.Label19.AutoSize = True - Me.Label19.Location = New System.Drawing.Point(69, 6) - Me.Label19.Name = "Label19" - Me.Label19.Size = New System.Drawing.Size(94, 13) - Me.Label19.TabIndex = 8 - Me.Label19.Text = "Engine Idle Speed" - ' 'VehicleForm ' Me.AcceptButton = Me.ButOK Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font Me.CancelButton = Me.ButCancel - Me.ClientSize = New System.Drawing.Size(599, 605) + Me.ClientSize = New System.Drawing.Size(599, 580) Me.Controls.Add(Me.TabControl1) Me.Controls.Add(Me.ButCancel) Me.Controls.Add(Me.ButOK) @@ -1257,12 +1224,12 @@ Partial Class VehicleForm CType(Me.PicVehicle, System.ComponentModel.ISupportInitialize).EndInit() Me.TabControl1.ResumeLayout(False) Me.TabPage1.ResumeLayout(False) - Me.TabPage2.ResumeLayout(False) - Me.TabPage3.ResumeLayout(False) - Me.TabPage3.PerformLayout() Me.GroupBox4.ResumeLayout(False) Me.Panel1.ResumeLayout(False) Me.Panel1.PerformLayout() + Me.TabPage2.ResumeLayout(False) + Me.TabPage3.ResumeLayout(False) + Me.TabPage3.PerformLayout() Me.ResumeLayout(False) Me.PerformLayout() @@ -1316,9 +1283,6 @@ Partial Class VehicleForm Friend WithEvents LbStatus As System.Windows.Forms.ToolStripStatusLabel Friend WithEvents CbAxleConfig As System.Windows.Forms.ComboBox Friend WithEvents TbHDVclass As System.Windows.Forms.TextBox - Friend WithEvents Label11 As System.Windows.Forms.Label - Friend WithEvents TbLoadingMax As System.Windows.Forms.TextBox - Friend WithEvents Label22 As System.Windows.Forms.Label Friend WithEvents GroupBox1 As System.Windows.Forms.GroupBox Friend WithEvents GrAirRes As System.Windows.Forms.GroupBox Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox diff --git a/VECTO/GUI/VehicleForm.vb b/VECTO/GUI/VehicleForm.vb index 876aa8de62b9ffa06d15b55480d32b6f4dcf9259..e850b7f9e247f67511ef903eab97bf208b0e319c 100644 --- a/VECTO/GUI/VehicleForm.vb +++ b/VECTO/GUI/VehicleForm.vb @@ -59,7 +59,6 @@ Public Class VehicleForm 'Initialise form Private Sub VehicleFormLoad(sender As Object, e As EventArgs) Handles MyBase.Load - TbLoadingMax.Text = "-" PnLoad.Enabled = Not Cfg.DeclMode ButAxlAdd.Enabled = Not Cfg.DeclMode ButAxlRem.Enabled = Not Cfg.DeclMode @@ -533,9 +532,7 @@ Public Class VehicleForm Case CrossWindCorrectionMode.SpeedDependentCorrectionFactor bEnabled = True - LbCdMode.Text = "Input file: Vehicle Speed [km/h], Cd Scaling Factor [-]" _ - 'TODO: MQ 20160901: check if scaling factor or absolue value! - + LbCdMode.Text = "Input file: Vehicle Speed [km/h], Cd Scaling Factor [-]" Case Else ' tCdMode.ConstCd0, tCdMode.CdOfVdecl bEnabled = False LbCdMode.Text = "" @@ -633,7 +630,6 @@ Public Class VehicleForm End Function Private Sub TBmass_TextChanged(sender As Object, e As EventArgs) Handles TbMass.TextChanged - SetMaxLoad() Change() End Sub @@ -651,12 +647,10 @@ Public Class VehicleForm End Sub Private Sub TbMassTrailer_TextChanged(sender As Object, e As EventArgs) Handles TbMassExtra.TextChanged - SetMaxLoad() Change() End Sub Private Sub TbMassMax_TextChanged(sender As Object, e As EventArgs) Handles TbMassMass.TextChanged - SetMaxLoad() Change() SetHdVclass() DeclInit() @@ -671,17 +665,6 @@ Public Class VehicleForm #End Region - 'Update maximum load when truck/trailer mass was changed - Private Sub SetMaxLoad() - If Not Cfg.DeclMode Then - If IsNumeric(TbMass.Text) And IsNumeric(TbMassExtra.Text) And IsNumeric(TbMassMass.Text) Then - TbLoadingMax.Text = CStr(CSng(TbMassMass.Text) * 1000 - CSng(TbMass.Text) - CSng(TbMassExtra.Text)) - Else - TbLoadingMax.Text = "" - End If - End If - End Sub - #Region "Axle Configuration" Private Sub ButAxlAdd_Click(sender As Object, e As EventArgs) Handles ButAxlAdd.Click diff --git a/VECTO/GUI/XMLExportJobDialog.Designer.vb b/VECTO/GUI/XMLExportJobDialog.Designer.vb index 723ab9d9a6b0168ab28dd64f77332c8c06a38240..49e75db030f68deb02b84cd10affaa91fcd84085 100644 --- a/VECTO/GUI/XMLExportJobDialog.Designer.vb +++ b/VECTO/GUI/XMLExportJobDialog.Designer.vb @@ -28,7 +28,6 @@ Partial Class XMLExportJobDialog Me.btnExport = New System.Windows.Forms.Button() Me.cbSingleFile = New System.Windows.Forms.CheckBox() Me.label1 = New System.Windows.Forms.Label() - Me.btnBrowseOutputDir = New System.Windows.Forms.Button() Me.tbJobfile = New System.Windows.Forms.TextBox() Me.tbMode = New System.Windows.Forms.TextBox() Me.lblJobfile = New System.Windows.Forms.Label() @@ -36,6 +35,7 @@ Partial Class XMLExportJobDialog Me.tbDestination = New System.Windows.Forms.TextBox() Me.lblMode = New System.Windows.Forms.Label() Me.btnCancel = New System.Windows.Forms.Button() + Me.BtTCfileBrowse = New System.Windows.Forms.Button() Me.SuspendLayout() ' 'lbVendor @@ -49,14 +49,14 @@ Partial Class XMLExportJobDialog ' 'tbVendor ' - Me.tbVendor.Location = New System.Drawing.Point(120, 94) + Me.tbVendor.Location = New System.Drawing.Point(131, 94) Me.tbVendor.Name = "tbVendor" Me.tbVendor.Size = New System.Drawing.Size(231, 20) Me.tbVendor.TabIndex = 24 ' 'btnExport ' - Me.btnExport.Location = New System.Drawing.Point(276, 150) + Me.btnExport.Location = New System.Drawing.Point(224, 150) Me.btnExport.Name = "btnExport" Me.btnExport.Size = New System.Drawing.Size(75, 23) Me.btnExport.TabIndex = 23 @@ -81,18 +81,9 @@ Partial Class XMLExportJobDialog Me.label1.TabIndex = 21 Me.label1.Text = "Output single XML File:" ' - 'btnBrowseOutputDir - ' - Me.btnBrowseOutputDir.Location = New System.Drawing.Point(357, 65) - Me.btnBrowseOutputDir.Name = "btnBrowseOutputDir" - Me.btnBrowseOutputDir.Size = New System.Drawing.Size(75, 23) - Me.btnBrowseOutputDir.TabIndex = 20 - Me.btnBrowseOutputDir.Text = "Browse" - Me.btnBrowseOutputDir.UseVisualStyleBackColor = True - ' 'tbJobfile ' - Me.tbJobfile.Location = New System.Drawing.Point(120, 20) + Me.tbJobfile.Location = New System.Drawing.Point(131, 20) Me.tbJobfile.Name = "tbJobfile" Me.tbJobfile.ReadOnly = True Me.tbJobfile.Size = New System.Drawing.Size(231, 20) @@ -100,7 +91,7 @@ Partial Class XMLExportJobDialog ' 'tbMode ' - Me.tbMode.Location = New System.Drawing.Point(120, 43) + Me.tbMode.Location = New System.Drawing.Point(131, 43) Me.tbMode.Name = "tbMode" Me.tbMode.ReadOnly = True Me.tbMode.Size = New System.Drawing.Size(231, 20) @@ -126,7 +117,7 @@ Partial Class XMLExportJobDialog ' 'tbDestination ' - Me.tbDestination.Location = New System.Drawing.Point(120, 68) + Me.tbDestination.Location = New System.Drawing.Point(131, 68) Me.tbDestination.Name = "tbDestination" Me.tbDestination.Size = New System.Drawing.Size(231, 20) Me.tbDestination.TabIndex = 15 @@ -142,24 +133,34 @@ Partial Class XMLExportJobDialog ' 'btnCancel ' - Me.btnCancel.Location = New System.Drawing.Point(357, 150) + Me.btnCancel.Location = New System.Drawing.Point(305, 150) Me.btnCancel.Name = "btnCancel" Me.btnCancel.Size = New System.Drawing.Size(75, 23) Me.btnCancel.TabIndex = 13 Me.btnCancel.Text = "Cancel" Me.btnCancel.UseVisualStyleBackColor = True ' + 'BtTCfileBrowse + ' + Me.BtTCfileBrowse.Image = Global.TUGraz.VECTO.My.Resources.Resources.Open_icon + Me.BtTCfileBrowse.Location = New System.Drawing.Point(362, 66) + Me.BtTCfileBrowse.Name = "BtTCfileBrowse" + Me.BtTCfileBrowse.Size = New System.Drawing.Size(24, 24) + Me.BtTCfileBrowse.TabIndex = 26 + Me.BtTCfileBrowse.TabStop = False + Me.BtTCfileBrowse.UseVisualStyleBackColor = True + ' 'XMLExportJobDialog ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font - Me.ClientSize = New System.Drawing.Size(449, 185) + Me.ClientSize = New System.Drawing.Size(392, 185) + Me.Controls.Add(Me.BtTCfileBrowse) Me.Controls.Add(Me.lbVendor) Me.Controls.Add(Me.tbVendor) Me.Controls.Add(Me.btnExport) Me.Controls.Add(Me.cbSingleFile) Me.Controls.Add(Me.label1) - Me.Controls.Add(Me.btnBrowseOutputDir) Me.Controls.Add(Me.tbJobfile) Me.Controls.Add(Me.tbMode) Me.Controls.Add(Me.lblJobfile) @@ -179,7 +180,6 @@ Partial Class XMLExportJobDialog Private WithEvents btnExport As System.Windows.Forms.Button Private WithEvents cbSingleFile As System.Windows.Forms.CheckBox Private WithEvents label1 As System.Windows.Forms.Label - Private WithEvents btnBrowseOutputDir As System.Windows.Forms.Button Private WithEvents tbJobfile As System.Windows.Forms.TextBox Private WithEvents tbMode As System.Windows.Forms.TextBox Private WithEvents lblJobfile As System.Windows.Forms.Label @@ -187,4 +187,5 @@ Partial Class XMLExportJobDialog Private WithEvents tbDestination As System.Windows.Forms.TextBox Private WithEvents lblMode As System.Windows.Forms.Label Private WithEvents btnCancel As System.Windows.Forms.Button + Friend WithEvents BtTCfileBrowse As System.Windows.Forms.Button End Class diff --git a/VECTO/GUI/XMLExportJobDialog.vb b/VECTO/GUI/XMLExportJobDialog.vb index c5fb05335d1465647490cc68618c0680687e0cd2..8072b66ce3046925fc75ba1dc90a15e5f7e49727 100644 --- a/VECTO/GUI/XMLExportJobDialog.vb +++ b/VECTO/GUI/XMLExportJobDialog.vb @@ -1,11 +1,8 @@ Imports System.IO Imports System.Xml.Linq -Imports Microsoft.WindowsAPICodePack.Dialogs -Imports TUGraz.IVT.VectoXML.Writer Imports TUGraz.VectoCommon.Exceptions Imports TUGraz.VectoCommon.InputData Imports TUGraz.VectoCommon.Models -Imports TUGraz.VectoCore.Models.Declaration Imports TUGraz.VectoCore.OutputData.XML Public Class XMLExportJobDialog @@ -37,12 +34,13 @@ Public Class XMLExportJobDialog cbSingleFile.Enabled = allowSingleFile End Sub - Private Sub btnBrowseOutputDir_Click(sender As Object, e As EventArgs) Handles btnBrowseOutputDir.Click - Dim dialog As CommonOpenFileDialog = New CommonOpenFileDialog() - dialog.IsFolderPicker = True - If (dialog.ShowDialog() = CommonFileDialogResult.Ok) Then - tbDestination.Text = Path.GetFullPath(dialog.FileName) + Private Sub btnBrowseOutputDir_Click(sender As Object, e As EventArgs) Handles BtTCfileBrowse.Click + If Not FolderFileBrowser.OpenDialog("") Then + Exit Sub End If + + Dim filePath As String = FolderFileBrowser.Files(0) + tbDestination.Text = Path.GetFullPath(filePath) End Sub Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click diff --git a/VECTO/GUI/XMLImportJobDialog.vb b/VECTO/GUI/XMLImportJobDialog.vb index 50c7dded4da162cf135f7d6d160f9278169b562d..d462a579bde57f6623279b9fab1c509caee61582 100644 --- a/VECTO/GUI/XMLImportJobDialog.vb +++ b/VECTO/GUI/XMLImportJobDialog.vb @@ -1,5 +1,4 @@ Imports System.IO -Imports Microsoft.WindowsAPICodePack.Dialogs Public Class XMLImportJobDialog Private Sub btnBrowseJob_Click(sender As Object, e As EventArgs) Handles btnBrowseJob.Click @@ -10,11 +9,12 @@ Public Class XMLImportJobDialog End Sub Private Sub btnBrowseOutput_Click(sender As Object, e As EventArgs) Handles btnBrowseOutput.Click - Dim dialog As CommonOpenFileDialog = New CommonOpenFileDialog() - dialog.IsFolderPicker = True - If (dialog.ShowDialog() = CommonFileDialogResult.Ok) Then - tbDestination.Text = Path.GetFullPath(dialog.FileName) + If Not FolderFileBrowser.OpenDialog("") Then + Exit Sub End If + + Dim filePath As String = FolderFileBrowser.Files(0) + tbDestination.Text = Path.GetFullPath(filePath) End Sub Private Sub btnClose_Click(sender As Object, e As EventArgs) Handles btnClose.Click diff --git a/VECTO/Input Files/Engine.vb b/VECTO/Input Files/Engine.vb index cc105e3beecde03d7813b6ab9ef4e98196c94138..0fe8dece66939dcfd284f5ab224f354c3a96456d 100644 --- a/VECTO/Input Files/Engine.vb +++ b/VECTO/Input Files/Engine.vb @@ -290,7 +290,8 @@ Public Class Engine Public ReadOnly Property Manufacturer As String Implements IComponentInputData.Manufacturer Get - Return "N.A." ' TODO: MQ 20160919 + ' Just for the interface. Value is not available in GUI yet. + Return "N.A." End Get End Property @@ -308,6 +309,7 @@ Public Class Engine Public ReadOnly Property CertificationNumber As String Implements IComponentInputData.CertificationNumber Get + ' Just for the interface. Value is not available in GUI yet. Return "N.A." End Get End Property diff --git a/VECTO/Input Files/Gearbox.vb b/VECTO/Input Files/Gearbox.vb index 4849eba590ffb2b27050f5aafbbf51b1a7165500..e2b8f1ba39c5d71867055e137be4d48cd6049ad7 100644 --- a/VECTO/Input Files/Gearbox.vb +++ b/VECTO/Input Files/Gearbox.vb @@ -22,6 +22,7 @@ Imports TUGraz.VectoCore.InputData.FileIO.JSON Imports TUGraz.VectoCore.InputData.Impl Imports TUGraz.VectoCore.InputData.Reader Imports TUGraz.VectoCore.InputData.Reader.DataObjectAdapter +Imports TUGraz.VectoCore.Models.Declaration Imports TUGraz.VectoCore.Models.SimulationComponent.Data Imports TUGraz.VectoCore.Models.SimulationComponent.Data.Engine Imports TUGraz.VectoCore.Utils @@ -204,7 +205,13 @@ Public Class Gearbox IEngineeringInputDataProvider) 'Dim vehicle As IVehicleEngineeringInputData = inputData.VehicleInputData Dim engine As CombustionEngineData + Dim vehiclecategory As VehicleCategory Dim rdyn As Meter = 0.5.SI(Of Meter)() + Try + vehiclecategory = inputData.VehicleInputData.VehicleCategory + Catch ex As Exception + vehiclecategory = vehiclecategory.RigidTruck + End Try If mode = ExecutionMode.Declaration Then Dim doa As DeclarationDataAdapter = New DeclarationDataAdapter() @@ -214,9 +221,9 @@ Public Class Gearbox Catch engine = GetDefaultEngine(gearbox.Gears) End Try - + axlegearData = doa.CreateAxleGearData(gearbox, False) - gearboxData = doa.CreateGearboxData(gearbox, engine, axlegearData.AxleGear.Ratio, rdyn, False) + gearboxData = doa.CreateGearboxData(gearbox, engine, axlegearData.AxleGear.Ratio, rdyn, vehiclecategory, False) Else Dim doa As EngineeringDataAdapter = New EngineeringDataAdapter() Try @@ -226,7 +233,7 @@ Public Class Gearbox End Try axlegearData = doa.CreateAxleGearData(gearbox, True) - gearboxData = doa.CreateGearboxData(gearbox, engine, axlegearData.AxleGear.Ratio, rdyn, True) + gearboxData = doa.CreateGearboxData(gearbox, engine, axlegearData.AxleGear.Ratio, rdyn, vehiclecategory, True) End If Dim result As IList(Of ValidationResult) = @@ -299,7 +306,8 @@ Public Class Gearbox Public ReadOnly Property Manufacturer As String Implements IComponentInputData.Manufacturer Get - Return "N.A." ' Todo MQ 20160915 + ' Just for the interface. Value is not available in GUI yet. + Return "N.A." End Get End Property @@ -318,6 +326,7 @@ Public Class Gearbox Public ReadOnly Property CertificationNumber As String Implements IComponentInputData.CertificationNumber Get + ' Just for the interface. Value is not available in GUI yet. Return "N.A." End Get End Property diff --git a/VECTO/Input Files/Vehicle.vb b/VECTO/Input Files/Vehicle.vb index 980d3f7f42c030a7458be5a164d9edfc46f1d97a..cf4a0695ef2fe9b00a4f04d00f08bdee49387ab1 100644 --- a/VECTO/Input Files/Vehicle.vb +++ b/VECTO/Input Files/Vehicle.vb @@ -265,13 +265,15 @@ Public Class Vehicle Public ReadOnly Property Manufacturer As String Implements IComponentInputData.Manufacturer Get - Return "N.A." ' TODO: MQ 20160908 + ' Just for the interface. Value is not available in GUI yet. + Return "N.A." End Get End Property Public ReadOnly Property Model As String Implements IComponentInputData.Model Get - Return "N.A." ' Todo: MQ 20160908 + ' Just for the interface. Value is not available in GUI yet. + Return "N.A." End Get End Property @@ -290,7 +292,8 @@ Public Class Vehicle Public ReadOnly Property CertificationNumber As String Implements IComponentInputData.CertificationNumber Get - Return "N.A." 'ToDo + ' Just for the interface. Value is not available in GUI yet. + Return "N.A." End Get End Property diff --git a/VECTO/VECTO.vbproj b/VECTO/VECTO.vbproj index 45117444d503eaa2e50ec337195b3d77a0a2dab7..3f965fcd2db740151a699b4e80e0e52dc769bfad 100644 --- a/VECTO/VECTO.vbproj +++ b/VECTO/VECTO.vbproj @@ -132,14 +132,6 @@ </PropertyGroup> <ItemGroup> <Reference Include="Microsoft.Build.Framework" /> - <Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Microsoft.WindowsAPICodePack.Core.1.1.0\lib\Microsoft.WindowsAPICodePack.dll</HintPath> - </Reference> - <Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Microsoft.WindowsAPICodePack.Shell.1.1.0\lib\Microsoft.WindowsAPICodePack.Shell.dll</HintPath> - </Reference> <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath> diff --git a/VECTO/packages.config b/VECTO/packages.config index 47375c31f95c9d83c04f58d7834b9488b6bb45b7..2f28545ebadb0a1ddd6f4d99a5a49309b01e8daf 100644 --- a/VECTO/packages.config +++ b/VECTO/packages.config @@ -1,7 +1,5 @@ -<?xml version="1.0" encoding="utf-8"?> -<packages> - <package id="Microsoft.WindowsAPICodePack.Core" version="1.1.0" targetFramework="net45" /> - <package id="Microsoft.WindowsAPICodePack.Shell" version="1.1.0" targetFramework="net45" /> - <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net45" /> - <package id="NLog" version="4.2.3" targetFramework="net45" /> +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net45" /> + <package id="NLog" version="4.2.3" targetFramework="net45" /> </packages> \ No newline at end of file diff --git a/VECTOAux/VectoAuxiliaries/AdvancedAuxiliaries.vb b/VECTOAux/VectoAuxiliaries/AdvancedAuxiliaries.vb index 47d9a7596d401e65d163ec184bdabc5fc9a765f1..9cd035d9f5bfa51cc7c6cf9f02303112f43f2aff 100644 --- a/VECTOAux/VectoAuxiliaries/AdvancedAuxiliaries.vb +++ b/VECTOAux/VectoAuxiliaries/AdvancedAuxiliaries.vb @@ -474,62 +474,4 @@ Public Class AdvancedAuxiliaries Return M9.TotalCycleFuelConsumptionCompressorOnContinuously End Get End Property - - - 'TODO:REMOVE WHEN TESTING IS COMPLETE - 'PURE DIAGNOSTICS SHOULD ONLY BE USED IN MOD FOR ENGINEERING TESTS - - Public ReadOnly Property AA_D_M12_INTERP1 As Kilogram Implements IAdvancedAuxiliaries.AA_D_M12_INTERP1 - Get - Return M12.INTRP1() - End Get - End Property - - Public ReadOnly Property AA_D_M12_INTERP2 As Kilogram Implements IAdvancedAuxiliaries.AA_D_M12_INTERP2 - Get - Return M12.INTRP2() - End Get - End Property - - Public ReadOnly Property AA_D_M12_P1X As Joule Implements IAdvancedAuxiliaries.AA_D_M12_P1X - Get - Return M12.P1X() - End Get - End Property - - Public ReadOnly Property AA_D_M12_P1Y As Kilogram Implements IAdvancedAuxiliaries.AA_D_M12_P1Y - Get - Return M12.P1Y() - End Get - End Property - - Public ReadOnly Property AA_D_M12_P2X As Joule Implements IAdvancedAuxiliaries.AA_D_M12_P2X - Get - Return M12.P2X() - End Get - End Property - - Public ReadOnly Property AA_D_M12_P2Y As Kilogram Implements IAdvancedAuxiliaries.AA_D_M12_P2Y - Get - Return M12.P2Y() - End Get - End Property - - Public ReadOnly Property AA_D_M12_P3X As Joule Implements IAdvancedAuxiliaries.AA_D_M12_P3X - Get - Return M12.P3X() - End Get - End Property - - Public ReadOnly Property AA_D_M12_P3Y As Kilogram Implements IAdvancedAuxiliaries.AA_D_M12_P3Y - Get - Return M12.P3Y() - End Get - End Property - - Public ReadOnly Property AA_D_M12_XTAIN As Joule Implements IAdvancedAuxiliaries.AA_D_M12_XTAIN - Get - Return M12.XTAIN() - End Get - End Property End Class diff --git a/VECTOAux/VectoAuxiliaries/DownstreamModules/cMAP.vb b/VECTOAux/VectoAuxiliaries/DownstreamModules/cMAP.vb index b32e65b86b56326e8187d65922a56f3c90787e2d..7b8c13d27d42bff352cbea31fec97461f7564548 100644 --- a/VECTOAux/VectoAuxiliaries/DownstreamModules/cMAP.vb +++ b/VECTOAux/VectoAuxiliaries/DownstreamModules/cMAP.vb @@ -28,7 +28,7 @@ Public Class cMAP lFC = Nothing LTq = Nothing LnU = Nothing - iMapDim = -1 + iMapDim = - 1 FuelMap = New cDelaunayMap End Sub @@ -46,7 +46,6 @@ Public Class cMAP 'Stop if there's no file If sFilePath = "" OrElse Not IO.File.Exists(sFilePath) Then - 'If ShowMsg Then WorkerMsg(tMsgID.Err, "Map file not found! (" & sFilePath & ")", MsgSrc) Return False End If @@ -54,7 +53,6 @@ Public Class cMAP file = New cFile_V3 If Not file.OpenRead(sFilePath) Then file = Nothing - 'TODO:WORKERMESSAGE If ShowMsg Then WorkerMsg(tMsgID.Err, "Failed to open file (" & sFilePath & ") !", MsgSrc) Return False End If @@ -87,7 +85,7 @@ Public Class cMAP 'Check sign If CSng(line(2)) < 0 Then file.Close() - 'TODO:WORKERMESSAGEIf ShowMsg Then WorkerMsg(tMsgID.Err, "FC < 0 in map at " & nU & " [1/min], " & line(1) & " [Nm]", MsgSrc) + Return False End If @@ -97,7 +95,7 @@ Public Class cMAP Loop Catch ex As Exception - 'TODO:WORKERMESSAGE If ShowMsg Then WorkerMsg(tMsgID.Err, "Error during file read! Line number " & iMapDim + 1 & " (" & sFilePath & ")", MsgSrc, sFilePath) + GoTo lbEr End Try @@ -111,7 +109,7 @@ Public Class cMAP 'ERROR-label for clean Abort -lbEr: + lbEr: file.Close() file = Nothing @@ -140,8 +138,8 @@ lbEr: val = CType(FuelMap.Intpol(nU, Tq), Single) If FuelMap.ExtrapolError Then - 'TODO:WORKERMESSAGE WorkerMsg(tMsgID.Err, "Cannot extrapolate FC map! n= " & nU.ToString("0.0") & " [1/min], Me= " & Tq.ToString("0.0") & " [Nm]", "MAP/FC_Intp") - Return -10000 + + Return - 10000 Else Return val End If diff --git a/VectoCommon/AdvancedAuxiliaryInterfaces/IAdvancedAuxiliaries.vb b/VectoCommon/AdvancedAuxiliaryInterfaces/IAdvancedAuxiliaries.vb index a07e798bf89202a68d4507932c23f8cd52a2c102..233cdb1d58a98d13321a44e3939b103f17fb3927 100644 --- a/VectoCommon/AdvancedAuxiliaryInterfaces/IAdvancedAuxiliaries.vb +++ b/VectoCommon/AdvancedAuxiliaryInterfaces/IAdvancedAuxiliaries.vb @@ -22,18 +22,6 @@ Public Interface IAdvancedAuxiliaries ReadOnly Property AuxiliaryName As String ReadOnly Property AuxiliaryVersion As String - - 'Diagnostic Only - Remove when beta over. - ReadOnly Property AA_D_M12_P1X As Joule - ReadOnly Property AA_D_M12_P1Y As Kilogram - ReadOnly Property AA_D_M12_P2X As Joule - ReadOnly Property AA_D_M12_P2Y As Kilogram - ReadOnly Property AA_D_M12_P3X As Joule - ReadOnly Property AA_D_M12_P3Y As Kilogram - ReadOnly Property AA_D_M12_XTAIN As Joule - ReadOnly Property AA_D_M12_INTERP1 As Kilogram - ReadOnly Property AA_D_M12_INTERP2 As Kilogram - 'Additional Permenent Monitoring Signals - Required by engineering ReadOnly Property AA_NonSmartAlternatorsEfficiency As Double ReadOnly Property AA_SmartIdleCurrent_Amps As Ampere diff --git a/VectoCommon/VectoCommon/InputData/IInputDataProvider.cs b/VectoCommon/VectoCommon/InputData/IInputDataProvider.cs index 16cd627535b02621b2ef2a626409cdbcf3b095fa..836135d05d95e69cacff2f26dde7ec2169d3743a 100644 --- a/VectoCommon/VectoCommon/InputData/IInputDataProvider.cs +++ b/VectoCommon/VectoCommon/InputData/IInputDataProvider.cs @@ -29,65 +29,65 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Xml.Linq; - -namespace TUGraz.VectoCommon.InputData -{ - public interface IInputDataProvider {} - - public interface IDeclarationInputDataProvider : IInputDataProvider - { - IDeclarationJobInputData JobInputData(); - - IVehicleDeclarationInputData VehicleInputData { get; } - - IAirdragDeclarationInputData AirdragInputData { get; } - - IGearboxDeclarationInputData GearboxInputData { get; } - - ITorqueConverterDeclarationInputData TorqueConverterInputData { get; } - - IAxleGearInputData AxleGearInputData { get; } - - IAngledriveInputData AngledriveInputData { get; } - - IEngineDeclarationInputData EngineInputData { get; } - - IAuxiliariesDeclarationInputData AuxiliaryInputData(); - - IRetarderInputData RetarderInputData { get; } - - IDriverDeclarationInputData DriverInputData { get; } - - IPTOTransmissionInputData PTOTransmissionInputData { get; } - - XElement XMLHash { get; } - } - - public interface IEngineeringInputDataProvider : IInputDataProvider - { - IEngineeringJobInputData JobInputData(); - - IVehicleEngineeringInputData VehicleInputData { get; } - - IAirdragEngineeringInputData AirdragInputData { get; } - - IGearboxEngineeringInputData GearboxInputData { get; } - - ITorqueConverterEngineeringInputData TorqueConverterInputData { get; } - - IAxleGearInputData AxleGearInputData { get; } - - IAngledriveInputData AngledriveInputData { get; } - - IEngineEngineeringInputData EngineInputData { get; } - - IAuxiliariesEngineeringInputData AuxiliaryInputData(); - - IRetarderInputData RetarderInputData { get; } - - IDriverEngineeringInputData DriverInputData { get; } - - IPTOTransmissionInputData PTOTransmissionInputData { get; } - } +using System.Xml.Linq; + +namespace TUGraz.VectoCommon.InputData +{ + public interface IInputDataProvider {} + + public interface IDeclarationInputDataProvider : IInputDataProvider + { + IDeclarationJobInputData JobInputData(); + + IVehicleDeclarationInputData VehicleInputData { get; } + + IAirdragDeclarationInputData AirdragInputData { get; } + + IGearboxDeclarationInputData GearboxInputData { get; } + + ITorqueConverterDeclarationInputData TorqueConverterInputData { get; } + + IAxleGearInputData AxleGearInputData { get; } + + IAngledriveInputData AngledriveInputData { get; } + + IEngineDeclarationInputData EngineInputData { get; } + + IAuxiliariesDeclarationInputData AuxiliaryInputData(); + + IRetarderInputData RetarderInputData { get; } + + IDriverDeclarationInputData DriverInputData { get; } + + IPTOTransmissionInputData PTOTransmissionInputData { get; } + + XElement XMLHash { get; } + } + + public interface IEngineeringInputDataProvider : IInputDataProvider + { + IEngineeringJobInputData JobInputData(); + + IVehicleEngineeringInputData VehicleInputData { get; } + + IAirdragEngineeringInputData AirdragInputData { get; } + + IGearboxEngineeringInputData GearboxInputData { get; } + + ITorqueConverterEngineeringInputData TorqueConverterInputData { get; } + + IAxleGearInputData AxleGearInputData { get; } + + IAngledriveInputData AngledriveInputData { get; } + + IEngineEngineeringInputData EngineInputData { get; } + + IAuxiliariesEngineeringInputData AuxiliaryInputData(); + + IRetarderInputData RetarderInputData { get; } + + IDriverEngineeringInputData DriverInputData { get; } + + IPTOTransmissionInputData PTOTransmissionInputData { get; } + } } \ No newline at end of file diff --git a/VectoCommon/VectoCommon/Models/VehicleCategory.cs b/VectoCommon/VectoCommon/Models/VehicleCategory.cs index af6baf04d0637013b03aae01d733db3a9bf0817f..8c59130ffc0d0278926eca1996c539f866c14062 100644 --- a/VectoCommon/VectoCommon/Models/VehicleCategory.cs +++ b/VectoCommon/VectoCommon/Models/VehicleCategory.cs @@ -29,72 +29,87 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; - -namespace TUGraz.VectoCommon.Models -{ - public enum VehicleCategory - { - RigidTruck, - Tractor, - CityBus, - InterurbanBus, - Coach - } - - public static class VehicleCategoryHelper - { - public static string GetLabel(this VehicleCategory category) - { - switch (category) - { - case VehicleCategory.RigidTruck: - return "Rigid Truck"; - case VehicleCategory.Tractor: - return "Tractor"; - case VehicleCategory.CityBus: - return "City Bus"; - case VehicleCategory.InterurbanBus: - return "Interurban Bus"; - case VehicleCategory.Coach: - return "Coach"; - default: - return category.ToString(); - } - } - public static string GetCategoryName(this VehicleCategory category) - { - switch (category) { - case VehicleCategory.RigidTruck: - return "Rigid Truck"; - case VehicleCategory.Tractor: - return "Semitrailer Truck"; - case VehicleCategory.CityBus: - return "Citybus"; - case VehicleCategory.InterurbanBus: - return "Interurban Bus"; - case VehicleCategory.Coach: - return "Coach"; - default: - return category.ToString(); - } - } - - public static string ToXMLFormat(this VehicleCategory vehicleCategory) - { - switch (vehicleCategory) { - case VehicleCategory.Coach: - case VehicleCategory.Tractor: - return vehicleCategory.ToString(); - case VehicleCategory.CityBus: - return "City Bus"; - case VehicleCategory.InterurbanBus: - return "Interurban Bus"; - case VehicleCategory.RigidTruck: - return "Rigid Truck"; - default: - throw new ArgumentOutOfRangeException("vehicleCategory", vehicleCategory, null); - } - } - } +using System; + +namespace TUGraz.VectoCommon.Models +{ + public enum VehicleCategory + { + RigidTruck, + Tractor, + CityBus, + InterurbanBus, + Coach + } + + public static class VehicleCategoryHelper + { + public static string GetLabel(this VehicleCategory category) + { + switch (category) { + case VehicleCategory.RigidTruck: + return "Rigid Truck"; + case VehicleCategory.Tractor: + return "Tractor"; + case VehicleCategory.CityBus: + return "City Bus"; + case VehicleCategory.InterurbanBus: + return "Interurban Bus"; + case VehicleCategory.Coach: + return "Coach"; + default: + return category.ToString(); + } + } + + public static string GetCategoryName(this VehicleCategory category) + { + switch (category) { + case VehicleCategory.RigidTruck: + return "Rigid Truck"; + case VehicleCategory.Tractor: + return "Semitrailer Truck"; + case VehicleCategory.CityBus: + return "Citybus"; + case VehicleCategory.InterurbanBus: + return "Interurban Bus"; + case VehicleCategory.Coach: + return "Coach"; + default: + return category.ToString(); + } + } + + public static string ToXMLFormat(this VehicleCategory vehicleCategory) + { + switch (vehicleCategory) { + case VehicleCategory.Coach: + case VehicleCategory.Tractor: + return vehicleCategory.ToString(); + case VehicleCategory.CityBus: + return "City Bus"; + case VehicleCategory.InterurbanBus: + return "Interurban Bus"; + case VehicleCategory.RigidTruck: + return "Rigid Truck"; + default: + throw new ArgumentOutOfRangeException("vehicleCategory", vehicleCategory, null); + } + } + + public static bool IsTruck(this VehicleCategory category) + { + switch (category) { + case VehicleCategory.RigidTruck: + case VehicleCategory.Tractor: + return true; + case VehicleCategory.CityBus: + case VehicleCategory.InterurbanBus: + case VehicleCategory.Coach: + return false; + default: + throw new ArgumentOutOfRangeException("VehicleCategory", category, null); + } + } + } } \ No newline at end of file diff --git a/VectoCommon/VectoHashingTest/VectoHashTest.cs b/VectoCommon/VectoHashingTest/VectoHashTest.cs index 2a6c5c43ea742558568b64662e0cb0bc01664fb7..a38bbeacaa4f12c341bbeb90019ade3c44ff749a 100644 --- a/VectoCommon/VectoHashingTest/VectoHashTest.cs +++ b/VectoCommon/VectoHashingTest/VectoHashTest.cs @@ -29,430 +29,430 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.IO; -using System.Linq; -using System.Text; -using System.Xml; -using System.Xml.Linq; -using System.Xml.Schema; -using NUnit.Framework; -using TUGraz.VectoCore.Utils; -using TUGraz.VectoHashing; -using VectoHashingTest.Utils; -using Assert = NUnit.Framework.Assert; - -namespace VectoHashingTest -{ - [TestFixture] - public class VectoHashTest - { - public const string ReferenceXMLEngine = @"Testdata\XML\Reference\vecto_engine-sample.xml"; - public const string ReferenceXMLVehicle = @"Testdata\XML\Reference\vecto_vehicle-sample_FULL.xml"; - - [TestCase] - public void TestComponentsEngineFile() - { - var h = VectoHash.Load(ReferenceXMLEngine); - var components = h.GetContainigComponents().ToList(); - - Assert.AreEqual(1, components.Count); - Assert.AreEqual(VectoComponents.Engine, components[0]); - } - - [TestCase] - public void TestComponentsVehicleFile() - { - var h = VectoHash.Load(ReferenceXMLVehicle); - var components = h.GetContainigComponents().ToList(); - - Assert.AreEqual(10, components.Count); - } - - [TestCase(ReferenceXMLEngine, VectoComponents.Engine, BasicHasingTests.HashEngineXML)] - public void TestHashComputationSelected(string file, VectoComponents component, string expectedHash) - { - var h = VectoHash.Load(file); - var hash = h.ComputeHash(component); - - Assert.AreEqual(expectedHash, hash); - } - - [TestCase(ReferenceXMLVehicle, BasicHasingTests.HashVehicleXML), - TestCase(ReferenceXMLEngine, BasicHasingTests.HashEngineXML)] - public void TestHashComputation(string file, string expectedHash) - { - var h = VectoHash.Load(file); - var hash = h.ComputeHash(); - - Assert.AreEqual(expectedHash, hash); - } - - [TestCase(ReferenceXMLEngine)] - public void TestHashComputationInvalidComponent(string file) - { - var h = VectoHash.Load(file); - AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Gearbox), "Component Gearbox not found"); - } - - [TestCase(ReferenceXMLEngine)] - public void TestReadHashInvalidComponent(string file) - { - var h = VectoHash.Load(file); - AssertHelper.Exception<Exception>(() => h.ReadHash(VectoComponents.Gearbox), "Component Gearbox not found"); - } - - [TestCase(ReferenceXMLVehicle, VectoComponents.Engine, "e0c253b643f7f8f09b963aca4a264d06fbfa599f"), - TestCase(ReferenceXMLVehicle, VectoComponents.Gearbox, "d14189366134120e08fa3f2c6e3328dd13c08a23")] - public void TestReadHash(string file, VectoComponents component, string expectedHash) - { - var h = VectoHash.Load(file); - var existingHash = h.ReadHash(component); - - Assert.AreEqual(expectedHash, existingHash); - } - - [TestCase(ReferenceXMLVehicle, VectoComponents.Tyre, 0, "5074334bb2c090c5e258e9a664f5d19689a3f13d"), - TestCase(ReferenceXMLVehicle, VectoComponents.Tyre, 1, "6074334bb2c090c5e258e9a664f5d19689a3f13d")] - public void TestReadHashIdx(string file, VectoComponents component, int index, string expectedHash) - { - var h = VectoHash.Load(file); - var existingHash = h.ReadHash(component, index); - - Assert.AreEqual(expectedHash, existingHash); - } - - [TestCase] - public void TestReadTyres1Index() - { - var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle1.xml"; - var h = VectoHash.Load(file); - var expectedHash = new[] { - "5074334bb2c090c5e258e9a664f5d19689a3f13d", - "6074334bb2c090c5e258e9a664f5d19689a3f13d", - "6074334bb2c090c5e258e9a664f5d19689a3f13d" - }; - - for (int i = 0; i < expectedHash.Length; i++) { - var existingHash = h.ReadHash(VectoComponents.Tyre, i); - - Assert.AreEqual(expectedHash[i], existingHash); - } - } - - [TestCase] - public void TestReadTyres2Index() - { - var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle2.xml"; - var h = VectoHash.Load(file); - var expectedHash = new[] { - "5074334bb2c090c5e258e9a664f5d19689a3f13d", - "5074334bb2c090c5e258e9a664f5d19689a3f13d", - "6074334bb2c090c5e258e9a664f5d19689a3f13d" - }; - - for (int i = 0; i < expectedHash.Length; i++) { - var existingHash = h.ReadHash(VectoComponents.Tyre, i); - - Assert.AreEqual(expectedHash[i], existingHash); - } - - AssertHelper.Exception<Exception>(() => h.ReadHash(VectoComponents.Tyre, 3), - "index exceeds number of components found! index: 3, #components: 3"); - } - - [TestCase] - public void TestComputeTyres1Index() - { - var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle1.xml"; - var h = VectoHash.Load(file); - - var hash1 = h.ComputeHash(VectoComponents.Tyre, 1); - var hash2 = h.ComputeHash(VectoComponents.Tyre, 2); - - Assert.AreEqual(hash1, hash2); - - AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Tyre, 3), - "index exceeds number of components found! index: 3, #components: 3"); - } - - [TestCase] - public void TestComputeTyres2Index() - { - var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle2.xml"; - var h = VectoHash.Load(file); - - var hash1 = h.ComputeHash(VectoComponents.Tyre, 0); - var hash2 = h.ComputeHash(VectoComponents.Tyre, 1); - - Assert.AreEqual(hash1, hash2); - - AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Tyre, 3), - "index exceeds number of components found! index: 3, #components: 3"); - } - - [TestCase("vecto_vehicle-sample_FULL_Comments.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_vehicle-sample_FULL_Entry_Order.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_vehicle-sample_FULL_Newlines_Linux_LF.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_vehicle-sample_FULL_Newlines_Mac_CR.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_vehicle-sample_FULL_Newlines_Windows_CRLF.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_engine-sample Encoding ISO 8859-15.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding UTF-8 BOM.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding UTF-8.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding UTF-16 BE BOM.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding UTF-16 LE.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding windows-1292.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample_Whitespaces.xml", BasicHasingTests.HashEngineXML), - ] - public void TestHashComputationVariations(string file, string expectedHash) - { - var h = VectoHash.Load(@"Testdata\XML\Variations\" + file); - var hash = h.ComputeHash(); - - Assert.AreEqual(expectedHash, hash); - } - - - [TestCase(@"Testdata\XML\Validation\vecto_engine_valid.xml"), - TestCase(@"Testdata\XML\Validation\vecto_gearbox_valid.xml")] - public void TestValidation(string file) - { - var h = VectoHash.Load(file); - Assert.IsTrue(h.ValidateHash()); - } - - [TestCase(@"Testdata\XML\Validation\vecto_engine_invalid.xml"), - TestCase(@"Testdata\XML\Validation\vecto_gearbox_invalid.xml")] - public void TestValidationInvalid(string file) - { - var h = VectoHash.Load(file); - Assert.IsFalse(h.ValidateHash()); - } - - [TestCase(VectoComponents.Engine), - TestCase(VectoComponents.Gearbox), - ] - public void TestValidationComponentValid(VectoComponents component) - { - var file = @"Testdata\XML\Validation\vecto_vehicle_components_valid-engine_gbx.xml"; - var h = VectoHash.Load(file); - - Assert.IsTrue(h.ValidateHash(component)); - } - - [TestCase(VectoComponents.Engine), - TestCase(VectoComponents.Gearbox), - TestCase(VectoComponents.Axlegear), - TestCase(VectoComponents.Angledrive), - TestCase(VectoComponents.Retarder), - TestCase(VectoComponents.TorqueConverter), - TestCase(VectoComponents.Tyre), - TestCase(VectoComponents.Airdrag), - ] - public void TestValidationComponentInvalid(VectoComponents component) - { - var file = @"Testdata\XML\Validation\vecto_vehicle_components_invalid.xml"; - var h = VectoHash.Load(file); - - Assert.IsFalse(h.ValidateHash(component)); - } - - [TestCase(@"Testdata\XML\ToHash\vecto_engine-input.xml"), - TestCase(@"Testdata\XML\ToHash\vecto_engine_withid-input.xml"), - TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input.xml")] - public void TestAddHash(string file) - { - var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; - - var h = VectoHash.Load(file); - var r = h.AddHash(); - - var writer = new XmlTextWriter(destination, Encoding.UTF8); - r.WriteTo(writer); - writer.Flush(); - writer.Close(); - - var h2 = VectoHash.Load(destination); - Assert.IsTrue(h2.ValidateHash()); - } - - [TestCase(@"Testdata\XML\ToHash\vecto_engine_withhash-input.xml", "input data already contains a signature element"), - TestCase(@"Testdata\XML\ToHash\vecto_vehicle-sample.xml", "adding hash for Vehicle is not supported"), - TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input_nodata.xml", "'Data' element for component 'Gearbox' not found!"), - TestCase(@"Testdata\XML\ToHash\multiple_components.xml", "input must not contain multiple components!"), - ] - public void TestAddHashException(string file, string expectedExceptionMsg) - { - var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; - - var h = VectoHash.Load(file); - AssertHelper.Exception<Exception>(() => { var r = h.AddHash(); }, expectedExceptionMsg); - } - - [TestCase] - public void TestDuplicateSigElement() - { - var filename = @"Testdata\XML\Invalid\duplicate-sig.xml"; - var h = VectoHash.Load(filename); - - AssertHelper.Exception<Exception>(() => { var r = h.ReadHash(); }, "Multiple DigestValue elements found!"); - } - - - [TestCase()] - public void TestLoadFromStream() - { - var fs = new FileStream(BasicHasingTests.ReferenceXMLVehicle, FileMode.Open); - var h = VectoHash.Load(fs); - - var hash = h.ComputeHash(); - Assert.AreEqual(BasicHasingTests.HashVehicleXML, hash); - fs.Close(); - } - - [TestCase(WhitespaceHandling.All), - TestCase(WhitespaceHandling.None), - TestCase(WhitespaceHandling.Significant)] - public void TestLoadXmlDocument(WhitespaceHandling whitespace) - { - var xml = new XmlDocument(); - var reader = new XmlTextReader(BasicHasingTests.ReferenceXMLVehicle); - reader.WhitespaceHandling = whitespace; - xml.Load(reader); - var h = VectoHash.Load(xml); - - var hash = h.ComputeHash(); - Assert.AreEqual(BasicHasingTests.HashVehicleXML, hash); - } - - [TestCase(@"Testdata\XML\ToHash\vecto_engine-input.xml"), - TestCase(@"Testdata\XML\ToHash\vecto_engine_withid-input.xml"), - TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input.xml")] - public void TestHashedComponentIsValid(string file) - { - var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; - - var h = VectoHash.Load(file); - var r = h.AddHash(); - - var writer = new XmlTextWriter(destination, Encoding.UTF8); - r.WriteTo(writer); - writer.Flush(); - writer.Close(); - - var h2 = VectoHash.Load(destination); - Assert.IsTrue(h2.ValidateHash()); - - // re-load generated XML and perform XSD validation - var settings = new XmlReaderSettings() { - ValidationType = ValidationType.Schema, - ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema | - //XmlSchemaValidationFlags.ProcessSchemaLocation | - XmlSchemaValidationFlags.ReportValidationWarnings - }; - settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack); - settings.Schemas.Add(GetXMLSchema(false)); - var xmlValidator = XmlReader.Create(destination, settings); - var xmlDoc = XDocument.Load(xmlValidator); - } - - - [TestCase("vecto_vehicle-namespace_prefix.xml", BasicHasingTests.HashVehicleXML)] - public void TestNamespacePrefixVariations(string file, string expectedHash) - { - var h = VectoHash.Load(@"Testdata\XML\Variations\" + file); - var hash = h.ComputeHash(); - - Assert.AreEqual(expectedHash, hash); - } - - [TestCase()] - public void TestInvalidXMLAsFile() - { - var file = @"Testdata\XML\Invalid\invalid-comp.xml"; - - AssertHelper.Exception<Exception>(() => VectoHash.Load(file), "failed to read XML document"); - } - - [TestCase()] - public void TestInvalidXMLAsStream() - { - var file = @"Testdata\XML\Invalid\invalid-comp.xml"; - var stream = File.Open(file, FileMode.Open); - AssertHelper.Exception<Exception>(() => VectoHash.Load(stream), "failed to read XML document"); - } - - [TestCase()] - public void TestComputeHashNoComponentInXML() - { - var xml = @"<VectoInputDeclaration/>"; - var stream = new MemoryStream(); - var writer = new StreamWriter(stream); - writer.Write(xml); - writer.Flush(); - stream.Seek(0, SeekOrigin.Begin); - - var h = VectoHash.Load(stream); - AssertHelper.Exception<Exception>(() => h.ComputeHash(), "No component found"); - } - - [TestCase()] - public void TestReadHashNoComponentInXML() - { - var xml = @"<VectoInputDeclaration/>"; - var stream = new MemoryStream(); - var writer = new StreamWriter(stream); - writer.Write(xml); - writer.Flush(); - stream.Seek(0, SeekOrigin.Begin); - - var h = VectoHash.Load(stream); - AssertHelper.Exception<Exception>(() => h.ReadHash(), "No component found"); - } - - [TestCase(VectoComponents.Engine, "ENG-"), - TestCase(VectoComponents.Gearbox, "GBX-"), - TestCase(VectoComponents.Axlegear, "AXL-"), - TestCase(VectoComponents.Retarder, "RET-"), - TestCase(VectoComponents.TorqueConverter, "TC-"), - TestCase(VectoComponents.Angledrive, "ANGL-"), - TestCase(VectoComponents.Airdrag, "AD-"), - TestCase(VectoComponents.Tyre, "TYRE-"), - ] - public void TestIdPrefix(VectoComponents component, string expectedPrefix) - { - Assert.AreEqual(expectedPrefix, component.HashIdPrefix()); - } - - [TestCase()] - public void TestInvalidComponentXMLName() - { - AssertHelper.Exception<ArgumentOutOfRangeException>(() => ((VectoComponents)9999).XMLElementName()); - } - - [TestCase()] - public void TestInvalidComponentPrefix() - { - AssertHelper.Exception<ArgumentOutOfRangeException>(() => ((VectoComponents)9999).HashIdPrefix()); - } - - private static XmlSchemaSet GetXMLSchema(bool job) - { - var resource = RessourceHelper.LoadResourceAsStream(RessourceHelper.ResourceType.XMLSchema, - job ? "VectoInput.xsd" : "VectoComponent.xsd"); - var xset = new XmlSchemaSet() { XmlResolver = new XmlResourceResolver() }; - var reader = XmlReader.Create(resource, new XmlReaderSettings(), "schema://"); - xset.Add(XmlSchema.Read(reader, null)); - xset.Compile(); - return xset; - } - - private static void ValidationCallBack(object sender, ValidationEventArgs args) - { - if (args.Severity == XmlSeverityType.Error) { - throw new Exception(string.Format("Validation error: {0}" + Environment.NewLine + - "Line: {1}", args.Message, args.Exception.LineNumber)); - } - } - } +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; +using System.Xml.Linq; +using System.Xml.Schema; +using NUnit.Framework; +using TUGraz.VectoCore.Utils; +using TUGraz.VectoHashing; +using VectoHashingTest.Utils; +using Assert = NUnit.Framework.Assert; + +namespace VectoHashingTest +{ + [TestFixture] + public class VectoHashTest + { + public const string ReferenceXMLEngine = @"Testdata\XML\Reference\vecto_engine-sample.xml"; + public const string ReferenceXMLVehicle = @"Testdata\XML\Reference\vecto_vehicle-sample_FULL.xml"; + + [TestCase] + public void TestComponentsEngineFile() + { + var h = VectoHash.Load(ReferenceXMLEngine); + var components = h.GetContainigComponents().ToList(); + + Assert.AreEqual(1, components.Count); + Assert.AreEqual(VectoComponents.Engine, components[0]); + } + + [TestCase] + public void TestComponentsVehicleFile() + { + var h = VectoHash.Load(ReferenceXMLVehicle); + var components = h.GetContainigComponents().ToList(); + + Assert.AreEqual(10, components.Count); + } + + [TestCase(ReferenceXMLEngine, VectoComponents.Engine, BasicHasingTests.HashEngineXML)] + public void TestHashComputationSelected(string file, VectoComponents component, string expectedHash) + { + var h = VectoHash.Load(file); + var hash = h.ComputeHash(component); + + Assert.AreEqual(expectedHash, hash); + } + + [TestCase(ReferenceXMLVehicle, BasicHasingTests.HashVehicleXML), + TestCase(ReferenceXMLEngine, BasicHasingTests.HashEngineXML)] + public void TestHashComputation(string file, string expectedHash) + { + var h = VectoHash.Load(file); + var hash = h.ComputeHash(); + + Assert.AreEqual(expectedHash, hash); + } + + [TestCase(ReferenceXMLEngine)] + public void TestHashComputationInvalidComponent(string file) + { + var h = VectoHash.Load(file); + AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Gearbox), "Component Gearbox not found"); + } + + [TestCase(ReferenceXMLEngine)] + public void TestReadHashInvalidComponent(string file) + { + var h = VectoHash.Load(file); + AssertHelper.Exception<Exception>(() => h.ReadHash(VectoComponents.Gearbox), "Component Gearbox not found"); + } + + [TestCase(ReferenceXMLVehicle, VectoComponents.Engine, "e0c253b643f7f8f09b963aca4a264d06fbfa599f"), + TestCase(ReferenceXMLVehicle, VectoComponents.Gearbox, "d14189366134120e08fa3f2c6e3328dd13c08a23")] + public void TestReadHash(string file, VectoComponents component, string expectedHash) + { + var h = VectoHash.Load(file); + var existingHash = h.ReadHash(component); + + Assert.AreEqual(expectedHash, existingHash); + } + + [TestCase(ReferenceXMLVehicle, VectoComponents.Tyre, 0, "5074334bb2c090c5e258e9a664f5d19689a3f13d"), + TestCase(ReferenceXMLVehicle, VectoComponents.Tyre, 1, "6074334bb2c090c5e258e9a664f5d19689a3f13d")] + public void TestReadHashIdx(string file, VectoComponents component, int index, string expectedHash) + { + var h = VectoHash.Load(file); + var existingHash = h.ReadHash(component, index); + + Assert.AreEqual(expectedHash, existingHash); + } + + [TestCase] + public void TestReadTyres1Index() + { + var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle1.xml"; + var h = VectoHash.Load(file); + var expectedHash = new[] { + "5074334bb2c090c5e258e9a664f5d19689a3f13d", + "6074334bb2c090c5e258e9a664f5d19689a3f13d", + "6074334bb2c090c5e258e9a664f5d19689a3f13d" + }; + + for (int i = 0; i < expectedHash.Length; i++) { + var existingHash = h.ReadHash(VectoComponents.Tyre, i); + + Assert.AreEqual(expectedHash[i], existingHash); + } + } + + [TestCase] + public void TestReadTyres2Index() + { + var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle2.xml"; + var h = VectoHash.Load(file); + var expectedHash = new[] { + "5074334bb2c090c5e258e9a664f5d19689a3f13d", + "5074334bb2c090c5e258e9a664f5d19689a3f13d", + "6074334bb2c090c5e258e9a664f5d19689a3f13d" + }; + + for (int i = 0; i < expectedHash.Length; i++) { + var existingHash = h.ReadHash(VectoComponents.Tyre, i); + + Assert.AreEqual(expectedHash[i], existingHash); + } + + AssertHelper.Exception<Exception>(() => h.ReadHash(VectoComponents.Tyre, 3), + "index exceeds number of components found! index: 3, #components: 3"); + } + + [TestCase] + public void TestComputeTyres1Index() + { + var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle1.xml"; + var h = VectoHash.Load(file); + + var hash1 = h.ComputeHash(VectoComponents.Tyre, 1); + var hash2 = h.ComputeHash(VectoComponents.Tyre, 2); + + Assert.AreEqual(hash1, hash2); + + AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Tyre, 3), + "index exceeds number of components found! index: 3, #components: 3"); + } + + [TestCase] + public void TestComputeTyres2Index() + { + var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle2.xml"; + var h = VectoHash.Load(file); + + var hash1 = h.ComputeHash(VectoComponents.Tyre, 0); + var hash2 = h.ComputeHash(VectoComponents.Tyre, 1); + + Assert.AreEqual(hash1, hash2); + + AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Tyre, 3), + "index exceeds number of components found! index: 3, #components: 3"); + } + + [TestCase("vecto_vehicle-sample_FULL_Comments.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_vehicle-sample_FULL_Entry_Order.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_vehicle-sample_FULL_Newlines_Linux_LF.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_vehicle-sample_FULL_Newlines_Mac_CR.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_vehicle-sample_FULL_Newlines_Windows_CRLF.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_engine-sample Encoding ISO 8859-15.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding UTF-8 BOM.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding UTF-8.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding UTF-16 BE BOM.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding UTF-16 LE.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding windows-1292.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample_Whitespaces.xml", BasicHasingTests.HashEngineXML), + ] + public void TestHashComputationVariations(string file, string expectedHash) + { + var h = VectoHash.Load(@"Testdata\XML\Variations\" + file); + var hash = h.ComputeHash(); + + Assert.AreEqual(expectedHash, hash); + } + + + [TestCase(@"Testdata\XML\Validation\vecto_engine_valid.xml"), + TestCase(@"Testdata\XML\Validation\vecto_gearbox_valid.xml")] + public void TestValidation(string file) + { + var h = VectoHash.Load(file); + Assert.IsTrue(h.ValidateHash()); + } + + [TestCase(@"Testdata\XML\Validation\vecto_engine_invalid.xml"), + TestCase(@"Testdata\XML\Validation\vecto_gearbox_invalid.xml")] + public void TestValidationInvalid(string file) + { + var h = VectoHash.Load(file); + Assert.IsFalse(h.ValidateHash()); + } + + [TestCase(VectoComponents.Engine), + TestCase(VectoComponents.Gearbox), + ] + public void TestValidationComponentValid(VectoComponents component) + { + var file = @"Testdata\XML\Validation\vecto_vehicle_components_valid-engine_gbx.xml"; + var h = VectoHash.Load(file); + + Assert.IsTrue(h.ValidateHash(component)); + } + + [TestCase(VectoComponents.Engine), + TestCase(VectoComponents.Gearbox), + TestCase(VectoComponents.Axlegear), + TestCase(VectoComponents.Angledrive), + TestCase(VectoComponents.Retarder), + TestCase(VectoComponents.TorqueConverter), + TestCase(VectoComponents.Tyre), + TestCase(VectoComponents.Airdrag), + ] + public void TestValidationComponentInvalid(VectoComponents component) + { + var file = @"Testdata\XML\Validation\vecto_vehicle_components_invalid.xml"; + var h = VectoHash.Load(file); + + Assert.IsFalse(h.ValidateHash(component)); + } + + [TestCase(@"Testdata\XML\ToHash\vecto_engine-input.xml"), + TestCase(@"Testdata\XML\ToHash\vecto_engine_withid-input.xml"), + TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input.xml")] + public void TestAddHash(string file) + { + var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; + + var h = VectoHash.Load(file); + var r = h.AddHash(); + + var writer = new XmlTextWriter(destination, Encoding.UTF8); + r.WriteTo(writer); + writer.Flush(); + writer.Close(); + + var h2 = VectoHash.Load(destination); + Assert.IsTrue(h2.ValidateHash()); + } + + [TestCase(@"Testdata\XML\ToHash\vecto_engine_withhash-input.xml", "input data already contains a signature element"), + TestCase(@"Testdata\XML\ToHash\vecto_vehicle-sample.xml", "adding hash for Vehicle is not supported"), + TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input_nodata.xml", "'Data' element for component 'Gearbox' not found!"), + TestCase(@"Testdata\XML\ToHash\multiple_components.xml", "input must not contain multiple components!"), + ] + public void TestAddHashException(string file, string expectedExceptionMsg) + { + var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; + + var h = VectoHash.Load(file); + AssertHelper.Exception<Exception>(() => { var r = h.AddHash(); }, expectedExceptionMsg); + } + + [TestCase] + public void TestDuplicateSigElement() + { + var filename = @"Testdata\XML\Invalid\duplicate-sig.xml"; + var h = VectoHash.Load(filename); + + AssertHelper.Exception<Exception>(() => { var r = h.ReadHash(); }, "Multiple DigestValue elements found!"); + } + + + [TestCase()] + public void TestLoadFromStream() + { + var fs = new FileStream(BasicHasingTests.ReferenceXMLVehicle, FileMode.Open); + var h = VectoHash.Load(fs); + + var hash = h.ComputeHash(); + Assert.AreEqual(BasicHasingTests.HashVehicleXML, hash); + fs.Close(); + } + + [TestCase(WhitespaceHandling.All), + TestCase(WhitespaceHandling.None), + TestCase(WhitespaceHandling.Significant)] + public void TestLoadXmlDocument(WhitespaceHandling whitespace) + { + var xml = new XmlDocument(); + var reader = new XmlTextReader(BasicHasingTests.ReferenceXMLVehicle); + reader.WhitespaceHandling = whitespace; + xml.Load(reader); + var h = VectoHash.Load(xml); + + var hash = h.ComputeHash(); + Assert.AreEqual(BasicHasingTests.HashVehicleXML, hash); + } + + [TestCase(@"Testdata\XML\ToHash\vecto_engine-input.xml"), + TestCase(@"Testdata\XML\ToHash\vecto_engine_withid-input.xml"), + TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input.xml")] + public void TestHashedComponentIsValid(string file) + { + var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; + + var h = VectoHash.Load(file); + var r = h.AddHash(); + + var writer = new XmlTextWriter(destination, Encoding.UTF8); + r.WriteTo(writer); + writer.Flush(); + writer.Close(); + + var h2 = VectoHash.Load(destination); + Assert.IsTrue(h2.ValidateHash()); + + // re-load generated XML and perform XSD validation + var settings = new XmlReaderSettings() { + ValidationType = ValidationType.Schema, + ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema | + //XmlSchemaValidationFlags.ProcessSchemaLocation | + XmlSchemaValidationFlags.ReportValidationWarnings + }; + settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack); + settings.Schemas.Add(GetXMLSchema(false)); + var xmlValidator = XmlReader.Create(destination, settings); + var xmlDoc = XDocument.Load(xmlValidator); + } + + + [TestCase("vecto_vehicle-namespace_prefix.xml", BasicHasingTests.HashVehicleXML)] + public void TestNamespacePrefixVariations(string file, string expectedHash) + { + var h = VectoHash.Load(@"Testdata\XML\Variations\" + file); + var hash = h.ComputeHash(); + + Assert.AreEqual(expectedHash, hash); + } + + [TestCase()] + public void TestInvalidXMLAsFile() + { + var file = @"Testdata\XML\Invalid\invalid-comp.xml"; + + AssertHelper.Exception<Exception>(() => VectoHash.Load(file), "failed to read XML document"); + } + + [TestCase()] + public void TestInvalidXMLAsStream() + { + var file = @"Testdata\XML\Invalid\invalid-comp.xml"; + var stream = File.Open(file, FileMode.Open); + AssertHelper.Exception<Exception>(() => VectoHash.Load(stream), "failed to read XML document"); + } + + [TestCase()] + public void TestComputeHashNoComponentInXML() + { + var xml = @"<VectoInputDeclaration/>"; + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(xml); + writer.Flush(); + stream.Seek(0, SeekOrigin.Begin); + + var h = VectoHash.Load(stream); + AssertHelper.Exception<Exception>(() => h.ComputeHash(), "No component found"); + } + + [TestCase()] + public void TestReadHashNoComponentInXML() + { + var xml = @"<VectoInputDeclaration/>"; + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(xml); + writer.Flush(); + stream.Seek(0, SeekOrigin.Begin); + + var h = VectoHash.Load(stream); + AssertHelper.Exception<Exception>(() => h.ReadHash(), "No component found"); + } + + [TestCase(VectoComponents.Engine, "ENG-"), + TestCase(VectoComponents.Gearbox, "GBX-"), + TestCase(VectoComponents.Axlegear, "AXL-"), + TestCase(VectoComponents.Retarder, "RET-"), + TestCase(VectoComponents.TorqueConverter, "TC-"), + TestCase(VectoComponents.Angledrive, "ANGL-"), + TestCase(VectoComponents.Airdrag, "AD-"), + TestCase(VectoComponents.Tyre, "TYRE-"), + ] + public void TestIdPrefix(VectoComponents component, string expectedPrefix) + { + Assert.AreEqual(expectedPrefix, component.HashIdPrefix()); + } + + [TestCase()] + public void TestInvalidComponentXMLName() + { + AssertHelper.Exception<ArgumentOutOfRangeException>(() => ((VectoComponents)9999).XMLElementName()); + } + + [TestCase()] + public void TestInvalidComponentPrefix() + { + AssertHelper.Exception<ArgumentOutOfRangeException>(() => ((VectoComponents)9999).HashIdPrefix()); + } + + private static XmlSchemaSet GetXMLSchema(bool job) + { + var resource = RessourceHelper.LoadResourceAsStream(RessourceHelper.ResourceType.XMLSchema, + job ? "VectoInput.xsd" : "VectoComponent.xsd"); + var xset = new XmlSchemaSet() { XmlResolver = new XmlResourceResolver() }; + var reader = XmlReader.Create(resource, new XmlReaderSettings(), "schema://"); + xset.Add(XmlSchema.Read(reader, null)); + xset.Compile(); + return xset; + } + + private static void ValidationCallBack(object sender, ValidationEventArgs args) + { + if (args.Severity == XmlSeverityType.Error) { + throw new Exception(string.Format("Validation error: {0}" + Environment.NewLine + + "Line: {1}", args.Message, args.Exception.LineNumber)); + } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Configuration/Constants.cs b/VectoCore/VectoCore/Configuration/Constants.cs index 39866f24b040a941f7486b21034505e4851b898c..1bfde99ff9e9708a085b97eb99d6a62733e57ca8 100644 --- a/VectoCore/VectoCore/Configuration/Constants.cs +++ b/VectoCore/VectoCore/Configuration/Constants.cs @@ -36,6 +36,7 @@ namespace TUGraz.VectoCore.Configuration { public static class Constants { + public static Second DefaultPowerShiftTime = 0.8.SI<Second>(); public const double RPMToRad = 2 * Math.PI / 60; public const double Kilo = 1000; public const double MeterPerSecondToKMH = 3.6; diff --git a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONComponentInputData.cs b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONComponentInputData.cs index c31323bed471769f058132d46d28ceb7114923e3..53f64fc8c4ea957001a627be8194ec63a575b602 100644 --- a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONComponentInputData.cs +++ b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONComponentInputData.cs @@ -29,160 +29,160 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.IO; -using System.Xml.Linq; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.InputData.FileIO.JSON -{ - public class JSONComponentInputData : IEngineeringInputDataProvider, IDeclarationInputDataProvider - { - protected IGearboxEngineeringInputData Gearbox; - protected IAxleGearInputData AxleGear; - protected ITorqueConverterEngineeringInputData TorqueConverter; - protected IAngledriveInputData Angledrive; - protected IEngineEngineeringInputData Engine; - protected IVehicleEngineeringInputData VehicleData; - protected IRetarderInputData Retarder; - protected IPTOTransmissionInputData PTOTransmission; - private IAirdragEngineeringInputData AirdragData; - - - public JSONComponentInputData(string filename, bool tolerateMissing = false) - { - var extension = Path.GetExtension(filename); - object tmp = null; - switch (extension) { - case Constants.FileExtensions.VehicleDataFile: - tmp = JSONInputDataFactory.ReadJsonVehicle(filename, tolerateMissing); - break; - case Constants.FileExtensions.EngineDataFile: - tmp = JSONInputDataFactory.ReadEngine(filename, tolerateMissing); - break; - case Constants.FileExtensions.GearboxDataFile: - tmp = JSONInputDataFactory.ReadGearbox(filename, tolerateMissing); - break; - } - tmp.Switch() - .If<IVehicleEngineeringInputData>(c => VehicleData = c) - .If<IAirdragEngineeringInputData>(c => AirdragData = c) - .If<IEngineEngineeringInputData>(c => Engine = c) - .If<IGearboxEngineeringInputData>(c => Gearbox = c) - .If<IAxleGearInputData>(c => AxleGear = c) - .If<IRetarderInputData>(c => Retarder = c) - .If<ITorqueConverterEngineeringInputData>(c => TorqueConverter = c) - .If<IAngledriveInputData>(c => Angledrive = c) - .If<IPTOTransmissionInputData>(c => PTOTransmission = c); - } - - - public IEngineeringJobInputData JobInputData() - { - throw new NotImplementedException(); - } - - - IVehicleDeclarationInputData IDeclarationInputDataProvider.VehicleInputData - { - get { return VehicleData; } - } - - IAirdragDeclarationInputData IDeclarationInputDataProvider.AirdragInputData - { - get { return AirdragInputData; } - } - - public IAirdragEngineeringInputData AirdragInputData - { - get { return AirdragData; } - } - - IGearboxDeclarationInputData IDeclarationInputDataProvider.GearboxInputData - { - get { return GearboxInputData; } - } - - ITorqueConverterDeclarationInputData IDeclarationInputDataProvider.TorqueConverterInputData - { - get { return TorqueConverterInputData; } - } - - IDeclarationJobInputData IDeclarationInputDataProvider.JobInputData() - { - throw new NotImplementedException(); - } - - public IVehicleEngineeringInputData VehicleInputData - { - get { return VehicleData; } - } - - public IGearboxEngineeringInputData GearboxInputData - { - get { return Gearbox; } - } - - public ITorqueConverterEngineeringInputData TorqueConverterInputData - { - get { return TorqueConverter; } - } - - public IAxleGearInputData AxleGearInputData - { - get { return AxleGear; } - } - - public IAngledriveInputData AngledriveInputData - { - get { return Angledrive; } - } - - IEngineDeclarationInputData IDeclarationInputDataProvider.EngineInputData - { - get { return EngineInputData; } - } - - public IEngineEngineeringInputData EngineInputData - { - get { return Engine; } - } - - public IAuxiliariesEngineeringInputData AuxiliaryInputData() - { - throw new NotImplementedException(); - } - - IAuxiliariesDeclarationInputData IDeclarationInputDataProvider.AuxiliaryInputData() - { - throw new NotImplementedException(); - } - - public IRetarderInputData RetarderInputData - { - get { return Retarder; } - } - - IDriverDeclarationInputData IDeclarationInputDataProvider.DriverInputData - { - get { throw new NotImplementedException(); } - } - - public IDriverEngineeringInputData DriverInputData - { - get { throw new NotImplementedException(); } - } - - public IPTOTransmissionInputData PTOTransmissionInputData - { - get { return PTOTransmission; } - } - - public XElement XMLHash - { - get { return null; } - } - } +using System; +using System.IO; +using System.Xml.Linq; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.FileIO.JSON +{ + public class JSONComponentInputData : IEngineeringInputDataProvider, IDeclarationInputDataProvider + { + protected IGearboxEngineeringInputData Gearbox; + protected IAxleGearInputData AxleGear; + protected ITorqueConverterEngineeringInputData TorqueConverter; + protected IAngledriveInputData Angledrive; + protected IEngineEngineeringInputData Engine; + protected IVehicleEngineeringInputData VehicleData; + protected IRetarderInputData Retarder; + protected IPTOTransmissionInputData PTOTransmission; + private IAirdragEngineeringInputData AirdragData; + + + public JSONComponentInputData(string filename, bool tolerateMissing = false) + { + var extension = Path.GetExtension(filename); + object tmp = null; + switch (extension) { + case Constants.FileExtensions.VehicleDataFile: + tmp = JSONInputDataFactory.ReadJsonVehicle(filename, tolerateMissing); + break; + case Constants.FileExtensions.EngineDataFile: + tmp = JSONInputDataFactory.ReadEngine(filename, tolerateMissing); + break; + case Constants.FileExtensions.GearboxDataFile: + tmp = JSONInputDataFactory.ReadGearbox(filename, tolerateMissing); + break; + } + tmp.Switch() + .If<IVehicleEngineeringInputData>(c => VehicleData = c) + .If<IAirdragEngineeringInputData>(c => AirdragData = c) + .If<IEngineEngineeringInputData>(c => Engine = c) + .If<IGearboxEngineeringInputData>(c => Gearbox = c) + .If<IAxleGearInputData>(c => AxleGear = c) + .If<IRetarderInputData>(c => Retarder = c) + .If<ITorqueConverterEngineeringInputData>(c => TorqueConverter = c) + .If<IAngledriveInputData>(c => Angledrive = c) + .If<IPTOTransmissionInputData>(c => PTOTransmission = c); + } + + + public IEngineeringJobInputData JobInputData() + { + throw new NotImplementedException(); + } + + + IVehicleDeclarationInputData IDeclarationInputDataProvider.VehicleInputData + { + get { return VehicleData; } + } + + IAirdragDeclarationInputData IDeclarationInputDataProvider.AirdragInputData + { + get { return AirdragInputData; } + } + + public IAirdragEngineeringInputData AirdragInputData + { + get { return AirdragData; } + } + + IGearboxDeclarationInputData IDeclarationInputDataProvider.GearboxInputData + { + get { return GearboxInputData; } + } + + ITorqueConverterDeclarationInputData IDeclarationInputDataProvider.TorqueConverterInputData + { + get { return TorqueConverterInputData; } + } + + IDeclarationJobInputData IDeclarationInputDataProvider.JobInputData() + { + throw new NotImplementedException(); + } + + public IVehicleEngineeringInputData VehicleInputData + { + get { return VehicleData; } + } + + public IGearboxEngineeringInputData GearboxInputData + { + get { return Gearbox; } + } + + public ITorqueConverterEngineeringInputData TorqueConverterInputData + { + get { return TorqueConverter; } + } + + public IAxleGearInputData AxleGearInputData + { + get { return AxleGear; } + } + + public IAngledriveInputData AngledriveInputData + { + get { return Angledrive; } + } + + IEngineDeclarationInputData IDeclarationInputDataProvider.EngineInputData + { + get { return EngineInputData; } + } + + public IEngineEngineeringInputData EngineInputData + { + get { return Engine; } + } + + public IAuxiliariesEngineeringInputData AuxiliaryInputData() + { + throw new NotImplementedException(); + } + + IAuxiliariesDeclarationInputData IDeclarationInputDataProvider.AuxiliaryInputData() + { + throw new NotImplementedException(); + } + + public IRetarderInputData RetarderInputData + { + get { return Retarder; } + } + + IDriverDeclarationInputData IDeclarationInputDataProvider.DriverInputData + { + get { throw new NotImplementedException(); } + } + + public IDriverEngineeringInputData DriverInputData + { + get { throw new NotImplementedException(); } + } + + public IPTOTransmissionInputData PTOTransmissionInputData + { + get { return PTOTransmission; } + } + + public XElement XMLHash + { + get { return null; } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONEngineData.cs b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONEngineData.cs index bf8d8e57a5c19e2e4b8aaed3ac557377677a299c..d1cb4311b329be30216f3717c71a7d936d68dbfe 100644 --- a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONEngineData.cs +++ b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONEngineData.cs @@ -29,231 +29,231 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.IO; -using Newtonsoft.Json.Linq; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; - -namespace TUGraz.VectoCore.InputData.FileIO.JSON -{ - /// <summary> - /// Represents the CombustionEngineData. Fileformat: .veng - /// </summary> - /// <code> - /// { - /// "Header": { - /// "CreatedBy": " ()", - /// "Date": "3/4/2015 12:26:24 PM", - /// "AppVersion": "2.0.4-beta3", - /// "FileVersion": 2 - /// }, - /// "Body": { - /// "SavedInDeclMode": false, - /// "ModelName": "Generic 24t Coach", - /// "Displacement": 12730.0, - /// "IdlingSpeed": 560.0, - /// "Inertia": 3.8, - /// "FullLoadCurves": [ - /// { - /// "Path": "24t Coach.vfld", - /// "Gears": "0 - 99" - /// } - /// ], - /// "FuelMap": "24t Coach.vmap", - /// "WHTC-Urban": 0.0, - /// "WHTC-Rural": 0.0, - /// "WHTC-Motorway": 0.0 - /// } - /// } - /// </code> - public class JSONEngineDataV4 : JSONEngineDataV3 - { - public JSONEngineDataV4(JObject data, string fileName, bool tolerateMissing = false) - : base(data, fileName, tolerateMissing) {} - - public override Watt RatedPowerDeclared - { - get { return Body.GetEx<double>("RatedPower").SI<Watt>(); } - } - - public override PerSecond RatedSpeedDeclared - { - get { return Body.GetEx<double>("RatedSpeed").RPMtoRad(); } - } - - public override NewtonMeter MaxTorqueDeclared - { - get { return Body.GetEx<double>("MaxTorque").SI<NewtonMeter>(); } - } - - public override double CorrectionFactorRegPer - { - get { return Body.GetEx<double>("CFRegPer"); } - } - - - public override double CorrectionFactorNCV - { - get { return Body.GetEx<double>("CFNCV"); } - } - - public override FuelType FuelType - { - get { return Body.GetEx<string>("FuelType").ParseEnum<FuelType>(); } - } - } - - - public class JSONEngineDataV3 : JSONFile, IEngineEngineeringInputData - { - public JSONEngineDataV3(JObject data, string fileName, bool tolerateMissing = false) - : base(data, fileName, tolerateMissing) {} - - public virtual CubicMeter Displacement - { - get { return Body.GetEx<double>(JsonKeys.Engine_Displacement).SI().Cubic.Centi.Meter.Cast<CubicMeter>(); } - // convert vom ccm to m^3} - } - - public virtual PerSecond IdleSpeed - { - get { return Body.GetEx<double>(JsonKeys.Engine_IdleSpeed).RPMtoRad(); } - } - - - public virtual FuelType FuelType - { - get { return FuelType.DieselCI; } - } - - public virtual TableData FuelConsumptionMap - { - get { - try { - return ReadTableData(Body.GetEx<string>(JsonKeys.Engine_FuelConsumptionMap), "FuelConsumptionMap"); - } catch (Exception) { - if (!TolerateMissing) { - throw; - } - return - new TableData(Path.Combine(BasePath, Body[JsonKeys.Engine_FuelConsumptionMap].ToString()) + MissingFileSuffix, - DataSourceType.Missing); - } - } - } - - public virtual TableData FullLoadCurve - { - get { - try { - return ReadTableData(Body.GetEx<string>(JsonKeys.Engine_FullLoadCurveFile), "FullLoadCurve"); - } catch (Exception) { - if (!TolerateMissing) { - throw; - } - return new TableData( - Path.Combine(BasePath, Body[JsonKeys.Engine_FullLoadCurveFile].ToString()) + MissingFileSuffix, - DataSourceType.Missing); - } - } - } - - public virtual Watt RatedPowerDeclared - { - get { return 0.SI<Watt>(); } - } - - public virtual PerSecond RatedSpeedDeclared - { - get { return 0.RPMtoRad(); } - } - - public virtual NewtonMeter MaxTorqueDeclared - { - get { return 0.SI<NewtonMeter>(); } - } - - public virtual KilogramSquareMeter Inertia - { - get { return Body.GetEx<double>(JsonKeys.Engine_Inertia).SI<KilogramSquareMeter>(); } - } - - public virtual double WHTCEngineering - { - get { - if (Body["WHTC-Engineering"] == null) { - return 1; - } - return Body.GetEx<double>("WHTC-Engineering"); - } - } - - public virtual double WHTCMotorway - { - get { return Body.GetEx<double>(JsonKeys.Engine_WHTC_Motorway); } - } - - public virtual double WHTCRural - { - get { return Body.GetEx<double>(JsonKeys.Engine_WHTC_Rural); } - } - - public virtual double WHTCUrban - { - get { return Body.GetEx<double>(JsonKeys.Engine_WHTC_Urban); } - } - - public double ColdHotBalancingFactor - { - get { - if (Body["ColdHotBalancingFactor"] == null) { - return 1.0; - } - return Body.GetEx<double>("ColdHotBalancingFactor"); - } - } - - public virtual double CorrectionFactorRegPer - { - get { return 1; } - } - - public virtual double CorrectionFactorNCV - { - get { return 1; } - } - - public string Manufacturer - { - get { return "N/A"; } - } - - public string Model - { - get { return Body.GetEx<string>(JsonKeys.Engine_ModelName); } - } - - - public string Date - { - get { return "N/A"; } - } - - public CertificationMethod CertificationMethod - { - get { return CertificationMethod.NotCertified; } - } - - public string CertificationNumber - { - get { return "N/A"; } - } - - public string DigestValue - { - get { return "N/A"; } - } - } +using System; +using System.IO; +using Newtonsoft.Json.Linq; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.InputData.FileIO.JSON +{ + /// <summary> + /// Represents the CombustionEngineData. Fileformat: .veng + /// </summary> + /// <code> + /// { + /// "Header": { + /// "CreatedBy": " ()", + /// "Date": "3/4/2015 12:26:24 PM", + /// "AppVersion": "2.0.4-beta3", + /// "FileVersion": 2 + /// }, + /// "Body": { + /// "SavedInDeclMode": false, + /// "ModelName": "Generic 24t Coach", + /// "Displacement": 12730.0, + /// "IdlingSpeed": 560.0, + /// "Inertia": 3.8, + /// "FullLoadCurves": [ + /// { + /// "Path": "24t Coach.vfld", + /// "Gears": "0 - 99" + /// } + /// ], + /// "FuelMap": "24t Coach.vmap", + /// "WHTC-Urban": 0.0, + /// "WHTC-Rural": 0.0, + /// "WHTC-Motorway": 0.0 + /// } + /// } + /// </code> + public class JSONEngineDataV4 : JSONEngineDataV3 + { + public JSONEngineDataV4(JObject data, string fileName, bool tolerateMissing = false) + : base(data, fileName, tolerateMissing) {} + + public override Watt RatedPowerDeclared + { + get { return Body.GetEx<double>("RatedPower").SI<Watt>(); } + } + + public override PerSecond RatedSpeedDeclared + { + get { return Body.GetEx<double>("RatedSpeed").RPMtoRad(); } + } + + public override NewtonMeter MaxTorqueDeclared + { + get { return Body.GetEx<double>("MaxTorque").SI<NewtonMeter>(); } + } + + public override double CorrectionFactorRegPer + { + get { return Body.GetEx<double>("CFRegPer"); } + } + + + public override double CorrectionFactorNCV + { + get { return Body.GetEx<double>("CFNCV"); } + } + + public override FuelType FuelType + { + get { return Body.GetEx<string>("FuelType").ParseEnum<FuelType>(); } + } + } + + + public class JSONEngineDataV3 : JSONFile, IEngineEngineeringInputData + { + public JSONEngineDataV3(JObject data, string fileName, bool tolerateMissing = false) + : base(data, fileName, tolerateMissing) {} + + public virtual CubicMeter Displacement + { + get { return Body.GetEx<double>(JsonKeys.Engine_Displacement).SI().Cubic.Centi.Meter.Cast<CubicMeter>(); } + // convert vom ccm to m^3} + } + + public virtual PerSecond IdleSpeed + { + get { return Body.GetEx<double>(JsonKeys.Engine_IdleSpeed).RPMtoRad(); } + } + + + public virtual FuelType FuelType + { + get { return FuelType.DieselCI; } + } + + public virtual TableData FuelConsumptionMap + { + get { + try { + return ReadTableData(Body.GetEx<string>(JsonKeys.Engine_FuelConsumptionMap), "FuelConsumptionMap"); + } catch (Exception) { + if (!TolerateMissing) { + throw; + } + return + new TableData(Path.Combine(BasePath, Body[JsonKeys.Engine_FuelConsumptionMap].ToString()) + MissingFileSuffix, + DataSourceType.Missing); + } + } + } + + public virtual TableData FullLoadCurve + { + get { + try { + return ReadTableData(Body.GetEx<string>(JsonKeys.Engine_FullLoadCurveFile), "FullLoadCurve"); + } catch (Exception) { + if (!TolerateMissing) { + throw; + } + return new TableData( + Path.Combine(BasePath, Body[JsonKeys.Engine_FullLoadCurveFile].ToString()) + MissingFileSuffix, + DataSourceType.Missing); + } + } + } + + public virtual Watt RatedPowerDeclared + { + get { return 0.SI<Watt>(); } + } + + public virtual PerSecond RatedSpeedDeclared + { + get { return 0.RPMtoRad(); } + } + + public virtual NewtonMeter MaxTorqueDeclared + { + get { return 0.SI<NewtonMeter>(); } + } + + public virtual KilogramSquareMeter Inertia + { + get { return Body.GetEx<double>(JsonKeys.Engine_Inertia).SI<KilogramSquareMeter>(); } + } + + public virtual double WHTCEngineering + { + get { + if (Body["WHTC-Engineering"] == null) { + return 1; + } + return Body.GetEx<double>("WHTC-Engineering"); + } + } + + public virtual double WHTCMotorway + { + get { return Body.GetEx<double>(JsonKeys.Engine_WHTC_Motorway); } + } + + public virtual double WHTCRural + { + get { return Body.GetEx<double>(JsonKeys.Engine_WHTC_Rural); } + } + + public virtual double WHTCUrban + { + get { return Body.GetEx<double>(JsonKeys.Engine_WHTC_Urban); } + } + + public double ColdHotBalancingFactor + { + get { + if (Body["ColdHotBalancingFactor"] == null) { + return 1.0; + } + return Body.GetEx<double>("ColdHotBalancingFactor"); + } + } + + public virtual double CorrectionFactorRegPer + { + get { return 1; } + } + + public virtual double CorrectionFactorNCV + { + get { return 1; } + } + + public string Manufacturer + { + get { return "N/A"; } + } + + public string Model + { + get { return Body.GetEx<string>(JsonKeys.Engine_ModelName); } + } + + + public string Date + { + get { return "N/A"; } + } + + public CertificationMethod CertificationMethod + { + get { return CertificationMethod.NotCertified; } + } + + public string CertificationNumber + { + get { return "N/A"; } + } + + public string DigestValue + { + get { return "N/A"; } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONGearboxData.cs b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONGearboxData.cs index 4a0aaca25f61f92a241022b8024e2d2114fac47f..f4a16976b992e192e771f1fd0b5348d41009c8cc 100644 --- a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONGearboxData.cs +++ b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONGearboxData.cs @@ -38,6 +38,7 @@ using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCommon.InputData; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; using TUGraz.VectoCore.InputData.Impl; using TUGraz.VectoCore.Models.Declaration; @@ -389,7 +390,7 @@ namespace TUGraz.VectoCore.InputData.FileIO.JSON { get { return Body["PowershiftShiftTime"] == null - ? 0.8.SI<Second>() + ? Constants.DefaultPowerShiftTime : Body.GetEx<double>("PowershiftShiftTime").SI<Second>(); } } diff --git a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONInputDataFactory.cs b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONInputDataFactory.cs index c406af6f577cce116208b59668c8b6012643e388..84520f0a606ea9de508fb2a5a096b860c97d0320 100644 --- a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONInputDataFactory.cs +++ b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONInputDataFactory.cs @@ -29,96 +29,96 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System.IO; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCore.Configuration; - -namespace TUGraz.VectoCore.InputData.FileIO.JSON -{ - // ReSharper disable once InconsistentNaming - public static class JSONInputDataFactory - { - internal static JObject ReadFile(string fileName) - { - if (!File.Exists(fileName)) { - throw new FileNotFoundException("failed to load file: " + fileName, fileName); - } - using (var reader = File.OpenText(fileName)) { - return (JObject)JToken.ReadFrom(new JsonTextReader(reader)); - } - } - - public static IInputDataProvider ReadComponentData(string filename) - { - if (Constants.FileExtensions.VectoJobFile.Equals(Path.GetExtension(filename), StringComparison.OrdinalIgnoreCase)) { - return ReadJsonJob(filename, true); - } - return new JSONComponentInputData(filename, true); - } - - public static IInputDataProvider ReadJsonJob(string filename, bool tolerateMissing = false) - { - var json = ReadFile(filename); - var version = ReadVersion(json); - - switch (version) { - case 2: - return new JSONInputDataV2(json, filename, tolerateMissing); - case 3: - return new JSONInputDataV3(json, filename, tolerateMissing); - default: - throw new VectoException("Job-File: Unsupported FileVersion. Got: {0} ", version); - } - } - - public static IVehicleEngineeringInputData ReadJsonVehicle(string filename, bool tolerateMissing = false) - { - var json = ReadFile(filename); - var version = ReadVersion(json); - switch (version) { - case 7: - return new JSONVehicleDataV7(json, filename, tolerateMissing); - default: - throw new VectoException("Vehicle-File: Unsupported FileVersion. Got {0}", version); - } - } - - public static IGearboxEngineeringInputData ReadGearbox(string filename, bool tolerateMissing = false) - { - var json = ReadFile(filename); - var version = ReadVersion(json); - switch (version) { - case 5: - return new JSONGearboxDataV5(json, filename, tolerateMissing); - case 6: - return new JSONGearboxDataV6(json, filename, tolerateMissing); - default: - throw new VectoException("Gearbox-File: Unsupported FileVersion. Got {0}", version); - } - } - - public static IEngineEngineeringInputData ReadEngine(string filename, bool tolerateMissing = false) - { - var json = ReadFile(filename); - var version = ReadVersion(json); - switch (version) { - case 3: - return new JSONEngineDataV3(json, filename, tolerateMissing); - case 4: - return new JSONEngineDataV4(json, filename, tolerateMissing); - default: - throw new VectoException("Engine-File: Unsupported FileVersion. Got {0}", version); - } - } - - private static int ReadVersion(JObject json) - { - var value = json.GetEx(JsonKeys.JsonHeader).GetEx<string>(JsonKeys.JsonHeader_FileVersion); - return (int)double.Parse(value.Trim('"')); - } - } +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.IO; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCore.Configuration; + +namespace TUGraz.VectoCore.InputData.FileIO.JSON +{ + // ReSharper disable once InconsistentNaming + public static class JSONInputDataFactory + { + internal static JObject ReadFile(string fileName) + { + if (!File.Exists(fileName)) { + throw new FileNotFoundException("failed to load file: " + fileName, fileName); + } + using (var reader = File.OpenText(fileName)) { + return (JObject)JToken.ReadFrom(new JsonTextReader(reader)); + } + } + + public static IInputDataProvider ReadComponentData(string filename) + { + if (Constants.FileExtensions.VectoJobFile.Equals(Path.GetExtension(filename), StringComparison.OrdinalIgnoreCase)) { + return ReadJsonJob(filename, true); + } + return new JSONComponentInputData(filename, true); + } + + public static IInputDataProvider ReadJsonJob(string filename, bool tolerateMissing = false) + { + var json = ReadFile(filename); + var version = ReadVersion(json); + + switch (version) { + case 2: + return new JSONInputDataV2(json, filename, tolerateMissing); + case 3: + return new JSONInputDataV3(json, filename, tolerateMissing); + default: + throw new VectoException("Job-File: Unsupported FileVersion. Got: {0} ", version); + } + } + + public static IVehicleEngineeringInputData ReadJsonVehicle(string filename, bool tolerateMissing = false) + { + var json = ReadFile(filename); + var version = ReadVersion(json); + switch (version) { + case 7: + return new JSONVehicleDataV7(json, filename, tolerateMissing); + default: + throw new VectoException("Vehicle-File: Unsupported FileVersion. Got {0}", version); + } + } + + public static IGearboxEngineeringInputData ReadGearbox(string filename, bool tolerateMissing = false) + { + var json = ReadFile(filename); + var version = ReadVersion(json); + switch (version) { + case 5: + return new JSONGearboxDataV5(json, filename, tolerateMissing); + case 6: + return new JSONGearboxDataV6(json, filename, tolerateMissing); + default: + throw new VectoException("Gearbox-File: Unsupported FileVersion. Got {0}", version); + } + } + + public static IEngineEngineeringInputData ReadEngine(string filename, bool tolerateMissing = false) + { + var json = ReadFile(filename); + var version = ReadVersion(json); + switch (version) { + case 3: + return new JSONEngineDataV3(json, filename, tolerateMissing); + case 4: + return new JSONEngineDataV4(json, filename, tolerateMissing); + default: + throw new VectoException("Engine-File: Unsupported FileVersion. Got {0}", version); + } + } + + private static int ReadVersion(JObject json) + { + var value = json.GetEx(JsonKeys.JsonHeader).GetEx<string>(JsonKeys.JsonHeader_FileVersion); + return (int)double.Parse(value.Trim('"')); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Impl/InputData.cs b/VectoCore/VectoCore/InputData/Impl/InputData.cs index 5e882eedeff0805e80451c0e8bd9d5026be3f9f0..d14a8312dcf3eacad9808e9ec4442c431932db9d 100644 --- a/VectoCore/VectoCore/InputData/Impl/InputData.cs +++ b/VectoCore/VectoCore/InputData/Impl/InputData.cs @@ -29,123 +29,118 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Collections.Generic; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; - -namespace TUGraz.VectoCore.InputData.Impl -{ - public class CycleInputData : ICycleData - { - public string Name { get; internal set; } - - public TableData CycleData { get; internal set; } - } - - public class LookAheadCoastingInputData : ILookaheadCoastingInputData - { - public bool Enabled { get; internal set; } - - //public MeterPerSquareSecond Deceleration { get; internal set; } - - public MeterPerSecond MinSpeed { get; internal set; } - - public double CoastingDecisionFactorOffset { get; internal set; } - public double CoastingDecisionFactorScaling { get; internal set; } - public double LookaheadDistanceFactor { get; internal set; } - public TableData CoastingDecisionFactorTargetSpeedLookup { get; internal set; } - public TableData CoastingDecisionFactorVelocityDropLookup { get; internal set; } - } - - public class OverSpeedEcoRollInputData : IOverSpeedEcoRollEngineeringInputData - { - public DriverMode Mode { get; internal set; } - - public MeterPerSecond MinSpeed { get; internal set; } - - public MeterPerSecond OverSpeed { get; internal set; } - - public MeterPerSecond UnderSpeed { get; internal set; } - } - - public class TransmissionInputData : ITransmissionInputData - { - public int Gear { get; internal set; } - - public double Ratio { get; internal set; } - - public TableData LossMap { get; internal set; } - - public double Efficiency { get; internal set; } - - public NewtonMeter MaxTorque { get; internal set; } - - public PerSecond MaxInputSpeed { get; internal set; } - - public TableData ShiftPolygon { get; internal set; } - } - - public class AxleInputData : IAxleEngineeringInputData - { - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] - public bool SavedInDeclarationMode - { - get { throw new System.NotImplementedException(); } - } - - public DataSourceType SourceType { get; internal set; } - - public string Source { get; internal set; } - - public string Wheels { get; internal set; } - - public bool TwinTyres { get; internal set; } - - public bool Steered { get; internal set; } - - public AxleType AxleType { get; internal set; } - - public double RollResistanceCoefficient { get; internal set; } - - public Newton TyreTestLoad { get; internal set; } - - public double AxleWeightShare { get; internal set; } - - public KilogramSquareMeter Inertia { get; internal set; } - } - - public class AuxiliaryDataInputData : IAuxiliaryEngineeringInputData, IAuxiliaryDeclarationInputData - { - public AuxiliaryDataInputData() - { - AuxiliaryType = AuxiliaryDemandType.Mapping; - ConstantPowerDemand = 0.SI<Watt>(); - } - - public AuxiliaryDemandType AuxiliaryType { get; internal set; } - - public string ID { get; internal set; } - - public AuxiliaryType Type { get; internal set; } - - public IList<string> Technology { get; internal set; } - - public double TransmissionRatio { get; internal set; } - - public double EfficiencyToEngine { get; internal set; } - - public double EfficiencyToSupply { get; internal set; } - - public TableData DemandMap { get; internal set; } - - public Watt ConstantPowerDemand { get; internal set; } - } - - public class TorqueLimitInputData : ITorqueLimitInputData - { - public int Gear { get; internal set; } - public NewtonMeter MaxTorque { get; internal set; } - } +using System.Collections.Generic; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.InputData.Impl +{ + public class CycleInputData : ICycleData + { + public string Name { get; internal set; } + + public TableData CycleData { get; internal set; } + } + + public class LookAheadCoastingInputData : ILookaheadCoastingInputData + { + public bool Enabled { get; internal set; } + + //public MeterPerSquareSecond Deceleration { get; internal set; } + + public MeterPerSecond MinSpeed { get; internal set; } + + public double CoastingDecisionFactorOffset { get; internal set; } + public double CoastingDecisionFactorScaling { get; internal set; } + public double LookaheadDistanceFactor { get; internal set; } + public TableData CoastingDecisionFactorTargetSpeedLookup { get; internal set; } + public TableData CoastingDecisionFactorVelocityDropLookup { get; internal set; } + } + + public class OverSpeedEcoRollInputData : IOverSpeedEcoRollEngineeringInputData + { + public DriverMode Mode { get; internal set; } + + public MeterPerSecond MinSpeed { get; internal set; } + + public MeterPerSecond OverSpeed { get; internal set; } + + public MeterPerSecond UnderSpeed { get; internal set; } + } + + public class TransmissionInputData : ITransmissionInputData + { + public int Gear { get; internal set; } + + public double Ratio { get; internal set; } + + public TableData LossMap { get; internal set; } + + public double Efficiency { get; internal set; } + + public NewtonMeter MaxTorque { get; internal set; } + + public PerSecond MaxInputSpeed { get; internal set; } + + public TableData ShiftPolygon { get; internal set; } + } + + public class AxleInputData : IAxleEngineeringInputData + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", + "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] + public DataSourceType SourceType { get; internal set; } + + public string Source { get; internal set; } + + public string Wheels { get; internal set; } + + public bool TwinTyres { get; internal set; } + + public bool Steered { get; internal set; } + + public AxleType AxleType { get; internal set; } + + public double RollResistanceCoefficient { get; internal set; } + + public Newton TyreTestLoad { get; internal set; } + + public double AxleWeightShare { get; internal set; } + + public KilogramSquareMeter Inertia { get; internal set; } + } + + public class AuxiliaryDataInputData : IAuxiliaryEngineeringInputData, IAuxiliaryDeclarationInputData + { + public AuxiliaryDataInputData() + { + AuxiliaryType = AuxiliaryDemandType.Mapping; + ConstantPowerDemand = 0.SI<Watt>(); + } + + public AuxiliaryDemandType AuxiliaryType { get; internal set; } + + public string ID { get; internal set; } + + public AuxiliaryType Type { get; internal set; } + + public IList<string> Technology { get; internal set; } + + public double TransmissionRatio { get; internal set; } + + public double EfficiencyToEngine { get; internal set; } + + public double EfficiencyToSupply { get; internal set; } + + public TableData DemandMap { get; internal set; } + + public Watt ConstantPowerDemand { get; internal set; } + } + + public class TorqueLimitInputData : ITorqueLimitInputData + { + public int Gear { get; internal set; } + public NewtonMeter MaxTorque { get; internal set; } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs index 4e58f0cc8168bae342244d3144378d134e694921..8be37b2d141d5d634ba0dd38a233996b90c71d8f 100644 --- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs +++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs @@ -211,7 +211,7 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter } internal GearboxData CreateGearboxData(IGearboxDeclarationInputData gearbox, CombustionEngineData engine, - double axlegearRatio, Meter dynamicTyreRadius, bool useEfficiencyFallback) + double axlegearRatio, Meter dynamicTyreRadius, VehicleCategory vehicleCategory, bool useEfficiencyFallback) { if (!gearbox.SavedInDeclarationMode) { WarnDeclarationMode("GearboxData"); @@ -282,7 +282,7 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter // torqueconverter is active in first gear - duplicate ratio and lossmap for torque converter mode CreateTCFirstGearATSerial(gearData, tcShiftPolygon); } - if (i == 1 && gearDifferenceRatio >= DeclarationData.Gearbox.TorqueConverterSecondGearThreshold) { + if (i == 1 && gearDifferenceRatio >= DeclarationData.Gearbox.TorqueConverterSecondGearThreshold(vehicleCategory)) { // ratio between first and second gear is above threshold, torqueconverter is active in second gear as well // -> duplicate ratio and lossmap for torque converter mode, remove locked transmission for previous gear CreateTCSecondGearATSerial(gearData, tcShiftPolygon); diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs index f5af5e2dcd4f73446c93c39f1313c3d63e5325a1..e085a404aba7ca058b1ac1d9938858d311c0307d 100644 --- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs +++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs @@ -62,7 +62,6 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter retVal.DynamicTyreRadius = data.DynamicTyreRadius; var axles = data.Axles; - retVal.AxleData = axles.Select(axle => new Axle { WheelsDimension = axle.Wheels, Inertia = axle.Inertia, @@ -82,8 +81,7 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter switch (airdragData.CrossWindCorrectionMode) { case CrossWindCorrectionMode.NoCorrection: - retVal.CrossWindCorrectionCurve = - new CrosswindCorrectionCdxALookup(airdragData.AirDragArea, + retVal.CrossWindCorrectionCurve = new CrosswindCorrectionCdxALookup(airdragData.AirDragArea, CrossWindCorrectionCurveReader.GetNoCorrectionCurve(airdragData.AirDragArea), CrossWindCorrectionMode.NoCorrection); break; @@ -97,13 +95,14 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter CrossWindCorrectionCurveReader.ReadCdxABetaTable(airdragData.CrosswindCorrectionMap)); break; case CrossWindCorrectionMode.DeclarationModeCorrection: + var airDragArea = airdragData.AirDragArea ?? + DeclarationData.Segments.LookupCdA(data.VehicleCategory, data.AxleConfiguration, data.GrossVehicleMassRating); var height = DeclarationData.Segments.LookupHeight(data.VehicleCategory, data.AxleConfiguration, data.GrossVehicleMassRating); - retVal.CrossWindCorrectionCurve = - new CrosswindCorrectionCdxALookup(airdragData.AirDragArea, + retVal.CrossWindCorrectionCurve = new CrosswindCorrectionCdxALookup(airDragArea, DeclarationDataAdapter.GetDeclarationAirResistanceCurve( - GetAirdragParameterSet(data.VehicleCategory, data.AxleConfiguration, data.Axles.Count), - airdragData.AirDragArea, height), CrossWindCorrectionMode.DeclarationModeCorrection); + GetAirdragParameterSet(data.VehicleCategory, data.AxleConfiguration, data.Axles.Count), airDragArea, height), + CrossWindCorrectionMode.DeclarationModeCorrection); break; default: throw new ArgumentOutOfRangeException("CrosswindCorrection", airdragData.CrossWindCorrectionMode.ToString()); @@ -159,7 +158,7 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter } internal GearboxData CreateGearboxData(IGearboxEngineeringInputData gearbox, CombustionEngineData engineData, - double axlegearRatio, Meter dynamicTyreRadius, bool useEfficiencyFallback) + double axlegearRatio, Meter dynamicTyreRadius, VehicleCategory vehicleCategory, bool useEfficiencyFallback) { if (gearbox.SavedInDeclarationMode) { WarnEngineeringMode("GearboxData"); @@ -230,7 +229,7 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter // torqueconverter is active in first gear - duplicate ratio and lossmap for torque converter mode CreateTCFirstGearATSerial(gearData, tcShiftPolygon); } - if (i == 1 && gearDifferenceRatio >= DeclarationData.Gearbox.TorqueConverterSecondGearThreshold) { + if (i == 1 && gearDifferenceRatio >= DeclarationData.Gearbox.TorqueConverterSecondGearThreshold(vehicleCategory)) { // ratio between first and second gear is above threshold, torqueconverter is active in second gear as well // -> duplicate ratio and lossmap for torque converter mode, remove locked transmission for previous gear CreateTCSecondGearATSerial(gearData, tcShiftPolygon); @@ -255,7 +254,6 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter retVal.UpshiftMinAcceleration = gearbox.UpshiftMinAcceleration; } - public IList<VectoRunData.AuxData> CreateAuxiliaryData(IAuxiliariesEngineeringInputData auxInputData) { var auxList = new List<VectoRunData.AuxData>(auxInputData.Auxiliaries.Count + 1) { diff --git a/VectoCore/VectoCore/InputData/Reader/Impl/DeclarationModeVectoRunDataFactory.cs b/VectoCore/VectoCore/InputData/Reader/Impl/DeclarationModeVectoRunDataFactory.cs index 99b9a05a567f7fdae998099264f16f84e5a7ae94..8a61d30f9378869da8e4711a1e544f2c475383d3 100644 --- a/VectoCore/VectoCore/InputData/Reader/Impl/DeclarationModeVectoRunDataFactory.cs +++ b/VectoCore/VectoCore/InputData/Reader/Impl/DeclarationModeVectoRunDataFactory.cs @@ -29,174 +29,174 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.Linq; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.InputData.Reader.ComponentData; -using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; - - -namespace TUGraz.VectoCore.InputData.Reader.Impl -{ - public class DeclarationModeVectoRunDataFactory : LoggingObject, IVectoRunDataFactory - { - private static readonly object CyclesCacheLock = new object(); - - private static readonly Dictionary<MissionType, DrivingCycleData> CyclesCache = - new Dictionary<MissionType, DrivingCycleData>(); - - protected readonly IDeclarationInputDataProvider InputDataProvider; - - protected IDeclarationReport Report; - private DeclarationDataAdapter _dao; - private Segment _segment; - private DriverData _driverdata; - private AirdragData _airdragData; - private CombustionEngineData _engineData; - private AxleGearData _axlegearData; - private AngledriveData _angledriveData; - private GearboxData _gearboxData; - private RetarderData _retarderData; - private PTOData _ptoTransmissionData; - private PTOData _municipalPtoTransmissionData; - private Exception InitException; - - internal DeclarationModeVectoRunDataFactory(IDeclarationInputDataProvider dataProvider, IDeclarationReport report) - { - InputDataProvider = dataProvider; - Report = report; - - try { - Initialize(); - if (Report != null) { - InitializeReport(); - } - } catch (Exception e) { - InitException = e; - } - } - - private void Initialize() - { - _dao = new DeclarationDataAdapter(); - _segment = GetVehicleClassification(InputDataProvider.VehicleInputData.VehicleCategory, - InputDataProvider.VehicleInputData.AxleConfiguration, - InputDataProvider.VehicleInputData.GrossVehicleMassRating, InputDataProvider.VehicleInputData.CurbMassChassis); - _driverdata = _dao.CreateDriverData(InputDataProvider.DriverInputData); - _driverdata.AccelerationCurve = AccelerationCurveReader.ReadFromStream(_segment.AccelerationFile); - - var tempVehicle = _dao.CreateVehicleData(InputDataProvider.VehicleInputData, _segment.Missions.First(), - _segment.Missions.First().Loadings.First().Value, _segment.MunicipalBodyWeight); - _airdragData = _dao.CreateAirdragData(InputDataProvider.AirdragInputData, _segment.Missions.First(), _segment); - _engineData = _dao.CreateEngineData(InputDataProvider.EngineInputData, - InputDataProvider.VehicleInputData.EngineIdleSpeed, - InputDataProvider.GearboxInputData, InputDataProvider.VehicleInputData.TorqueLimits); - _axlegearData = _dao.CreateAxleGearData(InputDataProvider.AxleGearInputData, false); - _angledriveData = _dao.CreateAngledriveData(InputDataProvider.AngledriveInputData, false); - _gearboxData = _dao.CreateGearboxData(InputDataProvider.GearboxInputData, _engineData, _axlegearData.AxleGear.Ratio, - tempVehicle.DynamicTyreRadius, false); - _retarderData = _dao.CreateRetarderData(InputDataProvider.RetarderInputData); - - _ptoTransmissionData = _dao.CreatePTOTransmissionData(InputDataProvider.PTOTransmissionInputData); - - _municipalPtoTransmissionData = CreateDefaultPTOData(); - } - - private void InitializeReport() - { - var powertrainConfig = new VectoRunData() { - VehicleData = - _dao.CreateVehicleData(InputDataProvider.VehicleInputData, _segment.Missions.First(), - _segment.Missions.First().Loadings.First().Value, _segment.MunicipalBodyWeight), - AirdragData = _airdragData, - EngineData = _engineData, - GearboxData = _gearboxData, - AxleGearData = _axlegearData, - Retarder = _retarderData, - Aux = _dao.CreateAuxiliaryData(InputDataProvider.AuxiliaryInputData(), _segment.Missions.First().MissionType, - _segment.VehicleClass), - InputDataHash = InputDataProvider.XMLHash - }; - Report.InitializeReport(powertrainConfig, _segment); - } - - public IEnumerable<VectoRunData> NextRun() - { - if (InitException != null) { - throw InitException; - } - - foreach (var mission in _segment.Missions) { - if (mission.MissionType.IsEMS() && - _engineData.RatedPowerDeclared.IsSmaller(DeclarationData.MinEnginePowerForEMS)) { - continue; - } - DrivingCycleData cycle; - lock (CyclesCacheLock) { - if (CyclesCache.ContainsKey(mission.MissionType)) { - cycle = CyclesCache[mission.MissionType]; - } else { - cycle = DrivingCycleDataReader.ReadFromStream(mission.CycleFile, CycleType.DistanceBased, "", false); - CyclesCache.Add(mission.MissionType, cycle); - } - } - foreach (var loading in mission.Loadings) { - var simulationRunData = new VectoRunData { - Loading = loading.Key, - VehicleData = - _dao.CreateVehicleData(InputDataProvider.VehicleInputData, mission, loading.Value, _segment.MunicipalBodyWeight), - AirdragData = _dao.CreateAirdragData(InputDataProvider.AirdragInputData, mission, _segment), - EngineData = _engineData.Copy(), - GearboxData = _gearboxData, - AxleGearData = _axlegearData, - AngledriveData = _angledriveData, - Aux = _dao.CreateAuxiliaryData(InputDataProvider.AuxiliaryInputData(), mission.MissionType, - _segment.VehicleClass), - Cycle = new DrivingCycleProxy(cycle, mission.MissionType.ToString()), - Retarder = _retarderData, - DriverData = _driverdata, - ExecutionMode = ExecutionMode.Declaration, - JobName = InputDataProvider.JobInputData().JobName, - ModFileSuffix = loading.Key.ToString(), - Report = Report, - Mission = mission, - PTO = mission.MissionType == MissionType.MunicipalUtility - ? _municipalPtoTransmissionData - : _ptoTransmissionData, - InputDataHash = InputDataProvider.XMLHash - }; - simulationRunData.EngineData.FuelConsumptionCorrectionFactor = DeclarationData.WHTCCorrection.Lookup( - mission.MissionType.GetNonEMSMissionType(), _engineData.WHTCRural, _engineData.WHTCUrban, _engineData.WHTCMotorway) * - _engineData.ColdHotCorrectionFactor; - simulationRunData.VehicleData.VehicleClass = _segment.VehicleClass; - yield return simulationRunData; - } - } - } - - private PTOData CreateDefaultPTOData() - { - return new PTOData() { - TransmissionType = DeclarationData.PTO.DefaultPTOTechnology, - LossMap = PTOIdleLossMapReader.ReadFromStream(RessourceHelper.ReadStream(DeclarationData.PTO.DefaultPTOIdleLosses)), - PTOCycle = - DrivingCycleDataReader.ReadFromStream(RessourceHelper.ReadStream(DeclarationData.PTO.DefaultPTOActivationCycle), - CycleType.PTO, "PTO", false) - }; - } - - internal Segment GetVehicleClassification(VehicleCategory category, AxleConfiguration axles, Kilogram grossMassRating, - Kilogram curbWeight) - { - return DeclarationData.Segments.Lookup(category, axles, grossMassRating, curbWeight); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + + +namespace TUGraz.VectoCore.InputData.Reader.Impl +{ + public class DeclarationModeVectoRunDataFactory : LoggingObject, IVectoRunDataFactory + { + private static readonly object CyclesCacheLock = new object(); + + private static readonly Dictionary<MissionType, DrivingCycleData> CyclesCache = + new Dictionary<MissionType, DrivingCycleData>(); + + protected readonly IDeclarationInputDataProvider InputDataProvider; + + protected IDeclarationReport Report; + private DeclarationDataAdapter _dao; + private Segment _segment; + private DriverData _driverdata; + private AirdragData _airdragData; + private CombustionEngineData _engineData; + private AxleGearData _axlegearData; + private AngledriveData _angledriveData; + private GearboxData _gearboxData; + private RetarderData _retarderData; + private PTOData _ptoTransmissionData; + private PTOData _municipalPtoTransmissionData; + private Exception InitException; + + internal DeclarationModeVectoRunDataFactory(IDeclarationInputDataProvider dataProvider, IDeclarationReport report) + { + InputDataProvider = dataProvider; + Report = report; + + try { + Initialize(); + if (Report != null) { + InitializeReport(); + } + } catch (Exception e) { + InitException = e; + } + } + + private void Initialize() + { + _dao = new DeclarationDataAdapter(); + _segment = GetVehicleClassification(InputDataProvider.VehicleInputData.VehicleCategory, + InputDataProvider.VehicleInputData.AxleConfiguration, + InputDataProvider.VehicleInputData.GrossVehicleMassRating, InputDataProvider.VehicleInputData.CurbMassChassis); + _driverdata = _dao.CreateDriverData(InputDataProvider.DriverInputData); + _driverdata.AccelerationCurve = AccelerationCurveReader.ReadFromStream(_segment.AccelerationFile); + + var tempVehicle = _dao.CreateVehicleData(InputDataProvider.VehicleInputData, _segment.Missions.First(), + _segment.Missions.First().Loadings.First().Value, _segment.MunicipalBodyWeight); + _airdragData = _dao.CreateAirdragData(InputDataProvider.AirdragInputData, _segment.Missions.First(), _segment); + _engineData = _dao.CreateEngineData(InputDataProvider.EngineInputData, + InputDataProvider.VehicleInputData.EngineIdleSpeed, + InputDataProvider.GearboxInputData, InputDataProvider.VehicleInputData.TorqueLimits); + _axlegearData = _dao.CreateAxleGearData(InputDataProvider.AxleGearInputData, false); + _angledriveData = _dao.CreateAngledriveData(InputDataProvider.AngledriveInputData, false); + _gearboxData = _dao.CreateGearboxData(InputDataProvider.GearboxInputData, _engineData, _axlegearData.AxleGear.Ratio, + tempVehicle.DynamicTyreRadius, tempVehicle.VehicleCategory, false); + _retarderData = _dao.CreateRetarderData(InputDataProvider.RetarderInputData); + + _ptoTransmissionData = _dao.CreatePTOTransmissionData(InputDataProvider.PTOTransmissionInputData); + + _municipalPtoTransmissionData = CreateDefaultPTOData(); + } + + private void InitializeReport() + { + var powertrainConfig = new VectoRunData() { + VehicleData = + _dao.CreateVehicleData(InputDataProvider.VehicleInputData, _segment.Missions.First(), + _segment.Missions.First().Loadings.First().Value, _segment.MunicipalBodyWeight), + AirdragData = _airdragData, + EngineData = _engineData, + GearboxData = _gearboxData, + AxleGearData = _axlegearData, + Retarder = _retarderData, + Aux = _dao.CreateAuxiliaryData(InputDataProvider.AuxiliaryInputData(), _segment.Missions.First().MissionType, + _segment.VehicleClass), + InputDataHash = InputDataProvider.XMLHash + }; + Report.InitializeReport(powertrainConfig, _segment); + } + + public IEnumerable<VectoRunData> NextRun() + { + if (InitException != null) { + throw InitException; + } + + foreach (var mission in _segment.Missions) { + if (mission.MissionType.IsEMS() && + _engineData.RatedPowerDeclared.IsSmaller(DeclarationData.MinEnginePowerForEMS)) { + continue; + } + DrivingCycleData cycle; + lock (CyclesCacheLock) { + if (CyclesCache.ContainsKey(mission.MissionType)) { + cycle = CyclesCache[mission.MissionType]; + } else { + cycle = DrivingCycleDataReader.ReadFromStream(mission.CycleFile, CycleType.DistanceBased, "", false); + CyclesCache.Add(mission.MissionType, cycle); + } + } + foreach (var loading in mission.Loadings) { + var simulationRunData = new VectoRunData { + Loading = loading.Key, + VehicleData = + _dao.CreateVehicleData(InputDataProvider.VehicleInputData, mission, loading.Value, _segment.MunicipalBodyWeight), + AirdragData = _dao.CreateAirdragData(InputDataProvider.AirdragInputData, mission, _segment), + EngineData = _engineData.Copy(), + GearboxData = _gearboxData, + AxleGearData = _axlegearData, + AngledriveData = _angledriveData, + Aux = _dao.CreateAuxiliaryData(InputDataProvider.AuxiliaryInputData(), mission.MissionType, + _segment.VehicleClass), + Cycle = new DrivingCycleProxy(cycle, mission.MissionType.ToString()), + Retarder = _retarderData, + DriverData = _driverdata, + ExecutionMode = ExecutionMode.Declaration, + JobName = InputDataProvider.JobInputData().JobName, + ModFileSuffix = loading.Key.ToString(), + Report = Report, + Mission = mission, + PTO = mission.MissionType == MissionType.MunicipalUtility + ? _municipalPtoTransmissionData + : _ptoTransmissionData, + InputDataHash = InputDataProvider.XMLHash + }; + simulationRunData.EngineData.FuelConsumptionCorrectionFactor = DeclarationData.WHTCCorrection.Lookup( + mission.MissionType.GetNonEMSMissionType(), _engineData.WHTCRural, _engineData.WHTCUrban, _engineData.WHTCMotorway) * + _engineData.ColdHotCorrectionFactor; + simulationRunData.VehicleData.VehicleClass = _segment.VehicleClass; + yield return simulationRunData; + } + } + } + + private PTOData CreateDefaultPTOData() + { + return new PTOData() { + TransmissionType = DeclarationData.PTO.DefaultPTOTechnology, + LossMap = PTOIdleLossMapReader.ReadFromStream(RessourceHelper.ReadStream(DeclarationData.PTO.DefaultPTOIdleLosses)), + PTOCycle = + DrivingCycleDataReader.ReadFromStream(RessourceHelper.ReadStream(DeclarationData.PTO.DefaultPTOActivationCycle), + CycleType.PTO, "PTO", false) + }; + } + + internal Segment GetVehicleClassification(VehicleCategory category, AxleConfiguration axles, Kilogram grossMassRating, + Kilogram curbWeight) + { + return DeclarationData.Segments.Lookup(category, axles, grossMassRating, curbWeight); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs index 9a1a7935dbb04f8c4b24252b2334b0d3601559bb..dfcd0c3c747e29c04e293b8c6fff25400f979587 100644 --- a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs +++ b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs @@ -29,72 +29,72 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data; - -[assembly: InternalsVisibleTo("VectoCoreTest")] - -namespace TUGraz.VectoCore.InputData.Reader.Impl -{ - public class EngineeringModeVectoRunDataFactory : LoggingObject, IVectoRunDataFactory - { - private static readonly Dictionary<string, DrivingCycleData> CyclesCache = new Dictionary<string, DrivingCycleData>(); - - protected readonly IEngineeringInputDataProvider InputDataProvider; - - internal EngineeringModeVectoRunDataFactory(IEngineeringInputDataProvider dataProvider) - { - InputDataProvider = dataProvider; - } - - /// <summary> - /// Iterate over all cycles defined in the JobFile and create a container with all data required for creating a simulation run - /// </summary> - /// <returns>VectoRunData instance for initializing the powertrain.</returns> - public virtual IEnumerable<VectoRunData> NextRun() - { - var dao = new EngineeringDataAdapter(); - var driver = dao.CreateDriverData(InputDataProvider.DriverInputData); - var engineData = dao.CreateEngineData(InputDataProvider.EngineInputData, InputDataProvider.GearboxInputData, - InputDataProvider.VehicleInputData.TorqueLimits); - - var tempVehicle = dao.CreateVehicleData(InputDataProvider.VehicleInputData); - - var axlegearData = dao.CreateAxleGearData(InputDataProvider.AxleGearInputData, useEfficiencyFallback: true); - var gearboxData = dao.CreateGearboxData(InputDataProvider.GearboxInputData, engineData, axlegearData.AxleGear.Ratio, - tempVehicle.DynamicTyreRadius, useEfficiencyFallback: true); - var crossWindRequired = InputDataProvider.AirdragInputData.CrossWindCorrectionMode == - CrossWindCorrectionMode.VAirBetaLookupTable; - var angledriveData = dao.CreateAngledriveData(InputDataProvider.AngledriveInputData, useEfficiencyFallback: true); - var ptoTransmissionData = dao.CreatePTOTransmissionData(InputDataProvider.PTOTransmissionInputData); - - return InputDataProvider.JobInputData().Cycles.Select(cycle => { - var drivingCycle = CyclesCache.ContainsKey(cycle.CycleData.Source) - ? CyclesCache[cycle.CycleData.Source] - : DrivingCycleDataReader.ReadFromDataTable(cycle.CycleData, cycle.Name, crossWindRequired); - return new VectoRunData { - JobName = InputDataProvider.JobInputData().JobName, - EngineData = engineData, - GearboxData = gearboxData, - AxleGearData = axlegearData, - AngledriveData = angledriveData, - VehicleData = dao.CreateVehicleData(InputDataProvider.VehicleInputData), - AirdragData = dao.CreateAirdragData(InputDataProvider.AirdragInputData, InputDataProvider.VehicleInputData), - DriverData = driver, - Aux = dao.CreateAuxiliaryData(InputDataProvider.AuxiliaryInputData()), - AdvancedAux = dao.CreateAdvancedAuxData(InputDataProvider.AuxiliaryInputData()), - Retarder = dao.CreateRetarderData(InputDataProvider.RetarderInputData), - PTO = ptoTransmissionData, - Cycle = new DrivingCycleProxy(drivingCycle, cycle.Name), - ExecutionMode = ExecutionMode.Engineering - }; - }); - } - } +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data; + +[assembly: InternalsVisibleTo("VectoCoreTest")] + +namespace TUGraz.VectoCore.InputData.Reader.Impl +{ + public class EngineeringModeVectoRunDataFactory : LoggingObject, IVectoRunDataFactory + { + private static readonly Dictionary<string, DrivingCycleData> CyclesCache = new Dictionary<string, DrivingCycleData>(); + + protected readonly IEngineeringInputDataProvider InputDataProvider; + + internal EngineeringModeVectoRunDataFactory(IEngineeringInputDataProvider dataProvider) + { + InputDataProvider = dataProvider; + } + + /// <summary> + /// Iterate over all cycles defined in the JobFile and create a container with all data required for creating a simulation run + /// </summary> + /// <returns>VectoRunData instance for initializing the powertrain.</returns> + public virtual IEnumerable<VectoRunData> NextRun() + { + var dao = new EngineeringDataAdapter(); + var driver = dao.CreateDriverData(InputDataProvider.DriverInputData); + var engineData = dao.CreateEngineData(InputDataProvider.EngineInputData, InputDataProvider.GearboxInputData, + InputDataProvider.VehicleInputData.TorqueLimits); + + var tempVehicle = dao.CreateVehicleData(InputDataProvider.VehicleInputData); + + var axlegearData = dao.CreateAxleGearData(InputDataProvider.AxleGearInputData, useEfficiencyFallback: true); + var gearboxData = dao.CreateGearboxData(InputDataProvider.GearboxInputData, engineData, axlegearData.AxleGear.Ratio, + tempVehicle.DynamicTyreRadius,tempVehicle.VehicleCategory, useEfficiencyFallback: true); + var crossWindRequired = InputDataProvider.AirdragInputData.CrossWindCorrectionMode == + CrossWindCorrectionMode.VAirBetaLookupTable; + var angledriveData = dao.CreateAngledriveData(InputDataProvider.AngledriveInputData, useEfficiencyFallback: true); + var ptoTransmissionData = dao.CreatePTOTransmissionData(InputDataProvider.PTOTransmissionInputData); + + return InputDataProvider.JobInputData().Cycles.Select(cycle => { + var drivingCycle = CyclesCache.ContainsKey(cycle.CycleData.Source) + ? CyclesCache[cycle.CycleData.Source] + : DrivingCycleDataReader.ReadFromDataTable(cycle.CycleData, cycle.Name, crossWindRequired); + return new VectoRunData { + JobName = InputDataProvider.JobInputData().JobName, + EngineData = engineData, + GearboxData = gearboxData, + AxleGearData = axlegearData, + AngledriveData = angledriveData, + VehicleData = dao.CreateVehicleData(InputDataProvider.VehicleInputData), + AirdragData = dao.CreateAirdragData(InputDataProvider.AirdragInputData, InputDataProvider.VehicleInputData), + DriverData = driver, + Aux = dao.CreateAuxiliaryData(InputDataProvider.AuxiliaryInputData()), + AdvancedAux = dao.CreateAdvancedAuxData(InputDataProvider.AuxiliaryInputData()), + Retarder = dao.CreateRetarderData(InputDataProvider.RetarderInputData), + PTO = ptoTransmissionData, + Cycle = new DrivingCycleProxy(drivingCycle, cycle.Name), + ExecutionMode = ExecutionMode.Engineering + }; + }); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs index 25b74b9bef713ecce1e6622284c721da5e8a4819..2f4f41999a2b25a96fbde71eba1faa5e8b4f8f99 100644 --- a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs +++ b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs @@ -175,7 +175,10 @@ namespace TUGraz.VectoCore.Models.Declaration public static readonly MeterPerSquareSecond UpshiftMinAcceleration = 0.1.SI<MeterPerSquareSecond>(); //public static readonly PerSecond TorqueConverterSpeedLimit = 1600.RPMtoRad(); - public static readonly double TorqueConverterSecondGearThreshold = 1.8; + public static double TorqueConverterSecondGearThreshold(VehicleCategory category) + { + return category.IsTruck() ? 1.8 : 1.85; + } public static readonly Second PowershiftShiftTime = 0.8.SI<Second>(); diff --git a/VectoCore/VectoCore/Models/Declaration/Mission.cs b/VectoCore/VectoCore/Models/Declaration/Mission.cs index 2e1fac83d741e53777a232c965a96af38d1b904b..e0b15c2687297f5b417dfe312170a5adc512a945 100644 --- a/VectoCore/VectoCore/Models/Declaration/Mission.cs +++ b/VectoCore/VectoCore/Models/Declaration/Mission.cs @@ -29,79 +29,79 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.IO; -using TUGraz.VectoCommon.Utils; - -namespace TUGraz.VectoCore.Models.Declaration -{ - public enum LoadingType - { - FullLoading, - ReferenceLoad, - LowLoading, - EmptyLoading, - } - - public class Mission - { - public MissionType MissionType; - public string CrossWindCorrectionParameters; - public double[] AxleWeightDistribution; - - public Kilogram BodyCurbWeight; - - public Stream CycleFile; - - public List<MissionTrailer> Trailer; - - public Kilogram MinLoad; - public Kilogram LowLoad; - public Kilogram RefLoad; - public Kilogram MaxLoad; - - public CubicMeter TotalCargoVolume; - - public Dictionary<LoadingType, Kilogram> Loadings - { - get { - return new Dictionary<LoadingType, Kilogram> { - { LoadingType.LowLoading, LowLoad }, - { LoadingType.ReferenceLoad, RefLoad }, - }; - } - } - } - - public class MissionTrailer - { - public TrailerType TrailerType; - public Kilogram TrailerCurbWeight; - public Kilogram TrailerGrossVehicleWeight; - public List<Wheels.Entry> TrailerWheels; - public double TrailerAxleWeightShare; - public SquareMeter DeltaCdA; - public CubicMeter CargoVolume; - } - - public enum TrailerType - { - //None, - T1, - T2, - ST1, - Dolly - } - - public static class TrailterTypeHelper - { - public static TrailerType Parse(string trailer) - { - if ("d".Equals(trailer, StringComparison.InvariantCultureIgnoreCase)) { - return TrailerType.Dolly; - } - return trailer.ParseEnum<TrailerType>(); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.Models.Declaration +{ + public enum LoadingType + { + FullLoading, + ReferenceLoad, + LowLoading, + EmptyLoading, + } + + public class Mission + { + public MissionType MissionType; + public string CrossWindCorrectionParameters; + public double[] AxleWeightDistribution; + + public Kilogram BodyCurbWeight; + + public Stream CycleFile; + + public List<MissionTrailer> Trailer; + + public Kilogram MinLoad; + public Kilogram LowLoad; + public Kilogram RefLoad; + public Kilogram MaxLoad; + + public CubicMeter TotalCargoVolume; + + public Dictionary<LoadingType, Kilogram> Loadings + { + get { + return new Dictionary<LoadingType, Kilogram> { + { LoadingType.LowLoading, LowLoad }, + { LoadingType.ReferenceLoad, RefLoad }, + }; + } + } + } + + public class MissionTrailer + { + public TrailerType TrailerType; + public Kilogram TrailerCurbWeight; + public Kilogram TrailerGrossVehicleWeight; + public List<Wheels.Entry> TrailerWheels; + public double TrailerAxleWeightShare; + public SquareMeter DeltaCdA; + public CubicMeter CargoVolume; + } + + public enum TrailerType + { + //None, + T1, + T2, + ST1, + Dolly + } + + public static class TrailterTypeHelper + { + public static TrailerType Parse(string trailer) + { + if ("d".Equals(trailer, StringComparison.InvariantCultureIgnoreCase)) { + return TrailerType.Dolly; + } + return trailer.ParseEnum<TrailerType>(); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Declaration/Segment.cs b/VectoCore/VectoCore/Models/Declaration/Segment.cs index 16abc25895037280bf41566fa923085da223b0e7..aa0627c1736abbd73aa7e080d42a234e0c493a4c 100644 --- a/VectoCore/VectoCore/Models/Declaration/Segment.cs +++ b/VectoCore/VectoCore/Models/Declaration/Segment.cs @@ -29,38 +29,38 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.IO; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; - -namespace TUGraz.VectoCore.Models.Declaration -{ - public class Segment - { - public VehicleClass VehicleClass { get; internal set; } - - public VehicleCategory VehicleCategory { get; set; } - - public AxleConfiguration AxleConfiguration { get; set; } - - public Kilogram GrossVehicleWeightMin { get; set; } - - public Kilogram GrossVehicleWeightMax { get; set; } - - public Kilogram GrossVehicleMassRating { get; set; } - - public Stream AccelerationFile { get; internal set; } - - public Mission[] Missions { get; internal set; } - - public Meter VehicleHeight { get; internal set; } - - public MeterPerSecond DesignSpeed { get; internal set; } - - public SquareMeter CdADefault { get; internal set; } - - public SquareMeter CdAConstruction { get; internal set; } - - public Kilogram MunicipalBodyWeight { get; internal set; } - } +using System.IO; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.Models.Declaration +{ + public class Segment + { + public VehicleClass VehicleClass { get; internal set; } + + public VehicleCategory VehicleCategory { get; set; } + + public AxleConfiguration AxleConfiguration { get; set; } + + public Kilogram GrossVehicleWeightMin { get; set; } + + public Kilogram GrossVehicleWeightMax { get; set; } + + public Kilogram GrossVehicleMassRating { get; set; } + + public Stream AccelerationFile { get; internal set; } + + public Mission[] Missions { get; internal set; } + + public Meter VehicleHeight { get; internal set; } + + public MeterPerSecond DesignSpeed { get; internal set; } + + public SquareMeter CdADefault { get; internal set; } + + public SquareMeter CdAConstruction { get; internal set; } + + public Kilogram MunicipalBodyWeight { get; internal set; } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Declaration/Segments.cs b/VectoCore/VectoCore/Models/Declaration/Segments.cs index 73227147dccd376e8732826952b61774dfac6bf4..f070c9e29b1c41c2d2131dc48e2165dbcc551461 100644 --- a/VectoCore/VectoCore/Models/Declaration/Segments.cs +++ b/VectoCore/VectoCore/Models/Declaration/Segments.cs @@ -29,269 +29,279 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.Declaration -{ - public sealed class Segments : LookupData<VehicleCategory, AxleConfiguration, Kilogram, Kilogram, Segment> - { - private DataTable _segmentTable; - - protected override string ResourceId - { - get { return DeclarationData.DeclarationDataResourcePrefix + ".SegmentTable.csv"; } - } - - protected override string ErrorMessage - { - get { - return - "ERROR: Could not find the declaration segment for vehicle. Category: {0}, AxleConfiguration: {1}, GrossVehicleWeight: {2}"; - } - } - - protected override void ParseData(DataTable table) - { - _segmentTable = table.Copy(); - } - - public override Segment Lookup(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, - Kilogram grossVehicleMassRating, Kilogram curbWeight) - { - return Lookup(vehicleCategory, axleConfiguration, grossVehicleMassRating, curbWeight, false); - } - - public Segment Lookup(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, - Kilogram grossVehicleMassRating, Kilogram curbWeight, bool considerInvalid) - { - if (grossVehicleMassRating == null || grossVehicleMassRating < 7.5.SI().Ton) { - throw new VectoException("Gross vehicle mass must be greater than 7.5 tons"); - } - - var row = GetSegmentDataRow(vehicleCategory, axleConfiguration, grossVehicleMassRating, considerInvalid); - - var segment = new Segment { - GrossVehicleWeightMin = row.ParseDouble("gvw_min").SI().Ton.Cast<Kilogram>(), - GrossVehicleWeightMax = row.ParseDouble("gvw_max").SI().Ton.Cast<Kilogram>(), - VehicleCategory = vehicleCategory, - AxleConfiguration = axleConfiguration, - VehicleClass = VehicleClassHelper.Parse(row.Field<string>("hdvclass")), - AccelerationFile = - RessourceHelper.ReadStream(DeclarationData.DeclarationDataResourcePrefix + ".VACC." + - row.Field<string>(".vaccfile")), - Missions = CreateMissions(ref grossVehicleMassRating, curbWeight, row), - VehicleHeight = LookupHeight(vehicleCategory, axleConfiguration, grossVehicleMassRating), - DesignSpeed = row.ParseDouble("designspeed").KMPHtoMeterPerSecond(), - GrossVehicleMassRating = grossVehicleMassRating, - CdADefault = row.ParseDouble("cdxa_default").SI<SquareMeter>(), - CdAConstruction = string.IsNullOrEmpty(row["cdxa_construction"].ToString()) - ? null - : row.ParseDouble("cdxa_construction").SI<SquareMeter>(), - MunicipalBodyWeight = string.IsNullOrEmpty(row["bodyweight_municipalutility"].ToString()) - ? null - : row.ParseDouble("bodyweight_municipalutility").SI<Kilogram>() - }; - - return segment; - } - - private DataRow GetSegmentDataRow(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, - Kilogram grossVehicleMassRating, bool considerInvalid) - { - DataRow row; - try { - row = _segmentTable.AsEnumerable().First(r => { - var isValid = r.Field<string>("valid"); - var category = r.Field<string>("vehiclecategory"); - var axleConf = r.Field<string>("axleconf."); - var massMin = r.ParseDouble("gvw_min").SI().Ton; - var massMax = r.ParseDouble("gvw_max").SI().Ton; - return (considerInvalid || isValid == "1") - && category == vehicleCategory.ToString() - && axleConf == axleConfiguration.GetName() - // MK 2016-06-07: normally the next condition should be "mass > massMin", except for 7.5t where is should be ">=" - // in any case ">=" is also correct, because the segment table is sorted by weight. - && massMin <= grossVehicleMassRating && grossVehicleMassRating <= massMax; - }); - } catch (InvalidOperationException e) { - var errorMessage = string.Format(ErrorMessage, vehicleCategory, axleConfiguration.GetName(), - grossVehicleMassRating); - Log.Fatal(errorMessage); - throw new VectoException(errorMessage, e); - } - return row; - } - - public Meter LookupHeight(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, - Kilogram grossVehicleMassRating) - { - var row = GetSegmentDataRow(vehicleCategory, axleConfiguration, grossVehicleMassRating, true); - - var vehicleHeight = row.ParseDouble("height").SI<Meter>(); - var vehicleClass = VehicleClassHelper.Parse(row.Field<string>("hdvclass")); - - if (vehicleClass == VehicleClass.Class9) { - // VECTO-471: for class 9 take similar height than rigid with same maximum gross vehicle weight (class 1, 2, 3 or 4). - var rigidGVWrow = _segmentTable.AsEnumerable().FirstOrDefault(r => { - var massMin = r.ParseDouble("gvw_min").SI().Ton; - var massMax = r.ParseDouble("gvw_max").SI().Ton; - return new[] { "1", "2", "3", "4" }.Contains(r.Field<string>("hdvclass")) - && massMin <= grossVehicleMassRating && grossVehicleMassRating <= massMax; - }); - if (rigidGVWrow != null) { - vehicleHeight = rigidGVWrow.ParseDouble("height").SI<Meter>(); - } - } - - return vehicleHeight; - } - - private static Mission[] CreateMissions(ref Kilogram grossVehicleWeight, Kilogram curbWeight, DataRow row) - { - var missionTypes = Enum.GetValues(typeof(MissionType)).Cast<MissionType>(); - var missions = new List<Mission>(); - foreach (var missionType in missionTypes.Where(m => row.Field<string>(m.ToString()) != "-")) { - var body = DeclarationData.StandardBodies.Lookup(row.Field<string>("body")); - - var maxGVW = Constants.SimulationSettings.MaximumGrossVehicleWeight; - var trailers = new List<MissionTrailer>(); - if (missionType.IsEMS()) { - maxGVW = Constants.SimulationSettings.MaximumGrossVehicleWeightEMS; - var trailerList = row.Field<string>("ems").Split('+'); - var trailerWeightShares = row.Field<string>("traileraxles" + GetMissionSuffix(missionType)).Split('/'); - if (trailerList.Length != trailerWeightShares.Length) { - throw new VectoException( - "Error in segmentation table: number of trailers and list of weight shares does not match!"); - } - trailers.AddRange( - trailerWeightShares.Select((t, i) => CreateTrailer(trailerList[i], t.ToDouble() / 100.0, i == 0))); - } else { - if (ShouldTrailerBeUsed(row, missionType)) { - var trailerValue = row.Field<string>("trailer"); - if (string.IsNullOrWhiteSpace(trailerValue)) { - throw new VectoException("Error in segmentation table: trailer weight share is defined but not trailer type!"); - } - trailers.Add(CreateTrailer(trailerValue, GetTrailerAxleWeightDistribution(row, missionType), true)); - } - } - - //var semiTrailerField = row.Field<string>("semitrailer"); - //var semiTrailer = !string.IsNullOrWhiteSpace(semiTrailerField) - // ? DeclarationData.StandardBodies.Lookup(semiTrailerField) - // : StandardBodies.Empty; - - //trailer += semiTrailer; - - // limit gvw to MaxGVW (40t) - var gvw = - VectoMath.Min( - grossVehicleWeight + trailers.Sum(t => t.TrailerGrossVehicleWeight).DefaultIfNull(0), - maxGVW); - var maxLoad = gvw - curbWeight - body.CurbWeight - - trailers.Sum(t => t.TrailerCurbWeight).DefaultIfNull(0); - - var payloads = row.Field<string>(missionType.ToString()).Split('/'); - Kilogram refLoad, lowLoad = 0.SI<Kilogram>(); - if (payloads.Length == 2) { - lowLoad = GetLoading(payloads[0], grossVehicleWeight, trailers, true); - refLoad = GetLoading(payloads[1], grossVehicleWeight, trailers, false); - } else { - refLoad = GetLoading(row.Field<string>(missionType.ToString()), grossVehicleWeight, trailers, false); - } - - refLoad = refLoad.LimitTo(0.SI<Kilogram>(), maxLoad); - lowLoad = lowLoad.LimitTo(0.SI<Kilogram>(), maxLoad); - - var mission = new Mission { - MissionType = missionType, - CrossWindCorrectionParameters = row.Field<string>("crosswindcorrection" + GetMissionSuffix(missionType, true)), - CycleFile = - RessourceHelper.ReadStream(DeclarationData.DeclarationDataResourcePrefix + ".MissionCycles." + - missionType.ToString().Replace("EMS", "") + - Constants.FileExtensions.CycleFile), - AxleWeightDistribution = GetAxleWeightDistribution(row, missionType), - BodyCurbWeight = body.CurbWeight, - Trailer = trailers, - MinLoad = 0.SI<Kilogram>(), - MaxLoad = maxLoad, - RefLoad = refLoad, - LowLoad = lowLoad, - TotalCargoVolume = body.CargoVolume + trailers.Sum(t => t.CargoVolume).DefaultIfNull(0), - }; - missions.Add(mission); - } - return missions.ToArray(); - } - - private static Kilogram GetLoading(string payloadStr, Kilogram grossVehicleWeight, - IEnumerable<MissionTrailer> trailers, bool lowLoading) - { - var refLoadValue = payloadStr.ToDouble(double.NaN); - if (double.IsNaN(refLoadValue)) { - return DeclarationData.GetPayloadForGrossVehicleWeight(grossVehicleWeight, payloadStr) + - trailers.Sum( - t => DeclarationData.GetPayloadForTrailerWeight(t.TrailerGrossVehicleWeight, t.TrailerCurbWeight, lowLoading)) - .DefaultIfNull(0); - } - return refLoadValue.SI<Kilogram>(); - } - - /// <summary> - /// Checks if a trailer should be used for the current missionType. - /// </summary> - private static bool ShouldTrailerBeUsed(DataRow row, MissionType missionType) - { - return !string.IsNullOrWhiteSpace(row.Field<string>("traileraxles" + GetMissionSuffix(missionType))); - } - - private static double GetTrailerAxleWeightDistribution(DataRow row, MissionType missionType) - { - var trailerAxles = - row.Field<string>("traileraxles" + GetMissionSuffix(missionType)); - if (!string.IsNullOrWhiteSpace(trailerAxles)) { - return trailerAxles.ToDouble() / 100.0; - } - return 0; - } - - private static double[] GetAxleWeightDistribution(DataRow row, MissionType missionType) - { - return - row.Field<string>("truckaxles" + GetMissionSuffix(missionType)) - .Split('/').ToDouble().Select(x => x / 100.0).ToArray(); - } - - private static string GetMissionSuffix(MissionType missionType, bool ignoreEMS = false) - { - return "-" + - (missionType.IsEMS() && ignoreEMS - ? "" - : (missionType.GetNonEMSMissionType() == MissionType.LongHaul ? "longhaul" : "other")) + - (missionType.IsEMS() ? "ems" : ""); - } - - private static MissionTrailer CreateTrailer(string trailerValue, double axleWeightShare, bool firstTrailer) - { - var trailerType = TrailterTypeHelper.Parse(trailerValue); - var trailer = DeclarationData.StandardBodies.Lookup(trailerType.ToString()); - return new MissionTrailer { - TrailerType = trailerType, - TrailerWheels = trailer.Wheels, - TrailerAxleWeightShare = axleWeightShare, - TrailerCurbWeight = trailer.CurbWeight, - TrailerGrossVehicleWeight = trailer.GrossVehicleWeight, - DeltaCdA = trailer.DeltaCrossWindArea[firstTrailer ? 0 : 1], - CargoVolume = trailer.CargoVolume - }; - } - } +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.Declaration +{ + public sealed class Segments : LookupData<VehicleCategory, AxleConfiguration, Kilogram, Kilogram, Segment> + { + private DataTable _segmentTable; + + protected override string ResourceId + { + get { return DeclarationData.DeclarationDataResourcePrefix + ".SegmentTable.csv"; } + } + + protected override string ErrorMessage + { + get { + return + "ERROR: Could not find the declaration segment for vehicle. Category: {0}, AxleConfiguration: {1}, GrossVehicleWeight: {2}"; + } + } + + protected override void ParseData(DataTable table) + { + _segmentTable = table.Copy(); + } + + public override Segment Lookup(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, + Kilogram grossVehicleMassRating, Kilogram curbWeight) + { + return Lookup(vehicleCategory, axleConfiguration, grossVehicleMassRating, curbWeight, false); + } + + public Segment Lookup(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, + Kilogram grossVehicleMassRating, Kilogram curbWeight, bool considerInvalid) + { + if (grossVehicleMassRating == null || grossVehicleMassRating < 7.5.SI().Ton) { + throw new VectoException("Gross vehicle mass must be greater than 7.5 tons"); + } + + var row = GetSegmentDataRow(vehicleCategory, axleConfiguration, grossVehicleMassRating, considerInvalid); + + var segment = new Segment { + GrossVehicleWeightMin = row.ParseDouble("gvw_min").SI().Ton.Cast<Kilogram>(), + GrossVehicleWeightMax = row.ParseDouble("gvw_max").SI().Ton.Cast<Kilogram>(), + VehicleCategory = vehicleCategory, + AxleConfiguration = axleConfiguration, + VehicleClass = VehicleClassHelper.Parse(row.Field<string>("hdvclass")), + AccelerationFile = + RessourceHelper.ReadStream(DeclarationData.DeclarationDataResourcePrefix + ".VACC." + + row.Field<string>(".vaccfile")), + Missions = CreateMissions(ref grossVehicleMassRating, curbWeight, row), + VehicleHeight = LookupHeight(vehicleCategory, axleConfiguration, grossVehicleMassRating), + DesignSpeed = row.ParseDouble("designspeed").KMPHtoMeterPerSecond(), + GrossVehicleMassRating = grossVehicleMassRating, + CdADefault = row.ParseDouble("cdxa_default").SI<SquareMeter>(), + CdAConstruction = string.IsNullOrEmpty(row["cdxa_construction"].ToString()) + ? null + : row.ParseDouble("cdxa_construction").SI<SquareMeter>(), + MunicipalBodyWeight = string.IsNullOrEmpty(row["bodyweight_municipalutility"].ToString()) + ? null + : row.ParseDouble("bodyweight_municipalutility").SI<Kilogram>() + }; + + return segment; + } + + private DataRow GetSegmentDataRow(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, + Kilogram grossVehicleMassRating, bool considerInvalid) + { + DataRow row; + try { + row = _segmentTable.AsEnumerable().First(r => { + var isValid = r.Field<string>("valid"); + var category = r.Field<string>("vehiclecategory"); + var axleConf = r.Field<string>("axleconf."); + var massMin = r.ParseDouble("gvw_min").SI().Ton; + var massMax = r.ParseDouble("gvw_max").SI().Ton; + return (considerInvalid || isValid == "1") + && category == vehicleCategory.ToString() + && axleConf == axleConfiguration.GetName() + // MK 2016-06-07: normally the next condition should be "mass > massMin", except for 7.5t where is should be ">=" + // in any case ">=" is also correct, because the segment table is sorted by weight. + && massMin <= grossVehicleMassRating && grossVehicleMassRating <= massMax; + }); + } catch (InvalidOperationException e) { + var errorMessage = string.Format(ErrorMessage, vehicleCategory, axleConfiguration.GetName(), + grossVehicleMassRating); + Log.Fatal(errorMessage); + throw new VectoException(errorMessage, e); + } + return row; + } + + public Meter LookupHeight(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, + Kilogram grossVehicleMassRating) + { + var row = GetSegmentDataRow(vehicleCategory, axleConfiguration, grossVehicleMassRating, true); + + var vehicleHeight = row.ParseDouble("height").SI<Meter>(); + var vehicleClass = VehicleClassHelper.Parse(row.Field<string>("hdvclass")); + + if (vehicleClass == VehicleClass.Class9) { + // VECTO-471: for class 9 take similar height than rigid with same maximum gross vehicle weight (class 1, 2, 3 or 4). + var rigidGVWrow = _segmentTable.AsEnumerable().FirstOrDefault(r => { + var massMin = r.ParseDouble("gvw_min").SI().Ton; + var massMax = r.ParseDouble("gvw_max").SI().Ton; + return new[] { "1", "2", "3", "4" }.Contains(r.Field<string>("hdvclass")) + && massMin <= grossVehicleMassRating && grossVehicleMassRating <= massMax; + }); + if (rigidGVWrow != null) { + vehicleHeight = rigidGVWrow.ParseDouble("height").SI<Meter>(); + } + } + + return vehicleHeight; + } + + /// <summary> + /// Looks up the default CdxA value for the cross wind correction. + /// </summary> + public SquareMeter LookupCdA(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, + Kilogram grossVehicleMassRating) + { + var row = GetSegmentDataRow(vehicleCategory, axleConfiguration, grossVehicleMassRating, true); + return row.SI<SquareMeter>("cdxa_default"); + } + + private static Mission[] CreateMissions(ref Kilogram grossVehicleWeight, Kilogram curbWeight, DataRow row) + { + var missionTypes = Enum.GetValues(typeof(MissionType)).Cast<MissionType>(); + var missions = new List<Mission>(); + foreach (var missionType in missionTypes.Where(m => row.Field<string>(m.ToString()) != "-")) { + var body = DeclarationData.StandardBodies.Lookup(row.Field<string>("body")); + + var maxGVW = Constants.SimulationSettings.MaximumGrossVehicleWeight; + var trailers = new List<MissionTrailer>(); + if (missionType.IsEMS()) { + maxGVW = Constants.SimulationSettings.MaximumGrossVehicleWeightEMS; + var trailerList = row.Field<string>("ems").Split('+'); + var trailerWeightShares = row.Field<string>("traileraxles" + GetMissionSuffix(missionType)).Split('/'); + if (trailerList.Length != trailerWeightShares.Length) { + throw new VectoException( + "Error in segmentation table: number of trailers and list of weight shares does not match!"); + } + trailers.AddRange( + trailerWeightShares.Select((t, i) => CreateTrailer(trailerList[i], t.ToDouble() / 100.0, i == 0))); + } else { + if (ShouldTrailerBeUsed(row, missionType)) { + var trailerValue = row.Field<string>("trailer"); + if (string.IsNullOrWhiteSpace(trailerValue)) { + throw new VectoException("Error in segmentation table: trailer weight share is defined but not trailer type!"); + } + trailers.Add(CreateTrailer(trailerValue, GetTrailerAxleWeightDistribution(row, missionType), true)); + } + } + + //var semiTrailerField = row.Field<string>("semitrailer"); + //var semiTrailer = !string.IsNullOrWhiteSpace(semiTrailerField) + // ? DeclarationData.StandardBodies.Lookup(semiTrailerField) + // : StandardBodies.Empty; + + //trailer += semiTrailer; + + // limit gvw to MaxGVW (40t) + var gvw = + VectoMath.Min( + grossVehicleWeight + trailers.Sum(t => t.TrailerGrossVehicleWeight).DefaultIfNull(0), + maxGVW); + var maxLoad = gvw - curbWeight - body.CurbWeight - + trailers.Sum(t => t.TrailerCurbWeight).DefaultIfNull(0); + + var payloads = row.Field<string>(missionType.ToString()).Split('/'); + Kilogram refLoad, lowLoad = 0.SI<Kilogram>(); + if (payloads.Length == 2) { + lowLoad = GetLoading(payloads[0], grossVehicleWeight, trailers, true); + refLoad = GetLoading(payloads[1], grossVehicleWeight, trailers, false); + } else { + refLoad = GetLoading(row.Field<string>(missionType.ToString()), grossVehicleWeight, trailers, false); + } + + refLoad = refLoad.LimitTo(0.SI<Kilogram>(), maxLoad); + lowLoad = lowLoad.LimitTo(0.SI<Kilogram>(), maxLoad); + + var mission = new Mission { + MissionType = missionType, + CrossWindCorrectionParameters = row.Field<string>("crosswindcorrection" + GetMissionSuffix(missionType, true)), + CycleFile = + RessourceHelper.ReadStream(DeclarationData.DeclarationDataResourcePrefix + ".MissionCycles." + + missionType.ToString().Replace("EMS", "") + + Constants.FileExtensions.CycleFile), + AxleWeightDistribution = GetAxleWeightDistribution(row, missionType), + BodyCurbWeight = body.CurbWeight, + Trailer = trailers, + MinLoad = 0.SI<Kilogram>(), + MaxLoad = maxLoad, + RefLoad = refLoad, + LowLoad = lowLoad, + TotalCargoVolume = body.CargoVolume + trailers.Sum(t => t.CargoVolume).DefaultIfNull(0), + }; + missions.Add(mission); + } + return missions.ToArray(); + } + + private static Kilogram GetLoading(string payloadStr, Kilogram grossVehicleWeight, + IEnumerable<MissionTrailer> trailers, bool lowLoading) + { + var refLoadValue = payloadStr.ToDouble(double.NaN); + if (double.IsNaN(refLoadValue)) { + return DeclarationData.GetPayloadForGrossVehicleWeight(grossVehicleWeight, payloadStr) + + trailers.Sum( + t => DeclarationData.GetPayloadForTrailerWeight(t.TrailerGrossVehicleWeight, t.TrailerCurbWeight, lowLoading)) + .DefaultIfNull(0); + } + return refLoadValue.SI<Kilogram>(); + } + + /// <summary> + /// Checks if a trailer should be used for the current missionType. + /// </summary> + private static bool ShouldTrailerBeUsed(DataRow row, MissionType missionType) + { + return !string.IsNullOrWhiteSpace(row.Field<string>("traileraxles" + GetMissionSuffix(missionType))); + } + + private static double GetTrailerAxleWeightDistribution(DataRow row, MissionType missionType) + { + var trailerAxles = + row.Field<string>("traileraxles" + GetMissionSuffix(missionType)); + if (!string.IsNullOrWhiteSpace(trailerAxles)) { + return trailerAxles.ToDouble() / 100.0; + } + return 0; + } + + private static double[] GetAxleWeightDistribution(DataRow row, MissionType missionType) + { + return + row.Field<string>("truckaxles" + GetMissionSuffix(missionType)) + .Split('/').ToDouble().Select(x => x / 100.0).ToArray(); + } + + private static string GetMissionSuffix(MissionType missionType, bool ignoreEMS = false) + { + return "-" + + (missionType.IsEMS() && ignoreEMS + ? "" + : (missionType.GetNonEMSMissionType() == MissionType.LongHaul ? "longhaul" : "other")) + + (missionType.IsEMS() ? "ems" : ""); + } + + private static MissionTrailer CreateTrailer(string trailerValue, double axleWeightShare, bool firstTrailer) + { + var trailerType = TrailterTypeHelper.Parse(trailerValue); + var trailer = DeclarationData.StandardBodies.Lookup(trailerType.ToString()); + return new MissionTrailer { + TrailerType = trailerType, + TrailerWheels = trailer.Wheels, + TrailerAxleWeightShare = axleWeightShare, + TrailerCurbWeight = trailer.CurbWeight, + TrailerGrossVehicleWeight = trailer.GrossVehicleWeight, + DeltaCdA = trailer.DeltaCrossWindArea[firstTrailer ? 0 : 1], + CargoVolume = trailer.CargoVolume + }; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs index d9368e83f6a6efb131d79b3a2e2217d3b32ddb95..9ffcefc470bfcdb0282dc8ca5c34e0426daf38fc 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs @@ -29,271 +29,271 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.SimulationComponent; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Impl; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; -using Wheels = TUGraz.VectoCore.Models.SimulationComponent.Impl.Wheels; - -namespace TUGraz.VectoCore.Models.Simulation.Impl -{ - /// <summary> - /// Provides Methods to build a simulator with a powertrain step by step. - /// </summary> - public class PowertrainBuilder - { - private readonly IModalDataContainer _modData; - private readonly WriteSumData _sumWriter; - - public PowertrainBuilder(IModalDataContainer modData, WriteSumData sumWriter = null) - { - if (modData == null) { - throw new VectoException("Modal Data Container can't be null"); - } - _modData = modData; - _sumWriter = sumWriter; - } - - public VehicleContainer Build(VectoRunData data) - { - switch (data.Cycle.CycleType) { - case CycleType.EngineOnly: - return BuildEngineOnly(data); - case CycleType.PWheel: - return BuildPWheel(data); - case CycleType.MeasuredSpeed: - return BuildMeasuredSpeed(data); - case CycleType.MeasuredSpeedGear: - return BuildMeasuredSpeedGear(data); - case CycleType.DistanceBased: - return BuildFullPowertrain(data); - default: - throw new VectoException("Powertrain Builder cannot build Powertrain for CycleType: {0}", data.Cycle.CycleType); - } - } - - private VehicleContainer BuildEngineOnly(VectoRunData data) - { - if (data.Cycle.CycleType != CycleType.EngineOnly) { - throw new VectoException("CycleType must be EngineOnly."); - } - - var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data }; - var cycle = new PowertrainDrivingCycle(container, data.Cycle); - - var directAux = new EngineAuxiliary(container); - directAux.AddCycle(Constants.Auxiliaries.Cycle); - container.ModalData.AddAuxiliary(Constants.Auxiliaries.Cycle); - var engine = new EngineOnlyCombustionEngine(container, data.EngineData); - engine.Connect(directAux.Port()); - - cycle.InPort().Connect(engine.OutPort()); - return container; - } - - private VehicleContainer BuildPWheel(VectoRunData data) - { - if (data.Cycle.CycleType != CycleType.PWheel) { - throw new VectoException("CycleType must be PWheel."); - } - - var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data }; - var gearbox = new CycleGearbox(container, data); - - // PWheelCycle --> AxleGear --> Clutch --> Engine <-- Aux - var powertrain = new PWheelCycle(container, data.Cycle, data.AxleGearData.AxleGear.Ratio, data.VehicleData, - gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio)) - .AddComponent(new AxleGear(container, data.AxleGearData)) - .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null) - .AddComponent(gearbox, data.Retarder, container) - .AddComponent(new Clutch(container, data.EngineData)); - var engine = new CombustionEngine(container, data.EngineData, pt1Disabled: true); - var idleController = GetIdleController(data.PTO, engine, container); - - powertrain.AddComponent(engine, idleController) - .AddAuxiliaries(container, data); - - return container; - } - - private VehicleContainer BuildMeasuredSpeed(VectoRunData data) - { - if (data.Cycle.CycleType != CycleType.MeasuredSpeed) { - throw new VectoException("CycleType must be MeasuredSpeed."); - } - - var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data }; - - // MeasuredSpeedDrivingCycle --> vehicle --> wheels --> brakes - // --> axleGear --> (retarder) --> GearBox --> (retarder) --> Clutch --> engine <-- Aux - var cycle = new MeasuredSpeedDrivingCycle(container, data.Cycle); - var powertrain = cycle - .AddComponent(new Vehicle(container, data.VehicleData, data.AirdragData)) - .AddComponent(new Wheels(container, data.VehicleData.DynamicTyreRadius, data.VehicleData.WheelsInertia)) - .AddComponent(new Brakes(container)) - .AddComponent(new AxleGear(container, data.AxleGearData)) - .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null) - .AddComponent(GetGearbox(container, data), data.Retarder, container); - if (data.GearboxData.Type.ManualTransmission()) { - powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData)); - } - - var engine = new CombustionEngine(container, data.EngineData); - var idleController = GetIdleController(data.PTO, engine, container); - - powertrain.AddComponent(engine, idleController) - .AddAuxiliaries(container, data); - _modData.HasTorqueConverter = data.GearboxData.Type.AutomaticTransmission(); - - return container; - } - - private VehicleContainer BuildMeasuredSpeedGear(VectoRunData data) - { - if (data.Cycle.CycleType != CycleType.MeasuredSpeedGear) { - throw new VectoException("CycleType must be MeasuredSpeed with Gear."); - } - - var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data }; - - // MeasuredSpeedDrivingCycle --> vehicle --> wheels --> brakes - // --> axleGear --> (retarder) --> CycleGearBox --> (retarder) --> CycleClutch --> engine <-- Aux - var powertrain = new MeasuredSpeedDrivingCycle(container, data.Cycle) - .AddComponent(new Vehicle(container, data.VehicleData, data.AirdragData)) - .AddComponent(new Wheels(container, data.VehicleData.DynamicTyreRadius, data.VehicleData.WheelsInertia)) - .AddComponent(new Brakes(container)) - .AddComponent(new AxleGear(container, data.AxleGearData)) - .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null) - .AddComponent(new CycleGearbox(container, data)); - if (data.GearboxData.Type.ManualTransmission()) { - powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData)); - } - powertrain.AddComponent(new CombustionEngine(container, data.EngineData)) - .AddAuxiliaries(container, data); - - _modData.HasTorqueConverter = data.GearboxData.Type.AutomaticTransmission(); - - return container; - } - - private VehicleContainer BuildFullPowertrain(VectoRunData data) - { - if (data.Cycle.CycleType != CycleType.DistanceBased) { - throw new VectoException("CycleType must be DistanceBased"); - } - - var container = new VehicleContainer(data.ExecutionMode, _modData, _sumWriter) { RunData = data }; - - // DistanceBasedDrivingCycle --> driver --> vehicle --> wheels - // --> axleGear --> (retarder) --> gearBox --> (retarder) --> clutch --> engine <-- Aux - var cycle = new DistanceBasedDrivingCycle(container, data.Cycle); - var powertrain = cycle.AddComponent(new Driver(container, data.DriverData, new DefaultDriverStrategy())) - .AddComponent(new Vehicle(container, data.VehicleData, data.AirdragData)) - .AddComponent(new Wheels(container, data.VehicleData.DynamicTyreRadius, data.VehicleData.WheelsInertia)) - .AddComponent(new Brakes(container)) - .AddComponent(new AxleGear(container, data.AxleGearData)) - .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null) - .AddComponent(GetGearbox(container, data), data.Retarder, container); - if (data.GearboxData.Type.ManualTransmission()) { - powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData)); - } - - var engine = new CombustionEngine(container, data.EngineData); - var idleController = GetIdleController(data.PTO, engine, container); - cycle.IdleController = idleController as IdleControllerSwitcher; - - powertrain.AddComponent(engine, idleController) - .AddAuxiliaries(container, data); - - _modData.HasTorqueConverter = data.GearboxData.Type.AutomaticTransmission(); - - return container; - } - - private static IIdleController GetIdleController(PTOData pto, ICombustionEngine engine, IVehicleContainer container) - { - var controller = engine.IdleController; - - if (pto != null && pto.PTOCycle != null) { - var ptoController = new PTOCycleController(container, pto.PTOCycle); - controller = new IdleControllerSwitcher(engine.IdleController, ptoController); - } - - return controller; - } - - internal static IAuxInProvider CreateAdvancedAuxiliaries(VectoRunData data, IVehicleContainer container) - { - var conventionalAux = CreateAuxiliaries(data, container); - var busAux = new BusAuxiliariesAdapter(container, data.AdvancedAux.AdvancedAuxiliaryFilePath, data.Cycle.Name, - data.VehicleData.TotalVehicleWeight, data.EngineData.ConsumptionMap, data.EngineData.IdleSpeed, conventionalAux); - return busAux; - } - - internal static EngineAuxiliary CreateAuxiliaries(VectoRunData data, IVehicleContainer container) - { - var aux = new EngineAuxiliary(container); - foreach (var auxData in data.Aux) { - // id's in upper case - var id = auxData.ID.ToUpper(); - - switch (auxData.DemandType) { - case AuxiliaryDemandType.Constant: - aux.AddConstant(id, auxData.PowerDemand); - break; - case AuxiliaryDemandType.Direct: - aux.AddCycle(id); - break; - case AuxiliaryDemandType.Mapping: - aux.AddMapping(id, auxData.Data); - break; - default: - throw new ArgumentOutOfRangeException("AuxiliaryDemandType", auxData.DemandType.ToString()); - } - container.ModalData.AddAuxiliary(id); - } - - if (data.PTO != null) { - aux.AddConstant(Constants.Auxiliaries.IDs.PTOTransmission, - DeclarationData.PTOTransmission.Lookup(data.PTO.TransmissionType)); - container.ModalData.AddAuxiliary(Constants.Auxiliaries.IDs.PTOTransmission, - Constants.Auxiliaries.PowerPrefix + Constants.Auxiliaries.IDs.PTOTransmission); - - aux.Add(Constants.Auxiliaries.IDs.PTOConsumer, - n => container.PTOActive ? null : data.PTO.LossMap.GetTorqueLoss(n) * n); - container.ModalData.AddAuxiliary(Constants.Auxiliaries.IDs.PTOConsumer, - Constants.Auxiliaries.PowerPrefix + Constants.Auxiliaries.IDs.PTOConsumer); - } - - return aux; - } - - private static IGearbox GetGearbox(IVehicleContainer container, VectoRunData runData) - { - IShiftStrategy strategy; - switch (runData.GearboxData.Type) { - case GearboxType.AMT: - strategy = new AMTShiftStrategy(runData, container); - break; - case GearboxType.MT: - strategy = new MTShiftStrategy(runData, container); - break; - case GearboxType.ATPowerSplit: - case GearboxType.ATSerial: - strategy = new ATShiftStrategy(runData.GearboxData, container); - return new ATGearbox(container, strategy, runData); - default: - throw new ArgumentOutOfRangeException("Unknown Gearbox Type", runData.GearboxData.Type.ToString()); - } - return new Gearbox(container, strategy, runData); - } - } +using System; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; +using Wheels = TUGraz.VectoCore.Models.SimulationComponent.Impl.Wheels; + +namespace TUGraz.VectoCore.Models.Simulation.Impl +{ + /// <summary> + /// Provides Methods to build a simulator with a powertrain step by step. + /// </summary> + public class PowertrainBuilder + { + private readonly IModalDataContainer _modData; + private readonly WriteSumData _sumWriter; + + public PowertrainBuilder(IModalDataContainer modData, WriteSumData sumWriter = null) + { + if (modData == null) { + throw new VectoException("Modal Data Container can't be null"); + } + _modData = modData; + _sumWriter = sumWriter; + } + + public VehicleContainer Build(VectoRunData data) + { + switch (data.Cycle.CycleType) { + case CycleType.EngineOnly: + return BuildEngineOnly(data); + case CycleType.PWheel: + return BuildPWheel(data); + case CycleType.MeasuredSpeed: + return BuildMeasuredSpeed(data); + case CycleType.MeasuredSpeedGear: + return BuildMeasuredSpeedGear(data); + case CycleType.DistanceBased: + return BuildFullPowertrain(data); + default: + throw new VectoException("Powertrain Builder cannot build Powertrain for CycleType: {0}", data.Cycle.CycleType); + } + } + + private VehicleContainer BuildEngineOnly(VectoRunData data) + { + if (data.Cycle.CycleType != CycleType.EngineOnly) { + throw new VectoException("CycleType must be EngineOnly."); + } + + var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data }; + var cycle = new PowertrainDrivingCycle(container, data.Cycle); + + var directAux = new EngineAuxiliary(container); + directAux.AddCycle(Constants.Auxiliaries.Cycle); + container.ModalData.AddAuxiliary(Constants.Auxiliaries.Cycle); + var engine = new EngineOnlyCombustionEngine(container, data.EngineData); + engine.Connect(directAux.Port()); + + cycle.InPort().Connect(engine.OutPort()); + return container; + } + + private VehicleContainer BuildPWheel(VectoRunData data) + { + if (data.Cycle.CycleType != CycleType.PWheel) { + throw new VectoException("CycleType must be PWheel."); + } + + var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data }; + var gearbox = new CycleGearbox(container, data); + + // PWheelCycle --> AxleGear --> Clutch --> Engine <-- Aux + var powertrain = new PWheelCycle(container, data.Cycle, data.AxleGearData.AxleGear.Ratio, data.VehicleData, + gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio)) + .AddComponent(new AxleGear(container, data.AxleGearData)) + .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null) + .AddComponent(gearbox, data.Retarder, container) + .AddComponent(new Clutch(container, data.EngineData)); + var engine = new CombustionEngine(container, data.EngineData, pt1Disabled: true); + var idleController = GetIdleController(data.PTO, engine, container); + + powertrain.AddComponent(engine, idleController) + .AddAuxiliaries(container, data); + + return container; + } + + private VehicleContainer BuildMeasuredSpeed(VectoRunData data) + { + if (data.Cycle.CycleType != CycleType.MeasuredSpeed) { + throw new VectoException("CycleType must be MeasuredSpeed."); + } + + var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data }; + + // MeasuredSpeedDrivingCycle --> vehicle --> wheels --> brakes + // --> axleGear --> (retarder) --> GearBox --> (retarder) --> Clutch --> engine <-- Aux + var cycle = new MeasuredSpeedDrivingCycle(container, data.Cycle); + var powertrain = cycle + .AddComponent(new Vehicle(container, data.VehicleData, data.AirdragData)) + .AddComponent(new Wheels(container, data.VehicleData.DynamicTyreRadius, data.VehicleData.WheelsInertia)) + .AddComponent(new Brakes(container)) + .AddComponent(new AxleGear(container, data.AxleGearData)) + .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null) + .AddComponent(GetGearbox(container, data), data.Retarder, container); + if (data.GearboxData.Type.ManualTransmission()) { + powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData)); + } + + var engine = new CombustionEngine(container, data.EngineData); + var idleController = GetIdleController(data.PTO, engine, container); + + powertrain.AddComponent(engine, idleController) + .AddAuxiliaries(container, data); + _modData.HasTorqueConverter = data.GearboxData.Type.AutomaticTransmission(); + + return container; + } + + private VehicleContainer BuildMeasuredSpeedGear(VectoRunData data) + { + if (data.Cycle.CycleType != CycleType.MeasuredSpeedGear) { + throw new VectoException("CycleType must be MeasuredSpeed with Gear."); + } + + var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data }; + + // MeasuredSpeedDrivingCycle --> vehicle --> wheels --> brakes + // --> axleGear --> (retarder) --> CycleGearBox --> (retarder) --> CycleClutch --> engine <-- Aux + var powertrain = new MeasuredSpeedDrivingCycle(container, data.Cycle) + .AddComponent(new Vehicle(container, data.VehicleData, data.AirdragData)) + .AddComponent(new Wheels(container, data.VehicleData.DynamicTyreRadius, data.VehicleData.WheelsInertia)) + .AddComponent(new Brakes(container)) + .AddComponent(new AxleGear(container, data.AxleGearData)) + .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null) + .AddComponent(new CycleGearbox(container, data)); + if (data.GearboxData.Type.ManualTransmission()) { + powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData)); + } + powertrain.AddComponent(new CombustionEngine(container, data.EngineData)) + .AddAuxiliaries(container, data); + + _modData.HasTorqueConverter = data.GearboxData.Type.AutomaticTransmission(); + + return container; + } + + private VehicleContainer BuildFullPowertrain(VectoRunData data) + { + if (data.Cycle.CycleType != CycleType.DistanceBased) { + throw new VectoException("CycleType must be DistanceBased"); + } + + var container = new VehicleContainer(data.ExecutionMode, _modData, _sumWriter) { RunData = data }; + + // DistanceBasedDrivingCycle --> driver --> vehicle --> wheels + // --> axleGear --> (retarder) --> gearBox --> (retarder) --> clutch --> engine <-- Aux + var cycle = new DistanceBasedDrivingCycle(container, data.Cycle); + var powertrain = cycle.AddComponent(new Driver(container, data.DriverData, new DefaultDriverStrategy())) + .AddComponent(new Vehicle(container, data.VehicleData, data.AirdragData)) + .AddComponent(new Wheels(container, data.VehicleData.DynamicTyreRadius, data.VehicleData.WheelsInertia)) + .AddComponent(new Brakes(container)) + .AddComponent(new AxleGear(container, data.AxleGearData)) + .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null) + .AddComponent(GetGearbox(container, data), data.Retarder, container); + if (data.GearboxData.Type.ManualTransmission()) { + powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData)); + } + + var engine = new CombustionEngine(container, data.EngineData); + var idleController = GetIdleController(data.PTO, engine, container); + cycle.IdleController = idleController as IdleControllerSwitcher; + + powertrain.AddComponent(engine, idleController) + .AddAuxiliaries(container, data); + + _modData.HasTorqueConverter = data.GearboxData.Type.AutomaticTransmission(); + + return container; + } + + private static IIdleController GetIdleController(PTOData pto, ICombustionEngine engine, IVehicleContainer container) + { + var controller = engine.IdleController; + + if (pto != null && pto.PTOCycle != null) { + var ptoController = new PTOCycleController(container, pto.PTOCycle); + controller = new IdleControllerSwitcher(engine.IdleController, ptoController); + } + + return controller; + } + + internal static IAuxInProvider CreateAdvancedAuxiliaries(VectoRunData data, IVehicleContainer container) + { + var conventionalAux = CreateAuxiliaries(data, container); + var busAux = new BusAuxiliariesAdapter(container, data.AdvancedAux.AdvancedAuxiliaryFilePath, data.Cycle.Name, + data.VehicleData.TotalVehicleWeight, data.EngineData.ConsumptionMap, data.EngineData.IdleSpeed, conventionalAux); + return busAux; + } + + internal static EngineAuxiliary CreateAuxiliaries(VectoRunData data, IVehicleContainer container) + { + var aux = new EngineAuxiliary(container); + foreach (var auxData in data.Aux) { + // id's in upper case + var id = auxData.ID.ToUpper(); + + switch (auxData.DemandType) { + case AuxiliaryDemandType.Constant: + aux.AddConstant(id, auxData.PowerDemand); + break; + case AuxiliaryDemandType.Direct: + aux.AddCycle(id); + break; + case AuxiliaryDemandType.Mapping: + aux.AddMapping(id, auxData.Data); + break; + default: + throw new ArgumentOutOfRangeException("AuxiliaryDemandType", auxData.DemandType.ToString()); + } + container.ModalData.AddAuxiliary(id); + } + + if (data.PTO != null) { + aux.AddConstant(Constants.Auxiliaries.IDs.PTOTransmission, + DeclarationData.PTOTransmission.Lookup(data.PTO.TransmissionType)); + container.ModalData.AddAuxiliary(Constants.Auxiliaries.IDs.PTOTransmission, + Constants.Auxiliaries.PowerPrefix + Constants.Auxiliaries.IDs.PTOTransmission); + + aux.Add(Constants.Auxiliaries.IDs.PTOConsumer, + n => container.PTOActive ? null : data.PTO.LossMap.GetTorqueLoss(n) * n); + container.ModalData.AddAuxiliary(Constants.Auxiliaries.IDs.PTOConsumer, + Constants.Auxiliaries.PowerPrefix + Constants.Auxiliaries.IDs.PTOConsumer); + } + + return aux; + } + + private static IGearbox GetGearbox(IVehicleContainer container, VectoRunData runData) + { + IShiftStrategy strategy; + switch (runData.GearboxData.Type) { + case GearboxType.AMT: + strategy = new AMTShiftStrategy(runData, container); + break; + case GearboxType.MT: + strategy = new MTShiftStrategy(runData, container); + break; + case GearboxType.ATPowerSplit: + case GearboxType.ATSerial: + strategy = new ATShiftStrategy(runData.GearboxData, container); + return new ATGearbox(container, strategy, runData); + default: + throw new ArgumentOutOfRangeException("Unknown Gearbox Type", runData.GearboxData.Type.ToString()); + } + return new Gearbox(container, strategy, runData); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/VehicleData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/VehicleData.cs index 95244bc8ab9e073843affa71a204f57cb5a67154..1d688b2e734e64862d201e3aba535b0a44a9427e 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/VehicleData.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/VehicleData.cs @@ -29,254 +29,262 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Data -{ - public class AirdragData : SimulationComponentData - { - public CrossWindCorrectionMode CrossWindCorrectionMode { get; set; } - - [Required, ValidateObject] - public ICrossWindCorrection CrossWindCorrectionCurve { get; internal set; } - - public SquareMeter DeclaredAirdragArea { get; internal set; } - } - - /// <summary> - /// Data Class for the Vehicle - /// </summary> - [CustomValidation(typeof(VehicleData), "ValidateVehicleData")] - public class VehicleData : SimulationComponentData - { - public string VIN { get; internal set; } - - public string LegislativeClass { get; internal set; } - - public VehicleCategory VehicleCategory { get; internal set; } - - public VehicleClass VehicleClass { get; internal set; } - - public AxleConfiguration AxleConfiguration { get; internal set; } - - public string ManufacturerAddress { get; internal set; } - - - [Required, ValidateObject] private List<Axle> _axleData; - - private KilogramSquareMeter _wheelsInertia; - private double? _totalRollResistanceCoefficient; - private double? _rollResistanceCoefficientWithoutTrailer; - - public List<Axle> AxleData - { - get { return _axleData; } - internal set { - _axleData = value; - _wheelsInertia = null; - _totalRollResistanceCoefficient = null; - } - } - - /// <summary> - /// The Curb Weight of the vehicle - /// (+ Curb Weight of Standard-Body if it has one) - /// (+ Curb Weight of Trailer if it has one) - /// </summary> - [Required, SIRange(500, 40000, emsMission: false), - SIRange(0, 60000, emsMission: true)] - public Kilogram CurbWeight { get; internal set; } - - /// <summary> - /// Curb Weight of Standard-Body (if it has one) - /// + Curb Weight of Trailer (if it has one) - /// </summary> - public Kilogram BodyAndTrailerWeight { get; internal set; } - - [Required, SIRange(0, 40000, emsMission: false), - SIRange(0, 60000, emsMission: true)] - public Kilogram Loading { get; internal set; } - - [SIRange(0, 500)] - public CubicMeter CargoVolume { get; internal set; } - - /// <summary> - /// The Gross Vehicle Weight of the Vehicle. - /// </summary> - [Required, - SIRange(3500, 40000, ExecutionMode.Declaration, emsMission: false), - SIRange(0, 60000, ExecutionMode.Declaration, emsMission: true), - SIRange(0, 1000000, ExecutionMode.Engineering)] - public Kilogram GrossVehicleWeight { get; internal set; } - - /// <summary> - /// The Gross Vehicle Weight of the Trailer (if the vehicle has one). - /// </summary> - [Required, SIRange(0, 40000, emsMission: false), - SIRange(0, 60000, emsMission: true)] - public Kilogram TrailerGrossVehicleWeight { get; internal set; } - - [Required, SIRange(0.1, 0.7)] - public Meter DynamicTyreRadius { get; internal set; } - - public KilogramSquareMeter WheelsInertia - { - get { - if (_wheelsInertia == null) { - ComputeRollResistanceAndReducedMassWheels(); - } - return _wheelsInertia; - } - internal set { _wheelsInertia = value; } - } - - //[Required, SIRange(0, 1E12)] - public double TotalRollResistanceCoefficient - { - get { - if (_totalRollResistanceCoefficient == null) { - ComputeRollResistanceAndReducedMassWheels(); - } - return _totalRollResistanceCoefficient.GetValueOrDefault(); - } - protected internal set { _totalRollResistanceCoefficient = value; } - } - - public double RollResistanceCoefficientWithoutTrailer - { - get { - if (_rollResistanceCoefficientWithoutTrailer == null) { - ComputeRollResistanceAndReducedMassWheels(); - } - return _rollResistanceCoefficientWithoutTrailer.GetValueOrDefault(); - } - protected internal set { _rollResistanceCoefficientWithoutTrailer = value; } - } - - public Kilogram TotalVehicleWeight - { - get { - var retVal = 0.0.SI<Kilogram>(); - retVal += CurbWeight ?? 0.SI<Kilogram>(); - retVal += BodyAndTrailerWeight ?? 0.SI<Kilogram>(); - retVal += Loading ?? 0.SI<Kilogram>(); - return retVal; - } - } - - public Kilogram TotalCurbWeight - { - get { return (CurbWeight ?? 0.SI<Kilogram>()) + (BodyAndTrailerWeight ?? 0.SI<Kilogram>()); } - } - - - protected void ComputeRollResistanceAndReducedMassWheels() - { - if (TotalVehicleWeight == 0.SI<Kilogram>()) { - throw new VectoException("Total vehicle weight must be greater than 0! Set CurbWeight and Loading before!"); - } - if (DynamicTyreRadius == null) { - throw new VectoException("Dynamic tyre radius must be set before axles!"); - } - - var g = Physics.GravityAccelleration; - - var rrc = 0.0.SI<Scalar>(); - var rrcVehicle = 0.0.SI<Scalar>(); - - var wheelsInertia = 0.0.SI<KilogramSquareMeter>(); - var vehicleWeightShare = 0.0; - foreach (var axle in _axleData) { - if (axle.AxleWeightShare.IsEqual(0, 1e-12)) { - continue; - } - var nrWheels = axle.TwinTyres ? 4 : 2; - var baseValue = (axle.AxleWeightShare * TotalVehicleWeight * g / axle.TyreTestLoad / nrWheels).Value(); - - var rrcShare = axle.AxleWeightShare * axle.RollResistanceCoefficient * - Math.Pow(baseValue, Physics.RollResistanceExponent - 1); - - if (axle.AxleType != AxleType.Trailer) { - rrcVehicle += rrcShare; - vehicleWeightShare += axle.AxleWeightShare; - } - rrc += rrcShare; - wheelsInertia += nrWheels * axle.Inertia; - } - RollResistanceCoefficientWithoutTrailer = rrcVehicle / vehicleWeightShare; - TotalRollResistanceCoefficient = rrc; - WheelsInertia = wheelsInertia; - } - - - // ReSharper disable once UnusedMember.Global -- used via Validation - public static ValidationResult ValidateVehicleData(VehicleData vehicleData, ValidationContext validationContext) - { - var mode = GetExecutionMode(validationContext); - var emsCycle = GetEmsMode(validationContext); - - if (vehicleData.AxleData.Count < 1) { - return new ValidationResult("At least two axles need to be specified"); - } - - var weightShareSum = vehicleData.AxleData.Sum(axle => axle.AxleWeightShare); - if (!weightShareSum.IsEqual(1.0, 1E-10)) { - return new ValidationResult( - string.Format("Sum of axle weight share is not 1! sum: {0}, difference: {1}", - weightShareSum, 1 - weightShareSum)); - } - for (var i = 0; i < vehicleData.AxleData.Count; i++) { - if (vehicleData.AxleData[i].TyreTestLoad.IsSmallerOrEqual(0)) { - return new ValidationResult(string.Format("Tyre test load (FzISO) for axle {0} must be greater than 0.", i)); - } - } - - - if (vehicleData.TotalRollResistanceCoefficient <= 0) { - return - new ValidationResult(string.Format("Total rolling resistance must be greater than 0! {0}", - vehicleData.TotalRollResistanceCoefficient)); - } - - // total gvw is limited by max gvw (40t) - var gvwTotal = VectoMath.Min(vehicleData.GrossVehicleWeight + vehicleData.TrailerGrossVehicleWeight, - emsCycle - ? Constants.SimulationSettings.MaximumGrossVehicleWeightEMS - : Constants.SimulationSettings.MaximumGrossVehicleWeight); - if (mode != ExecutionMode.Declaration) { - return ValidationResult.Success; - } - // vvvvvvv these checks apply only for declaration mode! vvvvvv - - //if (vehicleData.AxleConfiguration.NumAxles() != vehicleData.AxleData.Count) { - // return - // new ValidationResult( - // string.Format("For a {0} type vehicle exactly {1} number of axles have to pe specified. Found {2}", - // vehicleData.AxleConfiguration.GetName(), vehicleData.AxleConfiguration.NumAxles(), vehicleData.AxleData.Count)); - //} - - if (vehicleData.TotalVehicleWeight > gvwTotal) { - return new ValidationResult( - string.Format("Total Vehicle Weight is greater than GrossVehicleWeight! Weight: {0}, GVW: {1}", - vehicleData.TotalVehicleWeight, gvwTotal)); - } - - var numDrivenAxles = vehicleData._axleData.Count(x => x.AxleType == AxleType.VehicleDriven); - if (numDrivenAxles != 1) { - return new ValidationResult("Exactly one axle has to be defined as driven!"); - } - - - return ValidationResult.Success; - } - } +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Data +{ + [CustomValidation(typeof(AirdragData), "ValidateAirDragData")] + public class AirdragData : SimulationComponentData + { + public CrossWindCorrectionMode CrossWindCorrectionMode { get; set; } + + [Required, ValidateObject] + public ICrossWindCorrection CrossWindCorrectionCurve { get; internal set; } + + public SquareMeter DeclaredAirdragArea { get; internal set; } + + // ReSharper disable once UnusedMember.Global -- used via Validation + public static ValidationResult ValidateAirDragData(AirdragData airDragData, ValidationContext validationContext) + { + if (airDragData.CrossWindCorrectionMode != CrossWindCorrectionMode.DeclarationModeCorrection && + airDragData.CrossWindCorrectionCurve.AirDragArea == null) + return new ValidationResult( + "AirDrag Area (CdxA) must not be empty when the cross wind correction mode is not \"Speed dependent (Declaration Mode)\""); + + return ValidationResult.Success; + } + } + + /// <summary> + /// Data Class for the Vehicle + /// </summary> + [CustomValidation(typeof(VehicleData), "ValidateVehicleData")] + public class VehicleData : SimulationComponentData + { + public string VIN { get; internal set; } + + public string LegislativeClass { get; internal set; } + + public VehicleCategory VehicleCategory { get; internal set; } + + public VehicleClass VehicleClass { get; internal set; } + + public AxleConfiguration AxleConfiguration { get; internal set; } + + public string ManufacturerAddress { get; internal set; } + + + [Required, ValidateObject] private List<Axle> _axleData; + + private KilogramSquareMeter _wheelsInertia; + private double? _totalRollResistanceCoefficient; + private double? _rollResistanceCoefficientWithoutTrailer; + + public List<Axle> AxleData + { + get { return _axleData; } + internal set { + _axleData = value; + _wheelsInertia = null; + _totalRollResistanceCoefficient = null; + } + } + + /// <summary> + /// The Curb Weight of the vehicle + /// (+ Curb Weight of Standard-Body if it has one) + /// (+ Curb Weight of Trailer if it has one) + /// </summary> + [Required, SIRange(500, 40000, emsMission: false), + SIRange(0, 60000, emsMission: true)] + public Kilogram CurbWeight { get; internal set; } + + /// <summary> + /// Curb Weight of Standard-Body (if it has one) + /// + Curb Weight of Trailer (if it has one) + /// </summary> + public Kilogram BodyAndTrailerWeight { get; internal set; } + + [Required, SIRange(0, 40000, emsMission: false), + SIRange(0, 60000, emsMission: true)] + public Kilogram Loading { get; internal set; } + + [SIRange(0, 500)] + public CubicMeter CargoVolume { get; internal set; } + + /// <summary> + /// The Gross Vehicle Weight of the Vehicle. + /// </summary> + [Required, + SIRange(3500, 40000, ExecutionMode.Declaration, emsMission: false), + SIRange(0, 60000, ExecutionMode.Declaration, emsMission: true), + SIRange(0, 1000000, ExecutionMode.Engineering)] + public Kilogram GrossVehicleWeight { get; internal set; } + + /// <summary> + /// The Gross Vehicle Weight of the Trailer (if the vehicle has one). + /// </summary> + [Required, SIRange(0, 40000, emsMission: false), + SIRange(0, 60000, emsMission: true)] + public Kilogram TrailerGrossVehicleWeight { get; internal set; } + + [Required, SIRange(0.1, 0.7)] + public Meter DynamicTyreRadius { get; internal set; } + + public KilogramSquareMeter WheelsInertia + { + get { + if (_wheelsInertia == null) { + ComputeRollResistanceAndReducedMassWheels(); + } + return _wheelsInertia; + } + internal set { _wheelsInertia = value; } + } + + //[Required, SIRange(0, 1E12)] + public double TotalRollResistanceCoefficient + { + get { + if (_totalRollResistanceCoefficient == null) { + ComputeRollResistanceAndReducedMassWheels(); + } + return _totalRollResistanceCoefficient.GetValueOrDefault(); + } + protected internal set { _totalRollResistanceCoefficient = value; } + } + + public double RollResistanceCoefficientWithoutTrailer + { + get { + if (_rollResistanceCoefficientWithoutTrailer == null) { + ComputeRollResistanceAndReducedMassWheels(); + } + return _rollResistanceCoefficientWithoutTrailer.GetValueOrDefault(); + } + protected internal set { _rollResistanceCoefficientWithoutTrailer = value; } + } + + public Kilogram TotalVehicleWeight + { + get { + var retVal = 0.0.SI<Kilogram>(); + retVal += CurbWeight ?? 0.SI<Kilogram>(); + retVal += BodyAndTrailerWeight ?? 0.SI<Kilogram>(); + retVal += Loading ?? 0.SI<Kilogram>(); + return retVal; + } + } + + public Kilogram TotalCurbWeight + { + get { return (CurbWeight ?? 0.SI<Kilogram>()) + (BodyAndTrailerWeight ?? 0.SI<Kilogram>()); } + } + + protected void ComputeRollResistanceAndReducedMassWheels() + { + if (TotalVehicleWeight == 0.SI<Kilogram>()) { + throw new VectoException("Total vehicle weight must be greater than 0! Set CurbWeight and Loading before!"); + } + if (DynamicTyreRadius == null) { + throw new VectoException("Dynamic tyre radius must be set before axles!"); + } + + var g = Physics.GravityAccelleration; + + var rrc = 0.0.SI<Scalar>(); + var rrcVehicle = 0.0.SI<Scalar>(); + + var wheelsInertia = 0.0.SI<KilogramSquareMeter>(); + var vehicleWeightShare = 0.0; + foreach (var axle in _axleData) { + if (axle.AxleWeightShare.IsEqual(0, 1e-12)) { + continue; + } + var nrWheels = axle.TwinTyres ? 4 : 2; + var baseValue = (axle.AxleWeightShare * TotalVehicleWeight * g / axle.TyreTestLoad / nrWheels).Value(); + + var rrcShare = axle.AxleWeightShare * axle.RollResistanceCoefficient * + Math.Pow(baseValue, Physics.RollResistanceExponent - 1); + + if (axle.AxleType != AxleType.Trailer) { + rrcVehicle += rrcShare; + vehicleWeightShare += axle.AxleWeightShare; + } + rrc += rrcShare; + wheelsInertia += nrWheels * axle.Inertia; + } + RollResistanceCoefficientWithoutTrailer = rrcVehicle / vehicleWeightShare; + TotalRollResistanceCoefficient = rrc; + WheelsInertia = wheelsInertia; + } + + // ReSharper disable once UnusedMember.Global -- used via Validation + public static ValidationResult ValidateVehicleData(VehicleData vehicleData, ValidationContext validationContext) + { + var mode = GetExecutionMode(validationContext); + var emsCycle = GetEmsMode(validationContext); + + if (vehicleData.AxleData.Count < 1) { + return new ValidationResult("At least two axles need to be specified"); + } + + var weightShareSum = vehicleData.AxleData.Sum(axle => axle.AxleWeightShare); + if (!weightShareSum.IsEqual(1.0, 1E-10)) { + return new ValidationResult( + string.Format("Sum of axle weight share is not 1! sum: {0}, difference: {1}", + weightShareSum, 1 - weightShareSum)); + } + for (var i = 0; i < vehicleData.AxleData.Count; i++) { + if (vehicleData.AxleData[i].TyreTestLoad.IsSmallerOrEqual(0)) { + return new ValidationResult(string.Format("Tyre test load (FzISO) for axle {0} must be greater than 0.", i)); + } + } + + if (vehicleData.TotalRollResistanceCoefficient <= 0) { + return + new ValidationResult(string.Format("Total rolling resistance must be greater than 0! {0}", + vehicleData.TotalRollResistanceCoefficient)); + } + + // total gvw is limited by max gvw (40t) + var gvwTotal = VectoMath.Min(vehicleData.GrossVehicleWeight + vehicleData.TrailerGrossVehicleWeight, + emsCycle + ? Constants.SimulationSettings.MaximumGrossVehicleWeightEMS + : Constants.SimulationSettings.MaximumGrossVehicleWeight); + if (mode != ExecutionMode.Declaration) { + return ValidationResult.Success; + } + // vvvvvvv these checks apply only for declaration mode! vvvvvv + + //if (vehicleData.AxleConfiguration.NumAxles() != vehicleData.AxleData.Count) { + // return + // new ValidationResult( + // string.Format("For a {0} type vehicle exactly {1} number of axles have to pe specified. Found {2}", + // vehicleData.AxleConfiguration.GetName(), vehicleData.AxleConfiguration.NumAxles(), vehicleData.AxleData.Count)); + //} + + if (vehicleData.TotalVehicleWeight > gvwTotal) { + return new ValidationResult( + string.Format("Total Vehicle Weight is greater than GrossVehicleWeight! Weight: {0}, GVW: {1}", + vehicleData.TotalVehicleWeight, gvwTotal)); + } + + var numDrivenAxles = vehicleData._axleData.Count(x => x.AxleType == AxleType.VehicleDriven); + if (numDrivenAxles != 1) { + return new ValidationResult("Exactly one axle has to be defined as driven!"); + } + + return ValidationResult.Success; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs index 1267b16fe0557d1db55ee07a9d7bd6f841bd12c3..02152d10f148ffa1f50bd06011d4a593f7cb2c18 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs @@ -384,7 +384,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } var fc = result.Value; - //TODO mk-2015-11-11: calculate aux start stop correction var fcAux = fc; var fcWHTC = fcAux * ModelData.FuelConsumptionCorrectionFactor; diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs index 1a001d4de84453d4148a1428e7867cbb8f9c4a8c..e3d6c3420179a779cf08ff9a5b570211edf9add7 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs @@ -228,13 +228,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl CurrentState.TorqueConverterActive = true; return TorqueConverter.Request(absTime, dt, inTorque, inAngularVelocity); } - // mk 2016-12-13 - //if (outTorque.IsSmaller(0) && inAngularVelocity.IsSmaller(DataBus.EngineIdleSpeed)) { - // Log.Warn("engine speed would fall below idle speed - disengage! gear from cycle: {0}, vehicle speed: {1}", Gear, - // DataBus.VehicleSpeed); - // Gear = 0; - // return RequestDisengaged(absTime, dt, outTorque, outAngularVelocity, dryRun); - //} + if (TorqueConverter != null) { TorqueConverter.Locked(CurrentState.InTorque, CurrentState.InAngularVelocity, CurrentState.InTorque, CurrentState.InAngularVelocity); @@ -315,26 +309,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl }; } - - //var motoringSpeed = DataBus.EngineIdleSpeed; - //var disengagedResponse = NextComponent.Request(absTime, dt, 0.SI<NewtonMeter>(), DataBus.EngineIdleSpeed); - //if (!(disengagedResponse is ResponseSuccess)) { - // motoringSpeed = DataBus.EngineSpeed; - // if (motoringSpeed.IsGreater(DataBus.EngineIdleSpeed)) { - // var first = (ResponseDryRun)NextComponent.Request(absTime, dt, 0.SI<NewtonMeter>(), motoringSpeed, true); - // try { - // motoringSpeed = SearchAlgorithm.Search(motoringSpeed, first.DeltaDragLoad, - // Constants.SimulationSettings.EngineIdlingSearchInterval, - // getYValue: result => ((ResponseDryRun)result).DeltaDragLoad, - // evaluateFunction: n => NextComponent.Request(absTime, dt, 0.SI<NewtonMeter>(), n, true), - // criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value()); - // } catch (VectoException) { - // Log.Warn("CycleGearbox could not find motoring speed for disengaged state."); - // } - // motoringSpeed = motoringSpeed.LimitTo(DataBus.EngineIdleSpeed, DataBus.EngineSpeed); - // } - // disengagedResponse = NextComponent.Request(absTime, dt, 0.SI<NewtonMeter>(), motoringSpeed); - //} IResponse disengagedResponse; if (GearboxType.AutomaticTransmission()) { disengagedResponse = EngineIdleRequest(absTime, dt); diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs index 4abc435139bc42eba92e5b12bdc463a4610a1771..f077fefc392a8c938032d8c729544493c8417a43 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs @@ -318,18 +318,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl CurrentState = CurrentState.Clone(); _intervalProlonged = false; - // @@@quam TODO: duplicate code - same as below! - //var stopTime = Left.PTOActive && IdleController != null - // ? Left.StoppingTime + IdleController.Duration - // : Left.StoppingTime; - - //if (!stopTime.IsEqual(0) && stopTime.IsEqual(PreviousState.WaitTime)) { - // // we needed to stop at the current interval in the cycle and have already waited enough time, move on.. - // if (IdleController != null) { - // IdleController.ActivateIdle(); - // } - // CycleIntervalIterator.MoveNext(); - //} var stopTime = Left.PTOActive && IdleController != null ? Left.StoppingTime + IdleController.Duration @@ -430,10 +418,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl // only use the one with min. speed if (cycleIterator.RightSample.VehicleTargetSpeed < lookaheadEntry.VehicleTargetSpeed) { retVal.Remove(lookaheadEntry); - retVal.Add(cycleIterator.RightSample); // TODO: MQ 2016-05-13: use clone of iterator here? + retVal.Add(cycleIterator.RightSample); } } else { - retVal.Add(cycleIterator.RightSample); // TODO: MQ 2016-05-13: use clone of iterator here? + retVal.Add(cycleIterator.RightSample); } velocity = cycleIterator.RightSample.VehicleTargetSpeed; if (velocity.IsEqual(0.KMPHtoMeterPerSecond())) { diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PWheelCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PWheelCycle.cs index de4431d73f2da57d2d87a4a19a94e6c34cee0c9d..098c05e6f802d251de62ffd15ceccc4ca99ffa43 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PWheelCycle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PWheelCycle.cs @@ -29,138 +29,138 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Collections.Generic; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.Connector.Ports.Impl; -using TUGraz.VectoCore.Models.Simulation; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.OutputData; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - /// <summary> - /// Driving Cycle for the PWheel driving cycle. - /// </summary> - public class PWheelCycle : PowertrainDrivingCycle, IDriverInfo, IVehicleInfo - { - private readonly VehicleData _vehicleData; - - /// <summary> - /// Initializes a new instance of the <see cref="PWheelCycle"/> class. - /// </summary> - /// <param name="container">The container.</param> - /// <param name="cycle">The cycle.</param> - /// <param name="axleRatio">The axle ratio.</param> - /// <param name="vehicleData"></param> - /// <param name="gearRatios"></param> - public PWheelCycle(IVehicleContainer container, IDrivingCycleData cycle, double axleRatio, VehicleData vehicleData, - IDictionary<uint, double> gearRatios) : base(container, cycle) - { - // just to ensure that null-gear has ratio 1 - gearRatios[0] = 1; - _vehicleData = vehicleData; - foreach (var entry in Data.Entries) { - entry.WheelAngularVelocity = entry.AngularVelocity / (axleRatio * gearRatios[entry.Gear]); - entry.Torque = entry.PWheel / entry.WheelAngularVelocity; - } - } - - public override IResponse Initialize() - { - var first = Data.Entries[0]; - AbsTime = first.Time; - var response = NextComponent.Initialize(first.Torque, first.WheelAngularVelocity); - response.AbsTime = AbsTime; - return response; - } - - public override IResponse Request(Second absTime, Second dt) - { - if (CycleIterator.LastEntry && CycleIterator.RightSample.Time == absTime) { - return new ResponseCycleFinished { Source = this }; - } - - // interval exceeded - if (CycleIterator.RightSample != null && (absTime + dt).IsGreater(CycleIterator.RightSample.Time)) { - return new ResponseFailTimeInterval { - AbsTime = absTime, - Source = this, - DeltaT = CycleIterator.RightSample.Time - absTime - }; - } - - return DoHandleRequest(absTime, dt, CycleIterator.LeftSample.WheelAngularVelocity); - } - - protected override void DoWriteModalResults(IModalDataContainer container) - { - container[ModalResultField.P_wheel_in] = CycleIterator.LeftSample.PWheel; - base.DoWriteModalResults(container); - } - - #region IDriverInfo - - public MeterPerSecond VehicleSpeed { get; private set; } - - /// <summary> - /// True if the angularVelocity at the wheels is 0. - /// </summary> - public bool VehicleStopped - { - get { return CycleIterator.LeftSample.WheelAngularVelocity.IsEqual(0); } - } - - public Kilogram VehicleMass - { - get { return _vehicleData.TotalCurbWeight; } - } - - public Kilogram VehicleLoading - { - get { return _vehicleData.Loading; } - } - - public Kilogram TotalMass - { - get { return _vehicleData.TotalVehicleWeight; } - } - - public CubicMeter CargoVolume - { - get { return _vehicleData.CargoVolume; } - } - - public Newton AirDragResistance(MeterPerSecond previousVelocity, MeterPerSecond nextVelocity) - { - throw new System.NotImplementedException(); - } - - public Newton RollingResistance(Radian gradient) - { - throw new System.NotImplementedException(); - } - - public Newton SlopeResistance(Radian gradient) - { - throw new System.NotImplementedException(); - } - - /// <summary> - /// Always Driving. - /// </summary> - public DrivingBehavior DriverBehavior - { - get { return DrivingBehavior.Driving; } - } - - public MeterPerSquareSecond DriverAcceleration - { - get { return 0.SI<MeterPerSquareSecond>(); } - } - - #endregion - } +using System.Collections.Generic; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.OutputData; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + /// <summary> + /// Driving Cycle for the PWheel driving cycle. + /// </summary> + public class PWheelCycle : PowertrainDrivingCycle, IDriverInfo, IVehicleInfo + { + private readonly VehicleData _vehicleData; + + /// <summary> + /// Initializes a new instance of the <see cref="PWheelCycle"/> class. + /// </summary> + /// <param name="container">The container.</param> + /// <param name="cycle">The cycle.</param> + /// <param name="axleRatio">The axle ratio.</param> + /// <param name="vehicleData"></param> + /// <param name="gearRatios"></param> + public PWheelCycle(IVehicleContainer container, IDrivingCycleData cycle, double axleRatio, VehicleData vehicleData, + IDictionary<uint, double> gearRatios) : base(container, cycle) + { + // just to ensure that null-gear has ratio 1 + gearRatios[0] = 1; + _vehicleData = vehicleData; + foreach (var entry in Data.Entries) { + entry.WheelAngularVelocity = entry.AngularVelocity / (axleRatio * gearRatios[entry.Gear]); + entry.Torque = entry.PWheel / entry.WheelAngularVelocity; + } + } + + public override IResponse Initialize() + { + var first = Data.Entries[0]; + AbsTime = first.Time; + var response = NextComponent.Initialize(first.Torque, first.WheelAngularVelocity); + response.AbsTime = AbsTime; + return response; + } + + public override IResponse Request(Second absTime, Second dt) + { + if (CycleIterator.LastEntry && CycleIterator.RightSample.Time == absTime) { + return new ResponseCycleFinished { Source = this }; + } + + // interval exceeded + if (CycleIterator.RightSample != null && (absTime + dt).IsGreater(CycleIterator.RightSample.Time)) { + return new ResponseFailTimeInterval { + AbsTime = absTime, + Source = this, + DeltaT = CycleIterator.RightSample.Time - absTime + }; + } + + return DoHandleRequest(absTime, dt, CycleIterator.LeftSample.WheelAngularVelocity); + } + + protected override void DoWriteModalResults(IModalDataContainer container) + { + container[ModalResultField.P_wheel_in] = CycleIterator.LeftSample.PWheel; + base.DoWriteModalResults(container); + } + + #region IDriverInfo + + public MeterPerSecond VehicleSpeed { get; private set; } + + /// <summary> + /// True if the angularVelocity at the wheels is 0. + /// </summary> + public bool VehicleStopped + { + get { return CycleIterator.LeftSample.WheelAngularVelocity.IsEqual(0); } + } + + public Kilogram VehicleMass + { + get { return _vehicleData.TotalCurbWeight; } + } + + public Kilogram VehicleLoading + { + get { return _vehicleData.Loading; } + } + + public Kilogram TotalMass + { + get { return _vehicleData.TotalVehicleWeight; } + } + + public CubicMeter CargoVolume + { + get { return _vehicleData.CargoVolume; } + } + + public Newton AirDragResistance(MeterPerSecond previousVelocity, MeterPerSecond nextVelocity) + { + throw new System.NotImplementedException(); + } + + public Newton RollingResistance(Radian gradient) + { + throw new System.NotImplementedException(); + } + + public Newton SlopeResistance(Radian gradient) + { + throw new System.NotImplementedException(); + } + + /// <summary> + /// Always Driving. + /// </summary> + public DrivingBehavior DriverBehavior + { + get { return DrivingBehavior.Driving; } + } + + public MeterPerSquareSecond DriverAcceleration + { + get { return 0.SI<MeterPerSquareSecond>(); } + } + + #endregion + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs index 67e0e9125535e42d7c03529c2a56ed003090f7ba..17fd58fa9018e5ff64a3141adff58c6234ecf1bd 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs @@ -29,204 +29,204 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.Connector.Ports; -using TUGraz.VectoCore.Models.Connector.Ports.Impl; -using TUGraz.VectoCore.Models.Simulation; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - /// <summary> - /// Represents a driving cycle which directly is connected to the powertrain (e.g. engine, or axle gear). - /// </summary> - public class PowertrainDrivingCycle : - StatefulProviderComponent<SimpleComponentState, ISimulationOutPort, ITnInPort, ITnOutPort>, - IDrivingCycleInfo, ISimulationOutPort, ITnInProvider, ITnInPort - { - protected readonly IDrivingCycleData Data; - protected internal readonly DrivingCycleEnumerator CycleIterator; - - protected Second AbsTime { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="PowertrainDrivingCycle"/> class. - /// </summary> - /// <param name="container">The container.</param> - /// <param name="cycle">The cycle.</param> - public PowertrainDrivingCycle(IVehicleContainer container, IDrivingCycleData cycle) : base(container) - { - Data = cycle; - CycleIterator = new DrivingCycleEnumerator(Data); - - AbsTime = 0.SI<Second>(); - } - - public virtual IResponse Initialize() - { - var first = Data.Entries[0]; - AbsTime = first.Time; - var response = NextComponent.Initialize(first.Torque, first.AngularVelocity); - response.AbsTime = AbsTime; - return response; - } - - #region ISimulationOutPort - - public IResponse Request(Second absTime, Meter ds) - { - throw new VectoSimulationException("Powertrain Only Simulation can not handle distance request."); - } - - public virtual IResponse Request(Second absTime, Second dt) - { - // cycle finished (no more entries in cycle) - if (CycleIterator.LastEntry && CycleIterator.RightSample.Time == absTime) { - return new ResponseCycleFinished { Source = this }; - } - - // interval exceeded - if (CycleIterator.RightSample != null && (absTime + dt).IsGreater(CycleIterator.RightSample.Time)) { - return new ResponseFailTimeInterval { - AbsTime = absTime, - Source = this, - DeltaT = CycleIterator.RightSample.Time - absTime - }; - } - - return DoHandleRequest(absTime, dt, CycleIterator.LeftSample.AngularVelocity); - } - - protected IResponse DoHandleRequest(Second absTime, Second dt, PerSecond angularVelocity) - { - var debug = new DebugData(); - - IResponse response; - var responseCount = 0; - do { - response = NextComponent.Request(absTime, dt, CycleIterator.LeftSample.Torque, angularVelocity); - CurrentState.InAngularVelocity = angularVelocity; - CurrentState.InTorque = CycleIterator.LeftSample.Torque; - debug.Add(response); - response.Switch() - .Case<ResponseGearShift>( - () => response = NextComponent.Request(absTime, dt, CurrentState.InTorque, angularVelocity)) - .Case<ResponseUnderload>(r => { - var torqueInterval = -r.Delta / (angularVelocity.IsEqual(0) ? 10.RPMtoRad() : angularVelocity); - var torque = SearchAlgorithm.Search(CycleIterator.LeftSample.Torque, r.Delta, torqueInterval, - getYValue: result => ((ResponseDryRun)result).DeltaDragLoad, - evaluateFunction: t => NextComponent.Request(absTime, dt, t, angularVelocity, true), - criterion: y => ((ResponseDryRun)y).DeltaDragLoad.Value()); - response = NextComponent.Request(absTime, dt, torque, angularVelocity); - CurrentState.InTorque = torque; - }) - .Case<ResponseOverload>(r => { - var torque = SearchAlgorithm.Search(CycleIterator.LeftSample.Torque, r.Delta, 50.SI<NewtonMeter>(), - getYValue: result => ((ResponseDryRun)result).DeltaFullLoad, - evaluateFunction: t => NextComponent.Request(absTime, dt, t, angularVelocity, true), - criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value()); - response = NextComponent.Request(absTime, dt, torque, angularVelocity); - CurrentState.InAngularVelocity = angularVelocity; - }) - .Case<ResponseEngineSpeedTooHigh>(r => { - angularVelocity = SearchAlgorithm.Search(angularVelocity, r.DeltaEngineSpeed, - 1.RPMtoRad(), - getYValue: result => ((ResponseDryRun)result).DeltaEngineSpeed, - evaluateFunction: x => NextComponent.Request(absTime, dt, CurrentState.InTorque, x, true), - criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value()); - }) - .Case<ResponseFailTimeInterval>(r => { dt = r.DeltaT; }) - .Case<ResponseSuccess>(() => { }) - .Default( - r => { throw new UnexpectedResponseException("PowertrainDrivingCycle received an unexpected response.", r); }); - } while (!(response is ResponseSuccess || response is ResponseFailTimeInterval) && (++responseCount < 10)); - - AbsTime = absTime + dt; - response.SimulationInterval = dt; - debug.Add(response); - return response; - } - - public double Progress - { - get { return AbsTime.Value() / Data.Entries.Last().Time.Value(); } - } - - #endregion - - #region VectoSimulationComponent - - protected override void DoWriteModalResults(IModalDataContainer container) {} - - protected override void DoCommitSimulationStep() - { - CycleIterator.MoveNext(); - AdvanceState(); - } - - #endregion - - public CycleData CycleData - { - get { - return new CycleData { - AbsTime = CycleIterator.LeftSample.Time, - AbsDistance = null, - LeftSample = CycleIterator.LeftSample, - RightSample = CycleIterator.RightSample, - }; - } - } - - public bool PTOActive - { - get { return true; } - } - - public DrivingCycleData.DrivingCycleEntry CycleLookAhead(Meter distance) - { - return new DrivingCycleData.DrivingCycleEntry() { - Altitude = 0.SI<Meter>() - }; - } - - public Meter Altitude - { - get { return 0.SI<Meter>(); } - } - - public Meter CycleStartDistance - { - get { return 0.SI<Meter>(); } - } - - public IReadOnlyList<DrivingCycleData.DrivingCycleEntry> LookAhead(Meter lookaheadDistance) - { - throw new NotImplementedException(); - } - - public IReadOnlyList<DrivingCycleData.DrivingCycleEntry> LookAhead(Second time) - { - var retVal = new List<DrivingCycleData.DrivingCycleEntry>(); - - var iterator = CycleIterator.Clone(); - do { - retVal.Add(iterator.RightSample); - } while (iterator.MoveNext() && iterator.RightSample.Time < AbsTime + time); - - return retVal; - } - - public void FinishSimulation() - { - Data.Finish(); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + /// <summary> + /// Represents a driving cycle which directly is connected to the powertrain (e.g. engine, or axle gear). + /// </summary> + public class PowertrainDrivingCycle : + StatefulProviderComponent<SimpleComponentState, ISimulationOutPort, ITnInPort, ITnOutPort>, + IDrivingCycleInfo, ISimulationOutPort, ITnInProvider, ITnInPort + { + protected readonly IDrivingCycleData Data; + protected internal readonly DrivingCycleEnumerator CycleIterator; + + protected Second AbsTime { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="PowertrainDrivingCycle"/> class. + /// </summary> + /// <param name="container">The container.</param> + /// <param name="cycle">The cycle.</param> + public PowertrainDrivingCycle(IVehicleContainer container, IDrivingCycleData cycle) : base(container) + { + Data = cycle; + CycleIterator = new DrivingCycleEnumerator(Data); + + AbsTime = 0.SI<Second>(); + } + + public virtual IResponse Initialize() + { + var first = Data.Entries[0]; + AbsTime = first.Time; + var response = NextComponent.Initialize(first.Torque, first.AngularVelocity); + response.AbsTime = AbsTime; + return response; + } + + #region ISimulationOutPort + + public IResponse Request(Second absTime, Meter ds) + { + throw new VectoSimulationException("Powertrain Only Simulation can not handle distance request."); + } + + public virtual IResponse Request(Second absTime, Second dt) + { + // cycle finished (no more entries in cycle) + if (CycleIterator.LastEntry && CycleIterator.RightSample.Time == absTime) { + return new ResponseCycleFinished { Source = this }; + } + + // interval exceeded + if (CycleIterator.RightSample != null && (absTime + dt).IsGreater(CycleIterator.RightSample.Time)) { + return new ResponseFailTimeInterval { + AbsTime = absTime, + Source = this, + DeltaT = CycleIterator.RightSample.Time - absTime + }; + } + + return DoHandleRequest(absTime, dt, CycleIterator.LeftSample.AngularVelocity); + } + + protected IResponse DoHandleRequest(Second absTime, Second dt, PerSecond angularVelocity) + { + var debug = new DebugData(); + + IResponse response; + var responseCount = 0; + do { + response = NextComponent.Request(absTime, dt, CycleIterator.LeftSample.Torque, angularVelocity); + CurrentState.InAngularVelocity = angularVelocity; + CurrentState.InTorque = CycleIterator.LeftSample.Torque; + debug.Add(response); + response.Switch() + .Case<ResponseGearShift>( + () => response = NextComponent.Request(absTime, dt, CurrentState.InTorque, angularVelocity)) + .Case<ResponseUnderload>(r => { + var torqueInterval = -r.Delta / (angularVelocity.IsEqual(0) ? 10.RPMtoRad() : angularVelocity); + var torque = SearchAlgorithm.Search(CycleIterator.LeftSample.Torque, r.Delta, torqueInterval, + getYValue: result => ((ResponseDryRun)result).DeltaDragLoad, + evaluateFunction: t => NextComponent.Request(absTime, dt, t, angularVelocity, true), + criterion: y => ((ResponseDryRun)y).DeltaDragLoad.Value()); + response = NextComponent.Request(absTime, dt, torque, angularVelocity); + CurrentState.InTorque = torque; + }) + .Case<ResponseOverload>(r => { + var torque = SearchAlgorithm.Search(CycleIterator.LeftSample.Torque, r.Delta, 50.SI<NewtonMeter>(), + getYValue: result => ((ResponseDryRun)result).DeltaFullLoad, + evaluateFunction: t => NextComponent.Request(absTime, dt, t, angularVelocity, true), + criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value()); + response = NextComponent.Request(absTime, dt, torque, angularVelocity); + CurrentState.InAngularVelocity = angularVelocity; + }) + .Case<ResponseEngineSpeedTooHigh>(r => { + angularVelocity = SearchAlgorithm.Search(angularVelocity, r.DeltaEngineSpeed, + 1.RPMtoRad(), + getYValue: result => ((ResponseDryRun)result).DeltaEngineSpeed, + evaluateFunction: x => NextComponent.Request(absTime, dt, CurrentState.InTorque, x, true), + criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value()); + }) + .Case<ResponseFailTimeInterval>(r => { dt = r.DeltaT; }) + .Case<ResponseSuccess>(() => { }) + .Default( + r => { throw new UnexpectedResponseException("PowertrainDrivingCycle received an unexpected response.", r); }); + } while (!(response is ResponseSuccess || response is ResponseFailTimeInterval) && (++responseCount < 10)); + + AbsTime = absTime + dt; + response.SimulationInterval = dt; + debug.Add(response); + return response; + } + + public double Progress + { + get { return AbsTime.Value() / Data.Entries.Last().Time.Value(); } + } + + #endregion + + #region VectoSimulationComponent + + protected override void DoWriteModalResults(IModalDataContainer container) {} + + protected override void DoCommitSimulationStep() + { + CycleIterator.MoveNext(); + AdvanceState(); + } + + #endregion + + public CycleData CycleData + { + get { + return new CycleData { + AbsTime = CycleIterator.LeftSample.Time, + AbsDistance = null, + LeftSample = CycleIterator.LeftSample, + RightSample = CycleIterator.RightSample, + }; + } + } + + public bool PTOActive + { + get { return true; } + } + + public DrivingCycleData.DrivingCycleEntry CycleLookAhead(Meter distance) + { + return new DrivingCycleData.DrivingCycleEntry() { + Altitude = 0.SI<Meter>() + }; + } + + public Meter Altitude + { + get { return 0.SI<Meter>(); } + } + + public Meter CycleStartDistance + { + get { return 0.SI<Meter>(); } + } + + public IReadOnlyList<DrivingCycleData.DrivingCycleEntry> LookAhead(Meter lookaheadDistance) + { + throw new NotImplementedException(); + } + + public IReadOnlyList<DrivingCycleData.DrivingCycleEntry> LookAhead(Second time) + { + var retVal = new List<DrivingCycleData.DrivingCycleEntry>(); + + var iterator = CycleIterator.Clone(); + do { + retVal.Add(iterator.RightSample); + } while (iterator.MoveNext() && iterator.RightSample.Time < AbsTime + time); + + return retVal; + } + + public void FinishSimulation() + { + Data.Finish(); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs index 5a749e071ff0aa74a8cd1115e933cf0b33739515..57cdd58380c2ac56974b0496f08e483539a41728 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs @@ -29,228 +29,228 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Models.Connector.Ports; -using TUGraz.VectoCore.Models.Simulation; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - public class Vehicle : StatefulProviderComponent<Vehicle.VehicleState, IDriverDemandOutPort, IFvInPort, IFvOutPort>, - IVehicle, IMileageCounter, IFvInPort, - IDriverDemandOutPort - { - internal readonly VehicleData ModelData; - - public readonly AirdragData AirdragData; - - - public Vehicle(IVehicleContainer container, VehicleData modelData, AirdragData airdrag) : base(container) - { - ModelData = modelData; - AirdragData = airdrag; - if (AirdragData.CrossWindCorrectionCurve != null) { - AirdragData.CrossWindCorrectionCurve.SetDataBus(container); - } - } - - - public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient) - { - PreviousState = new VehicleState { - Distance = DataBus.CycleStartDistance, - Velocity = vehicleSpeed, - RollingResistance = RollingResistance(roadGradient), - SlopeResistance = SlopeResistance(roadGradient), - AirDragResistance = AirDragResistance(vehicleSpeed, vehicleSpeed), - }; - PreviousState.VehicleTractionForce = PreviousState.RollingResistance - + PreviousState.AirDragResistance - + PreviousState.SlopeResistance; - - return NextComponent.Initialize(PreviousState.VehicleTractionForce, vehicleSpeed); - } - - public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient, MeterPerSquareSecond startAcceleration) - { - //CurrentState.Velocity = vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval; - var vehicleAccelerationForce = DriverAcceleration(startAcceleration) - + RollingResistance(roadGradient) - + - AirDragResistance(vehicleSpeed, - vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval) - + SlopeResistance(roadGradient); - - var retVal = NextComponent.Initialize(vehicleAccelerationForce, vehicleSpeed); - return retVal; - } - - public IResponse Request(Second absTime, Second dt, MeterPerSquareSecond acceleration, Radian gradient, - bool dryRun = false) - { - Log.Debug("Vehicle: acceleration: {0}", acceleration); - CurrentState.SimulationInterval = dt; - CurrentState.Acceleration = acceleration; - CurrentState.Velocity = PreviousState.Velocity + acceleration * dt; - if (CurrentState.Velocity.IsEqual(0.SI<MeterPerSecond>(), - Constants.SimulationSettings.VehicleSpeedHaltTolerance)) { - CurrentState.Velocity = 0.SI<MeterPerSecond>(); - } - CurrentState.Distance = PreviousState.Distance + PreviousState.Velocity * dt + acceleration * dt * dt / 2; - - CurrentState.DriverAcceleration = DriverAcceleration(acceleration); - CurrentState.RollingResistance = RollingResistance(gradient); - try { - CurrentState.AirDragResistance = AirDragResistance(PreviousState.Velocity, CurrentState.Velocity); - } catch (VectoException ex) { - Log.Warn("Exception during calculation of AirDragResistance: absTime: {0}, dist: {1}, v: {2}. {3}", absTime, - CurrentState.Distance, CurrentState.Velocity, ex); - CurrentState.AirDragResistance = AirDragResistance(VectoMath.Max(0, PreviousState.Velocity), - VectoMath.Max(0, CurrentState.Velocity)); - } - CurrentState.SlopeResistance = SlopeResistance(gradient); - - // DriverAcceleration = vehicleTractionForce - RollingResistance - AirDragResistance - SlopeResistance - CurrentState.VehicleTractionForce = CurrentState.DriverAcceleration - + CurrentState.RollingResistance - + CurrentState.AirDragResistance - + CurrentState.SlopeResistance; - - var retval = NextComponent.Request(absTime, dt, CurrentState.VehicleTractionForce, - CurrentState.Velocity, dryRun); - return retval; - } - - protected override void DoWriteModalResults(IModalDataContainer container) - { - var averageVelocity = (PreviousState.Velocity + CurrentState.Velocity) / 2.0; - - container[ModalResultField.v_act] = averageVelocity; - - container[ModalResultField.P_veh_inertia] = CurrentState.DriverAcceleration * averageVelocity; - container[ModalResultField.P_roll] = CurrentState.RollingResistance * averageVelocity; - container[ModalResultField.P_air] = CurrentState.AirDragResistance * averageVelocity; - container[ModalResultField.P_slope] = CurrentState.SlopeResistance * averageVelocity; - container[ModalResultField.P_trac] = CurrentState.VehicleTractionForce * averageVelocity; - - // sanity check: is the vehicle in step with the cycle? - if (container[ModalResultField.dist] == DBNull.Value) { - Log.Warn("Distance field is not set!"); - } else { - var distance = (SI)container[ModalResultField.dist]; - if (!distance.IsEqual(CurrentState.Distance)) { - Log.Warn("Vehicle Distance diverges from Cycle by {0} [m]. Distance: {1}", - (distance - CurrentState.Distance).Value(), distance); - } - } - } - - public Newton RollingResistance(Radian gradient) - { - var weight = ModelData.TotalVehicleWeight; - var gravity = Physics.GravityAccelleration; - var rollCoefficient = ModelData.TotalRollResistanceCoefficient; - - var retVal = Math.Cos(gradient.Value()) * weight * gravity * rollCoefficient; - Log.Debug("RollingResistance: {0}", retVal); - return retVal; - } - - protected internal Newton DriverAcceleration(MeterPerSquareSecond accelleration) - { - var retVal = ModelData.TotalVehicleWeight * accelleration; - Log.Debug("DriverAcceleration: {0}", retVal); - return retVal; - } - - public Newton SlopeResistance(Radian gradient) - { - var retVal = ModelData.TotalVehicleWeight * Physics.GravityAccelleration * Math.Sin(gradient.Value()); - Log.Debug("SlopeResistance: {0}", retVal); - return retVal; - } - - public Newton AirDragResistance(MeterPerSecond previousVelocity, MeterPerSecond nextVelocity) - { - var vAverage = (previousVelocity + nextVelocity) / 2; - if (vAverage.IsEqual(0)) { - return 0.SI<Newton>(); - } - var result = ComputeAirDragPowerLoss(previousVelocity, nextVelocity) / vAverage; - - Log.Debug("AirDragResistance: {0}", result); - return result; - } - - private Watt ComputeAirDragPowerLoss(MeterPerSecond v1, MeterPerSecond v2) - { - return AirdragData.CrossWindCorrectionCurve.AverageAirDragPowerLoss(v1, v2); - } - - public Meter Distance - { - get { return PreviousState.Distance; } - } - - public MeterPerSecond VehicleSpeed - { - get { return PreviousState.Velocity; } - } - - public bool VehicleStopped - { - get { return PreviousState.Velocity.IsEqual(0.SI<MeterPerSecond>(), 0.01.SI<MeterPerSecond>()); } - } - - public Kilogram VehicleMass - { - get { return ModelData.TotalCurbWeight; } - } - - public Kilogram VehicleLoading - { - get { return ModelData.Loading; } - } - - public Kilogram TotalMass - { - get { return ModelData.TotalVehicleWeight; } - } - - public CubicMeter CargoVolume - { - get { return ModelData.CargoVolume; } - } - - public class VehicleState - { - public Meter Distance = 0.SI<Meter>(); - public Second SimulationInterval = 0.SI<Second>(); - public Newton AirDragResistance = 0.SI<Newton>(); - public Newton DriverAcceleration = 0.SI<Newton>(); - public Newton RollingResistance = 0.SI<Newton>(); - public Newton SlopeResistance = 0.SI<Newton>(); - public Newton VehicleTractionForce = 0.SI<Newton>(); - public MeterPerSecond Velocity = 0.SI<MeterPerSecond>(); - public MeterPerSquareSecond Acceleration = 0.SI<MeterPerSquareSecond>(); - - public override string ToString() - { - return - string.Format( - "v: {0} a: {1}, dt: {2}, driver_acc: {3}, roll_res: {4}, slope_res: {5}, air_drag: {6}, traction force: {7}", - Velocity, Acceleration, SimulationInterval, DriverAcceleration, RollingResistance, SlopeResistance, - AirDragResistance, - VehicleTractionForce); - } - } - } +using System; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public class Vehicle : StatefulProviderComponent<Vehicle.VehicleState, IDriverDemandOutPort, IFvInPort, IFvOutPort>, + IVehicle, IMileageCounter, IFvInPort, + IDriverDemandOutPort + { + internal readonly VehicleData ModelData; + + public readonly AirdragData AirdragData; + + + public Vehicle(IVehicleContainer container, VehicleData modelData, AirdragData airdrag) : base(container) + { + ModelData = modelData; + AirdragData = airdrag; + if (AirdragData.CrossWindCorrectionCurve != null) { + AirdragData.CrossWindCorrectionCurve.SetDataBus(container); + } + } + + + public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient) + { + PreviousState = new VehicleState { + Distance = DataBus.CycleStartDistance, + Velocity = vehicleSpeed, + RollingResistance = RollingResistance(roadGradient), + SlopeResistance = SlopeResistance(roadGradient), + AirDragResistance = AirDragResistance(vehicleSpeed, vehicleSpeed), + }; + PreviousState.VehicleTractionForce = PreviousState.RollingResistance + + PreviousState.AirDragResistance + + PreviousState.SlopeResistance; + + return NextComponent.Initialize(PreviousState.VehicleTractionForce, vehicleSpeed); + } + + public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient, MeterPerSquareSecond startAcceleration) + { + //CurrentState.Velocity = vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval; + var vehicleAccelerationForce = DriverAcceleration(startAcceleration) + + RollingResistance(roadGradient) + + + AirDragResistance(vehicleSpeed, + vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval) + + SlopeResistance(roadGradient); + + var retVal = NextComponent.Initialize(vehicleAccelerationForce, vehicleSpeed); + return retVal; + } + + public IResponse Request(Second absTime, Second dt, MeterPerSquareSecond acceleration, Radian gradient, + bool dryRun = false) + { + Log.Debug("Vehicle: acceleration: {0}", acceleration); + CurrentState.SimulationInterval = dt; + CurrentState.Acceleration = acceleration; + CurrentState.Velocity = PreviousState.Velocity + acceleration * dt; + if (CurrentState.Velocity.IsEqual(0.SI<MeterPerSecond>(), + Constants.SimulationSettings.VehicleSpeedHaltTolerance)) { + CurrentState.Velocity = 0.SI<MeterPerSecond>(); + } + CurrentState.Distance = PreviousState.Distance + PreviousState.Velocity * dt + acceleration * dt * dt / 2; + + CurrentState.DriverAcceleration = DriverAcceleration(acceleration); + CurrentState.RollingResistance = RollingResistance(gradient); + try { + CurrentState.AirDragResistance = AirDragResistance(PreviousState.Velocity, CurrentState.Velocity); + } catch (VectoException ex) { + Log.Warn("Exception during calculation of AirDragResistance: absTime: {0}, dist: {1}, v: {2}. {3}", absTime, + CurrentState.Distance, CurrentState.Velocity, ex); + CurrentState.AirDragResistance = AirDragResistance(VectoMath.Max(0, PreviousState.Velocity), + VectoMath.Max(0, CurrentState.Velocity)); + } + CurrentState.SlopeResistance = SlopeResistance(gradient); + + // DriverAcceleration = vehicleTractionForce - RollingResistance - AirDragResistance - SlopeResistance + CurrentState.VehicleTractionForce = CurrentState.DriverAcceleration + + CurrentState.RollingResistance + + CurrentState.AirDragResistance + + CurrentState.SlopeResistance; + + var retval = NextComponent.Request(absTime, dt, CurrentState.VehicleTractionForce, + CurrentState.Velocity, dryRun); + return retval; + } + + protected override void DoWriteModalResults(IModalDataContainer container) + { + var averageVelocity = (PreviousState.Velocity + CurrentState.Velocity) / 2.0; + + container[ModalResultField.v_act] = averageVelocity; + + container[ModalResultField.P_veh_inertia] = CurrentState.DriverAcceleration * averageVelocity; + container[ModalResultField.P_roll] = CurrentState.RollingResistance * averageVelocity; + container[ModalResultField.P_air] = CurrentState.AirDragResistance * averageVelocity; + container[ModalResultField.P_slope] = CurrentState.SlopeResistance * averageVelocity; + container[ModalResultField.P_trac] = CurrentState.VehicleTractionForce * averageVelocity; + + // sanity check: is the vehicle in step with the cycle? + if (container[ModalResultField.dist] == DBNull.Value) { + Log.Warn("Distance field is not set!"); + } else { + var distance = (SI)container[ModalResultField.dist]; + if (!distance.IsEqual(CurrentState.Distance)) { + Log.Warn("Vehicle Distance diverges from Cycle by {0} [m]. Distance: {1}", + (distance - CurrentState.Distance).Value(), distance); + } + } + } + + public Newton RollingResistance(Radian gradient) + { + var weight = ModelData.TotalVehicleWeight; + var gravity = Physics.GravityAccelleration; + var rollCoefficient = ModelData.TotalRollResistanceCoefficient; + + var retVal = Math.Cos(gradient.Value()) * weight * gravity * rollCoefficient; + Log.Debug("RollingResistance: {0}", retVal); + return retVal; + } + + protected internal Newton DriverAcceleration(MeterPerSquareSecond accelleration) + { + var retVal = ModelData.TotalVehicleWeight * accelleration; + Log.Debug("DriverAcceleration: {0}", retVal); + return retVal; + } + + public Newton SlopeResistance(Radian gradient) + { + var retVal = ModelData.TotalVehicleWeight * Physics.GravityAccelleration * Math.Sin(gradient.Value()); + Log.Debug("SlopeResistance: {0}", retVal); + return retVal; + } + + public Newton AirDragResistance(MeterPerSecond previousVelocity, MeterPerSecond nextVelocity) + { + var vAverage = (previousVelocity + nextVelocity) / 2; + if (vAverage.IsEqual(0)) { + return 0.SI<Newton>(); + } + var result = ComputeAirDragPowerLoss(previousVelocity, nextVelocity) / vAverage; + + Log.Debug("AirDragResistance: {0}", result); + return result; + } + + private Watt ComputeAirDragPowerLoss(MeterPerSecond v1, MeterPerSecond v2) + { + return AirdragData.CrossWindCorrectionCurve.AverageAirDragPowerLoss(v1, v2); + } + + public Meter Distance + { + get { return PreviousState.Distance; } + } + + public MeterPerSecond VehicleSpeed + { + get { return PreviousState.Velocity; } + } + + public bool VehicleStopped + { + get { return PreviousState.Velocity.IsEqual(0.SI<MeterPerSecond>(), 0.01.SI<MeterPerSecond>()); } + } + + public Kilogram VehicleMass + { + get { return ModelData.TotalCurbWeight; } + } + + public Kilogram VehicleLoading + { + get { return ModelData.Loading; } + } + + public Kilogram TotalMass + { + get { return ModelData.TotalVehicleWeight; } + } + + public CubicMeter CargoVolume + { + get { return ModelData.CargoVolume; } + } + + public class VehicleState + { + public Meter Distance = 0.SI<Meter>(); + public Second SimulationInterval = 0.SI<Second>(); + public Newton AirDragResistance = 0.SI<Newton>(); + public Newton DriverAcceleration = 0.SI<Newton>(); + public Newton RollingResistance = 0.SI<Newton>(); + public Newton SlopeResistance = 0.SI<Newton>(); + public Newton VehicleTractionForce = 0.SI<Newton>(); + public MeterPerSecond Velocity = 0.SI<MeterPerSecond>(); + public MeterPerSquareSecond Acceleration = 0.SI<MeterPerSquareSecond>(); + + public override string ToString() + { + return + string.Format( + "v: {0} a: {1}, dt: {2}, driver_acc: {3}, roll_res: {4}, slope_res: {5}, air_drag: {6}, traction force: {7}", + Velocity, Acceleration, SimulationInterval, DriverAcceleration, RollingResistance, SlopeResistance, + AirDragResistance, + VehicleTractionForce); + } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/OutputData/FileIO/FileOutputWriter.cs b/VectoCore/VectoCore/OutputData/FileIO/FileOutputWriter.cs index 51f3e6f89c743ec023d4f4d87821b569f1386800..0520e1b177690a05adfe2f0f75cb1efa94c79eb2 100644 --- a/VectoCore/VectoCore/OutputData/FileIO/FileOutputWriter.cs +++ b/VectoCore/VectoCore/OutputData/FileIO/FileOutputWriter.cs @@ -29,89 +29,89 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Data; -using System.IO; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.OutputData.FileIO -{ - public class FileOutputWriter : LoggingObject, IOutputDataWriter - { - private readonly string _jobFile; - - private string BasePath - { - get { return Path.GetDirectoryName(_jobFile); } - } - - public string PDFReportName - { - get { return Path.ChangeExtension(_jobFile, Constants.FileExtensions.PDFReport); } - } - - public string XMLFullReportName - { - get { return Path.ChangeExtension(_jobFile, "RSLT_MANUFACTURER.xml"); } - } - - public string XMLCustomerReportName - { - get { return Path.ChangeExtension(_jobFile, "RSLT_CUSTOMER.xml"); } - } - - - public string SumFileName - { - get { return Path.ChangeExtension(_jobFile, Constants.FileExtensions.SumFile); } - } - - /// <summary> - /// - /// </summary> - /// <param name="jobFile">full path of the json job-file. jobName and basePath are extracted.</param> - public FileOutputWriter(string jobFile) - { - _jobFile = jobFile; - } - - public void WriteSumData(DataTable data) - { - VectoCSVFile.Write(SumFileName, data, true); - } - - public string GetModDataFileName(string runName, string cycleName, string runSuffix) - { - string modFileName; - if (!string.IsNullOrWhiteSpace(cycleName) || !string.IsNullOrWhiteSpace(runSuffix)) { - modFileName = string.Format("{0}_{1}{2}{3}", runName, cycleName, runSuffix, Constants.FileExtensions.ModDataFile); - } else { - modFileName = string.Format("{0}{1}", runName, Constants.FileExtensions.ModDataFile); - } - - return Path.Combine(BasePath, modFileName); - } - - public void WriteModData(string runName, string cycleName, string runSuffix, DataTable modData) - { - VectoCSVFile.Write(GetModDataFileName(runName, cycleName, runSuffix), modData, true); - } - - public Stream WriteStream(ReportType type) - { - switch (type) { - case ReportType.DeclarationReportPdf: - return new FileStream(PDFReportName, FileMode.Create); - case ReportType.DeclarationReportXMLFulll: - return new FileStream(XMLFullReportName, FileMode.Create); - case ReportType.DeclarationReportXMLCOC: - return new FileStream(XMLCustomerReportName, FileMode.Create); - default: - - throw new ArgumentOutOfRangeException("type"); - } - } - } +using System; +using System.Data; +using System.IO; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.OutputData.FileIO +{ + public class FileOutputWriter : LoggingObject, IOutputDataWriter + { + private readonly string _jobFile; + + private string BasePath + { + get { return Path.GetDirectoryName(_jobFile); } + } + + public string PDFReportName + { + get { return Path.ChangeExtension(_jobFile, Constants.FileExtensions.PDFReport); } + } + + public string XMLFullReportName + { + get { return Path.ChangeExtension(_jobFile, "RSLT_MANUFACTURER.xml"); } + } + + public string XMLCustomerReportName + { + get { return Path.ChangeExtension(_jobFile, "RSLT_CUSTOMER.xml"); } + } + + + public string SumFileName + { + get { return Path.ChangeExtension(_jobFile, Constants.FileExtensions.SumFile); } + } + + /// <summary> + /// + /// </summary> + /// <param name="jobFile">full path of the json job-file. jobName and basePath are extracted.</param> + public FileOutputWriter(string jobFile) + { + _jobFile = jobFile; + } + + public void WriteSumData(DataTable data) + { + VectoCSVFile.Write(SumFileName, data, true); + } + + public string GetModDataFileName(string runName, string cycleName, string runSuffix) + { + string modFileName; + if (!string.IsNullOrWhiteSpace(cycleName) || !string.IsNullOrWhiteSpace(runSuffix)) { + modFileName = string.Format("{0}_{1}{2}{3}", runName, cycleName, runSuffix, Constants.FileExtensions.ModDataFile); + } else { + modFileName = string.Format("{0}{1}", runName, Constants.FileExtensions.ModDataFile); + } + + return Path.Combine(BasePath, modFileName); + } + + public void WriteModData(string runName, string cycleName, string runSuffix, DataTable modData) + { + VectoCSVFile.Write(GetModDataFileName(runName, cycleName, runSuffix), modData, true); + } + + public Stream WriteStream(ReportType type) + { + switch (type) { + case ReportType.DeclarationReportPdf: + return new FileStream(PDFReportName, FileMode.Create); + case ReportType.DeclarationReportXMLFulll: + return new FileStream(XMLFullReportName, FileMode.Create); + case ReportType.DeclarationReportXMLCOC: + return new FileStream(XMLCustomerReportName, FileMode.Create); + default: + + throw new ArgumentOutOfRangeException("type"); + } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs index 622d04724afe278f28bc7f2c170bcca68dc41f9a..d58d0a42cb7b122f4016ac40b118223eb777387f 100644 --- a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs +++ b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs @@ -29,529 +29,529 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.Models.Simulation.Impl; - -namespace TUGraz.VectoCore.OutputData -{ - public interface IModalDataFilter - { - ModalResults Filter(ModalResults data); - string ID { get; } - } - - public interface IModalDataContainer - { - /// <summary> - /// Indexer for fields of the DataWriter. Accesses the data of the current step. - /// </summary> - /// <param name="key"></param> - /// <returns></returns> - object this[ModalResultField key] { get; set; } - - /// <summary> - /// Indexer for auxiliary fields of the DataWriter. - /// </summary> - /// <param name="auxId"></param> - /// <returns></returns> - object this[string auxId] { get; set; } - - bool HasTorqueConverter { set; } - - /// <summary> - /// Commits the data of the current simulation step. - /// </summary> - void CommitSimulationStep(); - - FuelData.Entry FuelData { get; } - - VectoRun.Status RunStatus { get; } - - string Error { get; } - - string StackTrace { get; } - - /// <summary> - /// Finishes the writing of the DataWriter. - /// </summary> - void Finish(VectoRun.Status runStatus); - - IEnumerable<T> GetValues<T>(ModalResultField key); - - IEnumerable<T> GetValues<T>(DataColumn col); - - IEnumerable<T> GetValues<T>(Func<DataRow, T> selectorFunc); - - Dictionary<string, DataColumn> Auxiliaries { get; } - - T TimeIntegral<T>(ModalResultField field, Func<SI, bool> filter = null) where T : SIBase<T>; - - void SetDataValue(string fieldName, object value); - - void AddAuxiliary(string id, string columnName = null); - - /// <summary> - /// clear the modal data after the simulation - /// called after the simulation is finished and the sum-entries have been written - /// </summary> - /// <param name="exception"></param> - void FinishSimulation(Exception exception = null); - } - - public static class ModalDataContainerExtensions - { - public static T Max<T>(this IModalDataContainer data, ModalResultField field) - { - return data.GetValues<T>(field).Max(); - } - - public static T Min<T>(this IModalDataContainer data, ModalResultField field) - { - return data.GetValues<T>(field).Min(); - } - - /// <summary> - /// Returns a default value if the SI object is null. - /// </summary> - /// <typeparam name="T">The SI Type.</typeparam> - /// <param name="self">The SI Instance.</param> - /// <param name="defaultValue">The default value.</param> - /// <returns>If self is null, the default value as SI-Type is returned. Otherwise self is returned.</returns> - /// <code> - /// NewtonMeter t = null; - /// var x = t.DefaultIfNull(0); - /// </code> - public static T DefaultIfNull<T>(this T self, double defaultValue) where T : SIBase<T> - { - return self ?? defaultValue.SI<T>(); - } - - public static MeterPerSquareSecond AccelerationsPositive(this IModalDataContainer data) - { - return data.GetValues<MeterPerSquareSecond>(ModalResultField.acc) - .Where(x => x > 0.125) - .DefaultIfEmpty(0.SI<MeterPerSquareSecond>()) - .Average(); - } - - public static MeterPerSquareSecond AccelerationsNegative(this IModalDataContainer data) - { - return data.GetValues<MeterPerSquareSecond>(ModalResultField.acc) - .Where(x => x < -0.125) - .DefaultIfEmpty(0.SI<MeterPerSquareSecond>()) - .Average(); - } - - public static Scalar AccelerationTimeShare(this IModalDataContainer data) - { - var accelerationTimeShare = data.GetValues(x => new { - a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.a > 0.125 ? x.dt : 0.SI<Second>()).DefaultIfNull(0); - return 100 * (accelerationTimeShare / data.Duration()).Cast<Scalar>(); - } - - public static Scalar DecelerationTimeShare(this IModalDataContainer data) - { - var decelerationTimeShare = data.GetValues(x => new { - a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.a < -0.125 ? x.dt : 0.SI<Second>()).DefaultIfNull(0); - return 100 * (decelerationTimeShare / data.Duration()).Cast<Scalar>(); - } - - public static Scalar CruiseTimeShare(this IModalDataContainer data) - { - var cruiseTime = data.GetValues(x => new { - v = x.Field<MeterPerSecond>((int)ModalResultField.v_act).DefaultIfNull(0), - a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.v >= 0.1.KMPHtoMeterPerSecond() && x.a.IsBetween(-0.125, 0.125) ? x.dt : 0.SI<Second>()) - .DefaultIfNull(0); - return 100 * (cruiseTime / data.Duration()).Cast<Scalar>(); - } - - public static Scalar StopTimeShare(this IModalDataContainer data) - { - var stopTime = data.GetValues(x => new { - v = x.Field<MeterPerSecond>((int)ModalResultField.v_act).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.v < 0.1.KMPHtoMeterPerSecond() ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); - return 100 * (stopTime / data.Duration()).Cast<Scalar>(); - } - - public static MeterPerSquareSecond AccelerationAverage(this IModalDataContainer data) - { - return data.TimeIntegral<MeterPerSecond>(ModalResultField.acc) / data.Duration(); - } - - public static Meter AltitudeDelta(this IModalDataContainer data) - { - var altitudes = data.GetValues<Meter>(ModalResultField.altitude).ToList(); - var first = altitudes.First(); - var last = altitudes.Last(); - return first == null || last == null ? null : last - first; - } - - public static WattSecond PowerAccelerations(this IModalDataContainer data) - { - var paEngine = data.TimeIntegral<WattSecond>(ModalResultField.P_eng_inertia); - var paGearbox = data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_inertia); - return paEngine + paGearbox; - } - - public static WattSecond WorkClutch(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_clutch_loss); - } - - public static WattSecond WorkGearshift(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_shift_loss); - } - - public static WattSecond WorkGearbox(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_loss); - } - - public static WattSecond WorkAxlegear(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_axle_loss); - } - - public static WattSecond WorkRetarder(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_ret_loss); - } - - public static WattSecond WorkAngledrive(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_angle_loss); - } - - public static WattSecond WorkTorqueConverter(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_TC_loss); - } - - public static Second Duration(this IModalDataContainer data) - { - var time = data.GetValues<Second>(ModalResultField.time).ToList(); - var dt = data.GetValues<Second>(ModalResultField.simulationInterval).ToList(); - if (time.Count == 1) { - return time.First(); - } - return time.Max() - time.Min() + dt.First() / 2 + dt.Last() / 2; - } - - public static Meter Distance(this IModalDataContainer data) - { - var max = data.Max<Meter>(ModalResultField.dist); - var min = data.Min<Meter>(ModalResultField.dist); - return max == null || min == null ? null : max - min; - } - - public static WattSecond WorkTotalMechanicalBrake(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_brake_loss); - } - - public static WattSecond WorkVehicleInertia(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_veh_inertia) + - data.TimeIntegral<WattSecond>(ModalResultField.P_wheel_inertia); - } - - public static WattSecond WorkAuxiliaries(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_aux); - } - - public static WattSecond WorkRoadGradientResistance(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_slope); - } - - public static WattSecond WorkRollingResistance(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_roll); - } - - public static WattSecond WorkAirResistance(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_air); - } - - - public static WattSecond TotalEngineWorkPositive(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_eng_fcmap, x => x > 0); - } - - public static WattSecond TotalEngineWorkNegative(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_eng_fcmap, x => x < 0); - } - - public static Watt PowerWheelPositive(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_wheel_in, x => x > 0) / data.Duration(); - } - - public static KilogramPerMeter FuelConsumptionWHTC(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCWHTCc) / distance; - } - - public static KilogramPerSecond FuelConsumptionWHTCPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCWHTCc) / data.Duration(); - } - - public static KilogramPerMeter FuelConsumptionAuxStartStop(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCAUXc) / distance; - } - - public static KilogramPerSecond FuelConsumptionAAUXPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCAAUX) / data.Duration(); - } - - public static KilogramPerMeter FuelConsumptionAAUX(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCAAUX) / distance; - } - - public static KilogramPerSecond FuelConsumptionAuxStartStopPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCAUXc) / data.Duration(); - } - - public static KilogramPerSecond FuelConsumptionFinalPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) / data.Duration(); - } - - public static KilogramPerMeter FuelConsumptionFinal(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) / distance; - } - - public static SI FuelConsumptionFinalLiterPer100Kilometer(this IModalDataContainer data) - { - var fuelConsumptionFinal = data.FuelConsumptionFinal(); - if (fuelConsumptionFinal == null || data.FuelData.FuelDensity == null) { - return null; - } - - var fcVolumePerMeter = fuelConsumptionFinal / data.FuelData.FuelDensity; - return fcVolumePerMeter.ConvertTo().Cubic.Dezi.Meter * 100.SI().Kilo.Meter; - } - - public static KilogramPerMeter CO2PerMeter(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) * data.FuelData.CO2PerFuelWeight / distance; - } - - public static JoulePerMeter EnergyPerMeter(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) * data.FuelData.LowerHeatingValue / distance; - } - - public static KilogramPerSecond FCMapPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCMap) / data.Duration(); - } - - public static KilogramPerMeter FCMapPerMeter(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCMap) / distance; - } - - - public static Watt TotalPowerEnginePositiveAverage(this IModalDataContainer data) - { - var simulationIntervals = data.GetValues<Second>(ModalResultField.simulationInterval); - var values = data.GetValues<Watt>(ModalResultField.P_eng_fcmap) - .Zip(simulationIntervals, (value, dt) => new { Dt = dt, Value = value * dt }) - .Where(v => v.Value > 0).ToList(); - if (values.Any()) { - return values.Sum(v => v.Value) / Duration(data); - } - return 0.SI<Watt>(); - } - - public static MeterPerSecond Speed(this IModalDataContainer data) - { - var distance = Distance(data); - var duration = Duration(data); - if (distance == null || duration == null || duration.IsEqual(0)) { - return null; - } - return distance / duration; - } - - public static WattSecond AuxiliaryWork(this IModalDataContainer data, DataColumn auxCol) - { - var simulationIntervals = data.GetValues<Second>(ModalResultField.simulationInterval).ToArray(); - var auxValues = data.GetValues<Watt>(auxCol).ToArray(); - var sum = 0.SI<WattSecond>(); - for (var i = 0; i < simulationIntervals.Length; i++) { - if (auxValues[i] != null && simulationIntervals[i] != null) { - sum += auxValues[i] * simulationIntervals[i]; - } - } - return sum; - } - - - public static MeterPerSecond MaxSpeed(this IModalDataContainer data) - { - return data.Max<MeterPerSecond>(ModalResultField.v_act).DefaultIfNull(0); - } - - public static MeterPerSecond MinSpeed(this IModalDataContainer data) - { - return data.Min<MeterPerSecond>(ModalResultField.v_act).DefaultIfNull(0); - } - - public static MeterPerSquareSecond MaxAcceleration(this IModalDataContainer data) - { - return data.Max<MeterPerSquareSecond>(ModalResultField.acc).DefaultIfNull(0); - } - - public static MeterPerSquareSecond MaxDeceleration(this IModalDataContainer data) - { - return -data.Min<MeterPerSquareSecond>(ModalResultField.acc).DefaultIfNull(0); - } - - public static PerSecond AvgEngineSpeed(this IModalDataContainer data) - { - var integral = data.GetValues(x => x.Field<PerSecond>((int)ModalResultField.n_eng_avg).Value() * - x.Field<Second>((int)ModalResultField.simulationInterval).Value()).Sum(); - return (integral / Duration(data).Value()).SI<PerSecond>(); - } - - public static PerSecond MaxEngineSpeed(this IModalDataContainer data) - { - return data.Max<PerSecond>(ModalResultField.n_eng_avg); - } - - public static Scalar EngineMaxLoadTimeShare(this IModalDataContainer data) - { - var sum = data.GetValues(x => new { - tMax = x.Field<NewtonMeter>((int)ModalResultField.Tq_full).DefaultIfNull(-1), - tEng = x.Field<NewtonMeter>((int)ModalResultField.T_eng_fcmap).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }).Sum(x => x.tMax.IsEqual(x.tEng, 5.SI<NewtonMeter>()) ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); - return 100 * sum / Duration(data); - } - - public static Scalar GearshiftCount(this IModalDataContainer data) - { - var prevGear = data.GetValues<uint>(ModalResultField.Gear).First(); - var gearCount = 0; - - data.GetValues(x => { - var gear = x.Field<uint>((int)ModalResultField.Gear); - var speed = x.Field<MeterPerSecond>((int)ModalResultField.v_act); - if (speed != null && speed.IsSmallerOrEqual(0.1)) { - prevGear = 0; - gearCount++; - return gear; // not used - } - if (gear == 0 || gear == prevGear) { - return gear; // not used - } - gearCount++; - prevGear = gear; - return gear; // not used - }); - return gearCount.SI<Scalar>(); - } - - public static Scalar CoastingTimeShare(this IModalDataContainer data) - { - var sum = data.GetValues(x => new { - DrivingBehavior = x.Field<DrivingBehavior>((int)ModalResultField.drivingBehavior), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.DrivingBehavior == DrivingBehavior.Coasting ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); - return 100 * sum / Duration(data); - } - - public static Scalar BrakingTimeShare(this IModalDataContainer data) - { - var sum = data.GetValues(x => new { - DrivingBehavior = x.Field<DrivingBehavior>((int)ModalResultField.drivingBehavior), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.DrivingBehavior == DrivingBehavior.Braking ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); - return 100 * sum / Duration(data); - } - - public static Dictionary<uint, Scalar> TimeSharePerGear(this IModalDataContainer data, uint gearCount) - { - var retVal = new Dictionary<uint, Scalar>(); - for (uint i = 0; i <= gearCount; i++) { - retVal[i] = 0.SI<Scalar>(); - } - - var gearData = data.GetValues(x => new { - Gear = x.Field<uint>((int)ModalResultField.Gear), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }); - - foreach (var entry in gearData) { - retVal[entry.Gear] += entry.dt.Value(); - } - - var duration = Duration(data).Value(); - for (uint i = 0; i <= gearCount; i++) { - retVal[i] = 100 * retVal[i] / duration; - } - return retVal; - } - } +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.Simulation.Impl; + +namespace TUGraz.VectoCore.OutputData +{ + public interface IModalDataFilter + { + ModalResults Filter(ModalResults data); + string ID { get; } + } + + public interface IModalDataContainer + { + /// <summary> + /// Indexer for fields of the DataWriter. Accesses the data of the current step. + /// </summary> + /// <param name="key"></param> + /// <returns></returns> + object this[ModalResultField key] { get; set; } + + /// <summary> + /// Indexer for auxiliary fields of the DataWriter. + /// </summary> + /// <param name="auxId"></param> + /// <returns></returns> + object this[string auxId] { get; set; } + + bool HasTorqueConverter { set; } + + /// <summary> + /// Commits the data of the current simulation step. + /// </summary> + void CommitSimulationStep(); + + FuelData.Entry FuelData { get; } + + VectoRun.Status RunStatus { get; } + + string Error { get; } + + string StackTrace { get; } + + /// <summary> + /// Finishes the writing of the DataWriter. + /// </summary> + void Finish(VectoRun.Status runStatus); + + IEnumerable<T> GetValues<T>(ModalResultField key); + + IEnumerable<T> GetValues<T>(DataColumn col); + + IEnumerable<T> GetValues<T>(Func<DataRow, T> selectorFunc); + + Dictionary<string, DataColumn> Auxiliaries { get; } + + T TimeIntegral<T>(ModalResultField field, Func<SI, bool> filter = null) where T : SIBase<T>; + + void SetDataValue(string fieldName, object value); + + void AddAuxiliary(string id, string columnName = null); + + /// <summary> + /// clear the modal data after the simulation + /// called after the simulation is finished and the sum-entries have been written + /// </summary> + /// <param name="exception"></param> + void FinishSimulation(Exception exception = null); + } + + public static class ModalDataContainerExtensions + { + public static T Max<T>(this IModalDataContainer data, ModalResultField field) + { + return data.GetValues<T>(field).Max(); + } + + public static T Min<T>(this IModalDataContainer data, ModalResultField field) + { + return data.GetValues<T>(field).Min(); + } + + /// <summary> + /// Returns a default value if the SI object is null. + /// </summary> + /// <typeparam name="T">The SI Type.</typeparam> + /// <param name="self">The SI Instance.</param> + /// <param name="defaultValue">The default value.</param> + /// <returns>If self is null, the default value as SI-Type is returned. Otherwise self is returned.</returns> + /// <code> + /// NewtonMeter t = null; + /// var x = t.DefaultIfNull(0); + /// </code> + public static T DefaultIfNull<T>(this T self, double defaultValue) where T : SIBase<T> + { + return self ?? defaultValue.SI<T>(); + } + + public static MeterPerSquareSecond AccelerationsPositive(this IModalDataContainer data) + { + return data.GetValues<MeterPerSquareSecond>(ModalResultField.acc) + .Where(x => x > 0.125) + .DefaultIfEmpty(0.SI<MeterPerSquareSecond>()) + .Average(); + } + + public static MeterPerSquareSecond AccelerationsNegative(this IModalDataContainer data) + { + return data.GetValues<MeterPerSquareSecond>(ModalResultField.acc) + .Where(x => x < -0.125) + .DefaultIfEmpty(0.SI<MeterPerSquareSecond>()) + .Average(); + } + + public static Scalar AccelerationTimeShare(this IModalDataContainer data) + { + var accelerationTimeShare = data.GetValues(x => new { + a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.a > 0.125 ? x.dt : 0.SI<Second>()).DefaultIfNull(0); + return 100 * (accelerationTimeShare / data.Duration()).Cast<Scalar>(); + } + + public static Scalar DecelerationTimeShare(this IModalDataContainer data) + { + var decelerationTimeShare = data.GetValues(x => new { + a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.a < -0.125 ? x.dt : 0.SI<Second>()).DefaultIfNull(0); + return 100 * (decelerationTimeShare / data.Duration()).Cast<Scalar>(); + } + + public static Scalar CruiseTimeShare(this IModalDataContainer data) + { + var cruiseTime = data.GetValues(x => new { + v = x.Field<MeterPerSecond>((int)ModalResultField.v_act).DefaultIfNull(0), + a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.v >= 0.1.KMPHtoMeterPerSecond() && x.a.IsBetween(-0.125, 0.125) ? x.dt : 0.SI<Second>()) + .DefaultIfNull(0); + return 100 * (cruiseTime / data.Duration()).Cast<Scalar>(); + } + + public static Scalar StopTimeShare(this IModalDataContainer data) + { + var stopTime = data.GetValues(x => new { + v = x.Field<MeterPerSecond>((int)ModalResultField.v_act).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.v < 0.1.KMPHtoMeterPerSecond() ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); + return 100 * (stopTime / data.Duration()).Cast<Scalar>(); + } + + public static MeterPerSquareSecond AccelerationAverage(this IModalDataContainer data) + { + return data.TimeIntegral<MeterPerSecond>(ModalResultField.acc) / data.Duration(); + } + + public static Meter AltitudeDelta(this IModalDataContainer data) + { + var altitudes = data.GetValues<Meter>(ModalResultField.altitude).ToList(); + var first = altitudes.First(); + var last = altitudes.Last(); + return first == null || last == null ? null : last - first; + } + + public static WattSecond PowerAccelerations(this IModalDataContainer data) + { + var paEngine = data.TimeIntegral<WattSecond>(ModalResultField.P_eng_inertia); + var paGearbox = data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_inertia); + return paEngine + paGearbox; + } + + public static WattSecond WorkClutch(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_clutch_loss); + } + + public static WattSecond WorkGearshift(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_shift_loss); + } + + public static WattSecond WorkGearbox(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_loss); + } + + public static WattSecond WorkAxlegear(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_axle_loss); + } + + public static WattSecond WorkRetarder(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_ret_loss); + } + + public static WattSecond WorkAngledrive(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_angle_loss); + } + + public static WattSecond WorkTorqueConverter(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_TC_loss); + } + + public static Second Duration(this IModalDataContainer data) + { + var time = data.GetValues<Second>(ModalResultField.time).ToList(); + var dt = data.GetValues<Second>(ModalResultField.simulationInterval).ToList(); + if (time.Count == 1) { + return time.First(); + } + return time.Max() - time.Min() + dt.First() / 2 + dt.Last() / 2; + } + + public static Meter Distance(this IModalDataContainer data) + { + var max = data.Max<Meter>(ModalResultField.dist); + var min = data.Min<Meter>(ModalResultField.dist); + return max == null || min == null ? null : max - min; + } + + public static WattSecond WorkTotalMechanicalBrake(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_brake_loss); + } + + public static WattSecond WorkVehicleInertia(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_veh_inertia) + + data.TimeIntegral<WattSecond>(ModalResultField.P_wheel_inertia); + } + + public static WattSecond WorkAuxiliaries(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_aux); + } + + public static WattSecond WorkRoadGradientResistance(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_slope); + } + + public static WattSecond WorkRollingResistance(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_roll); + } + + public static WattSecond WorkAirResistance(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_air); + } + + + public static WattSecond TotalEngineWorkPositive(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_eng_fcmap, x => x > 0); + } + + public static WattSecond TotalEngineWorkNegative(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_eng_fcmap, x => x < 0); + } + + public static Watt PowerWheelPositive(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_wheel_in, x => x > 0) / data.Duration(); + } + + public static KilogramPerMeter FuelConsumptionWHTC(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCWHTCc) / distance; + } + + public static KilogramPerSecond FuelConsumptionWHTCPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCWHTCc) / data.Duration(); + } + + public static KilogramPerMeter FuelConsumptionAuxStartStop(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCAUXc) / distance; + } + + public static KilogramPerSecond FuelConsumptionAAUXPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCAAUX) / data.Duration(); + } + + public static KilogramPerMeter FuelConsumptionAAUX(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCAAUX) / distance; + } + + public static KilogramPerSecond FuelConsumptionAuxStartStopPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCAUXc) / data.Duration(); + } + + public static KilogramPerSecond FuelConsumptionFinalPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) / data.Duration(); + } + + public static KilogramPerMeter FuelConsumptionFinal(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) / distance; + } + + public static SI FuelConsumptionFinalLiterPer100Kilometer(this IModalDataContainer data) + { + var fuelConsumptionFinal = data.FuelConsumptionFinal(); + if (fuelConsumptionFinal == null || data.FuelData.FuelDensity == null) { + return null; + } + + var fcVolumePerMeter = fuelConsumptionFinal / data.FuelData.FuelDensity; + return fcVolumePerMeter.ConvertTo().Cubic.Dezi.Meter * 100.SI().Kilo.Meter; + } + + public static KilogramPerMeter CO2PerMeter(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) * data.FuelData.CO2PerFuelWeight / distance; + } + + public static JoulePerMeter EnergyPerMeter(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) * data.FuelData.LowerHeatingValue / distance; + } + + public static KilogramPerSecond FCMapPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCMap) / data.Duration(); + } + + public static KilogramPerMeter FCMapPerMeter(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCMap) / distance; + } + + + public static Watt TotalPowerEnginePositiveAverage(this IModalDataContainer data) + { + var simulationIntervals = data.GetValues<Second>(ModalResultField.simulationInterval); + var values = data.GetValues<Watt>(ModalResultField.P_eng_fcmap) + .Zip(simulationIntervals, (value, dt) => new { Dt = dt, Value = value * dt }) + .Where(v => v.Value > 0).ToList(); + if (values.Any()) { + return values.Sum(v => v.Value) / Duration(data); + } + return 0.SI<Watt>(); + } + + public static MeterPerSecond Speed(this IModalDataContainer data) + { + var distance = Distance(data); + var duration = Duration(data); + if (distance == null || duration == null || duration.IsEqual(0)) { + return null; + } + return distance / duration; + } + + public static WattSecond AuxiliaryWork(this IModalDataContainer data, DataColumn auxCol) + { + var simulationIntervals = data.GetValues<Second>(ModalResultField.simulationInterval).ToArray(); + var auxValues = data.GetValues<Watt>(auxCol).ToArray(); + var sum = 0.SI<WattSecond>(); + for (var i = 0; i < simulationIntervals.Length; i++) { + if (auxValues[i] != null && simulationIntervals[i] != null) { + sum += auxValues[i] * simulationIntervals[i]; + } + } + return sum; + } + + + public static MeterPerSecond MaxSpeed(this IModalDataContainer data) + { + return data.Max<MeterPerSecond>(ModalResultField.v_act).DefaultIfNull(0); + } + + public static MeterPerSecond MinSpeed(this IModalDataContainer data) + { + return data.Min<MeterPerSecond>(ModalResultField.v_act).DefaultIfNull(0); + } + + public static MeterPerSquareSecond MaxAcceleration(this IModalDataContainer data) + { + return data.Max<MeterPerSquareSecond>(ModalResultField.acc).DefaultIfNull(0); + } + + public static MeterPerSquareSecond MaxDeceleration(this IModalDataContainer data) + { + return -data.Min<MeterPerSquareSecond>(ModalResultField.acc).DefaultIfNull(0); + } + + public static PerSecond AvgEngineSpeed(this IModalDataContainer data) + { + var integral = data.GetValues(x => x.Field<PerSecond>((int)ModalResultField.n_eng_avg).Value() * + x.Field<Second>((int)ModalResultField.simulationInterval).Value()).Sum(); + return (integral / Duration(data).Value()).SI<PerSecond>(); + } + + public static PerSecond MaxEngineSpeed(this IModalDataContainer data) + { + return data.Max<PerSecond>(ModalResultField.n_eng_avg); + } + + public static Scalar EngineMaxLoadTimeShare(this IModalDataContainer data) + { + var sum = data.GetValues(x => new { + tMax = x.Field<NewtonMeter>((int)ModalResultField.Tq_full).DefaultIfNull(-1), + tEng = x.Field<NewtonMeter>((int)ModalResultField.T_eng_fcmap).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }).Sum(x => x.tMax.IsEqual(x.tEng, 5.SI<NewtonMeter>()) ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); + return 100 * sum / Duration(data); + } + + public static Scalar GearshiftCount(this IModalDataContainer data) + { + var prevGear = data.GetValues<uint>(ModalResultField.Gear).First(); + var gearCount = 0; + + var shifts = data.GetValues(x => new { + Gear = x.Field<uint>((int)ModalResultField.Gear), + Speed = x.Field<MeterPerSecond>((int)ModalResultField.v_act) + }); + foreach (var entry in shifts) { + if (entry.Speed != null && entry.Speed.IsSmallerOrEqual(0.1)) { + prevGear = 0; + gearCount++; + } + if (entry.Gear == 0 || entry.Gear == prevGear) { + continue; + } + gearCount++; + prevGear = entry.Gear; + } + return gearCount.SI<Scalar>(); + } + + public static Scalar CoastingTimeShare(this IModalDataContainer data) + { + var sum = data.GetValues(x => new { + DrivingBehavior = x.Field<DrivingBehavior>((int)ModalResultField.drivingBehavior), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.DrivingBehavior == DrivingBehavior.Coasting ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); + return 100 * sum / Duration(data); + } + + public static Scalar BrakingTimeShare(this IModalDataContainer data) + { + var sum = data.GetValues(x => new { + DrivingBehavior = x.Field<DrivingBehavior>((int)ModalResultField.drivingBehavior), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.DrivingBehavior == DrivingBehavior.Braking ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); + return 100 * sum / Duration(data); + } + + public static Dictionary<uint, Scalar> TimeSharePerGear(this IModalDataContainer data, uint gearCount) + { + var retVal = new Dictionary<uint, Scalar>(); + for (uint i = 0; i <= gearCount; i++) { + retVal[i] = 0.SI<Scalar>(); + } + + var gearData = data.GetValues(x => new { + Gear = x.Field<uint>((int)ModalResultField.Gear), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }); + + foreach (var entry in gearData) { + retVal[entry.Gear] += entry.dt.Value(); + } + + var duration = Duration(data).Value(); + for (uint i = 0; i <= gearCount; i++) { + retVal[i] = 100 * retVal[i] / duration; + } + return retVal; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/OutputData/XML/XMLDeclarationWriter.cs b/VectoCore/VectoCore/OutputData/XML/XMLDeclarationWriter.cs index 709c66864d9be213919b137e9d8b77cac657237a..fe9019df7c625a08db87a1afcf45d61da2ebb12a 100644 --- a/VectoCore/VectoCore/OutputData/XML/XMLDeclarationWriter.cs +++ b/VectoCore/VectoCore/OutputData/XML/XMLDeclarationWriter.cs @@ -49,8 +49,6 @@ namespace TUGraz.VectoCore.OutputData.XML public class XMLDeclarationWriter : AbstractXMLWriter { private XNamespace componentNamespace; - //private readonly XNamespace _vectoNs = @"../../../API/VectoInput.xsd"; - public XMLDeclarationWriter(string vendor) : base(null, vendor) { @@ -77,7 +75,7 @@ namespace TUGraz.VectoCore.OutputData.XML new XAttribute(xsi + "schemaLocation", string.Format("{0} {1}VectoInput.xsd", rootNamespace, SchemaLocationBaseUrl)), CreateDeclarationJob(data)) - ); + ); return job; } @@ -104,7 +102,7 @@ namespace TUGraz.VectoCore.OutputData.XML new XAttribute(xsi + "schemaLocation", string.Format("{0} {1}VectoComponent.xsd", componentNamespace, SchemaLocationBaseUrl)), content) - ); + ); return component; } @@ -149,17 +147,15 @@ namespace TUGraz.VectoCore.OutputData.XML CreateAxleWheels(data.VehicleInputData), CreateAuxiliaries(data.AuxiliaryInputData()), CreateAirdrag(data.AirdragInputData) - ) - ); + ) + ); } - protected XElement CreateEngine(IEngineDeclarationInputData data, XNamespace ns = null) { var id = string.Format("ENG-{0}", data.Model.RemoveWhitespace()); var fld = FullLoadCurveReader.Create(data.FullLoadCurve, true); return new XElement((ns ?? tns) + XMLNames.Component_Engine, - //new XAttribute(XMLNames.Component_CertificationNumber_Attr, string.Format("ENG-{0}", data.Model)), new XElement(tns + XMLNames.ComponentDataWrapper, new XAttribute(XMLNames.Component_ID_Attr, id), GetDefaultComponentElements(string.Format("ENG-{0}", data.Model), data.Model), @@ -179,13 +175,12 @@ namespace TUGraz.VectoCore.OutputData.XML EmbedDataTable(data.FuelConsumptionMap, AttributeMappings.FuelConsumptionMapMapping)), new XElement(tns + XMLNames.Engine_FullLoadAndDragCurve, EmbedDataTable(data.FullLoadCurve, AttributeMappings.EngineFullLoadCurveMapping) - ) - ), + ) + ), AddSignatureDummy(id) - ); + ); } - protected XElement CreateGearbox(IGearboxDeclarationInputData gbxData, ITorqueConverterDeclarationInputData torqueConverter, XNamespace ns = null) { @@ -203,25 +198,23 @@ namespace TUGraz.VectoCore.OutputData.XML : null, new XElement(tns + XMLNames.Gearbox_Gear_TorqueLossMap, EmbedDataTable(gearData.LossMap, AttributeMappings.TransmissionLossmapMapping)) - ); + ); gears.Add(gear); } var id = string.Format("GBX-{0}", gbxData.Model.RemoveWhitespace()); return new XElement((ns ?? tns) + XMLNames.Component_Gearbox, - //new XAttribute(XMLNames.Component_CertificationNumber_Attr, string.Format("GBX-{0}", gbxData.Model)), new XElement(tns + XMLNames.ComponentDataWrapper, new XAttribute(XMLNames.Component_ID_Attr, id), GetDefaultComponentElements(string.Format("GBX-{0}", gbxData.Model), gbxData.Model), new XElement(tns + XMLNames.Gearbox_TransmissionType, gbxData.Type.ToXMLFormat()), new XElement(tns + XMLNames.Component_Gearbox_CertificationMethod, "Standard values"), gears - ), + ), AddSignatureDummy(id), gbxData.Type.AutomaticTransmission() ? CreateTorqueConverter(torqueConverter) : null - ); + ); } - private XElement CreateTorqueConverter(ITorqueConverterDeclarationInputData data) { if (data == null) { @@ -229,7 +222,6 @@ namespace TUGraz.VectoCore.OutputData.XML } var id = string.Format("TC-{0}", data.Model.RemoveWhitespace()); return new XElement(tns + XMLNames.Component_TorqueConverter, - //new XAttribute(XMLNames.Component_CertificationNumber_Attr, id), new XElement(tns + XMLNames.ComponentDataWrapper, new XAttribute(XMLNames.Component_ID_Attr, id), GetDefaultComponentElements(data.CertificationNumber, data.Model), @@ -239,8 +231,8 @@ namespace TUGraz.VectoCore.OutputData.XML precision: new Dictionary<string, uint>() { { TorqueConverterDataReader.Fields.SpeedRatio, 4 } }) - ) - ), + ) + ), AddSignatureDummy(id)); } @@ -248,7 +240,6 @@ namespace TUGraz.VectoCore.OutputData.XML { var id = string.Format("ANGL-{0}", data.Model.RemoveWhitespace()); return new XElement((ns ?? tns) + XMLNames.Component_Angledrive, - //new XAttribute(XMLNames.Component_CertificationNumber_Attr, "ANGL-" + data.Model), new XElement(tns + XMLNames.ComponentDataWrapper, new XAttribute(XMLNames.Component_ID_Attr, id), GetDefaultComponentElements(data.CertificationNumber, data.Model), @@ -263,24 +254,22 @@ namespace TUGraz.VectoCore.OutputData.XML { var id = string.Format("RET-{0}", data.Model.RemoveWhitespace()); return new XElement((ns ?? tns) + XMLNames.Component_Retarder, - //new XAttribute(XMLNames.Component_CertificationNumber_Attr, "RET-none"), new XElement(tns + XMLNames.ComponentDataWrapper, new XAttribute(XMLNames.Component_ID_Attr, id), GetDefaultComponentElements(data.CertificationNumber, data.Model), new XElement(tns + XMLNames.Component_CertificationMethod, "Standard values"), new XElement(tns + XMLNames.Retarder_RetarderLossMap, EmbedDataTable(data.LossMap, AttributeMappings.RetarderLossmapMapping) - ) - ), + ) + ), AddSignatureDummy(id) - ); + ); } public XElement CreateAxlegear(IAxleGearInputData data, XNamespace ns = null) { var typeId = string.Format("AXLGEAR-{0}", data.Ratio.ToString("F3", CultureInfo.InvariantCulture)); return new XElement((ns ?? tns) + XMLNames.Component_Axlegear, - //new XAttribute(XMLNames.Component_CertificationNumber_Attr, string.Format("AXL-{0}", data.Model)), new XElement(tns + XMLNames.ComponentDataWrapper, new XAttribute(XMLNames.Component_ID_Attr, typeId), GetDefaultComponentElements(typeId, "N.A."), @@ -290,7 +279,7 @@ namespace TUGraz.VectoCore.OutputData.XML new XElement(tns + XMLNames.Axlegear_TorqueLossMap, EmbedDataTable(data.LossMap, AttributeMappings.TransmissionLossmapMapping))), AddSignatureDummy(typeId) - ); + ); } public XElement CreateAxleWheels(IVehicleDeclarationInputData data, XNamespace ns = null) @@ -307,29 +296,26 @@ namespace TUGraz.VectoCore.OutputData.XML new XElement(tns + XMLNames.AxleWheels_Axles_Axle_TwinTyres_Attr, axle.TwinTyres), new XElement(tns + XMLNames.AxleWheels_Axles_Axle_Steered, i == 0), CreateTyre(axle) - )); + )); } return new XElement((ns ?? tns) + XMLNames.Component_AxleWheels, new XElement(tns + XMLNames.ComponentDataWrapper, - //new XAttribute(XMLNames.Component_ID_Attr, - // string.Format("AXLWHL-{0}", data.AxleConfiguration.GetName())), new XElement(tns + XMLNames.AxleWheels_Axles, axles)) - ); + ); } private XElement CreateTyre(IAxleDeclarationInputData axle) { var id = string.Format("TYRE-{0}", axle.Wheels).RemoveWhitespace().Replace("/", "_"); return new XElement(tns + "Tyre", - //new XAttribute(XMLNames.Component_CertificationNumber_Attr, id), new XElement(tns + XMLNames.ComponentDataWrapper, new XAttribute(XMLNames.Component_ID_Attr, id), GetDefaultComponentElements(string.Format("TYRE-{0}", axle.Wheels), axle.Wheels), new XElement(tns + XMLNames.AxleWheels_Axles_Axle_Dimension, axle.Wheels), new XElement(tns + XMLNames.AxleWheels_Axles_Axle_RRCDeclared, axle.RollResistanceCoefficient.ToXMLFormat(4)), new XElement(tns + XMLNames.AxleWheels_Axles_Axle_FzISO, axle.TyreTestLoad.Value().ToXMLFormat(0)) - ), + ), AddSignatureDummy(id)); } @@ -344,10 +330,10 @@ namespace TUGraz.VectoCore.OutputData.XML var aux = new XElement(tns + XMLNames.ComponentDataWrapper); foreach ( var key in - new[] { - AuxiliaryType.Fan, AuxiliaryType.SteeringPump, AuxiliaryType.ElectricSystem, AuxiliaryType.PneumaticSystem, - AuxiliaryType.HVAC - }) { + new[] { + AuxiliaryType.Fan, AuxiliaryType.SteeringPump, AuxiliaryType.ElectricSystem, AuxiliaryType.PneumaticSystem, + AuxiliaryType.HVAC + }) { aux.Add(auxList[key]); } return new XElement(tns + XMLNames.Component_Auxiliaries, aux); @@ -357,15 +343,14 @@ namespace TUGraz.VectoCore.OutputData.XML { var id = string.Format("Airdrag-{0}", data.Model); return new XElement((ns ?? tns) + XMLNames.Component_AirDrag, - //new XAttribute(XMLNames.Component_CertificationNumber_Attr, string.Format("AD-{0}", data.Model)), new XElement(tns + XMLNames.ComponentDataWrapper, new XAttribute(XMLNames.Component_ID_Attr, id), GetDefaultComponentElements(data.Model, "N.A."), - new XElement(tns + "CdxA_0", data.AirDragArea.Value().ToXMLFormat(2)), // TODO - new XElement(tns + "TransferredCdxA", data.AirDragArea.Value().ToXMLFormat(2)), // TODO + new XElement(tns + "CdxA_0", data.AirDragArea.Value().ToXMLFormat(2)), + new XElement(tns + "TransferredCdxA", data.AirDragArea.Value().ToXMLFormat(2)), new XElement(tns + XMLNames.AirDrag_DeclaredCdxA, data.AirDragArea.Value().ToXMLFormat(2))), AddSignatureDummy(id) - ); + ); } private string AuxTypeToXML(AuxiliaryType type) @@ -373,7 +358,6 @@ namespace TUGraz.VectoCore.OutputData.XML return type.ToString(); } - private XElement AddSignatureDummy(string id) { return new XElement(tns + XMLNames.DI_Signature, @@ -385,12 +369,12 @@ namespace TUGraz.VectoCore.OutputData.XML "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithoutComments")), new XElement(di + XMLNames.DI_Signature_Reference_Transforms_Transform, new XAttribute(XMLNames.DI_Signature_Algorithm_Attr, "urn:vecto:xml:2017:canonicalization")) - ), + ), new XElement(di + XMLNames.DI_Signature_Reference_DigestMethod, new XAttribute(XMLNames.DI_Signature_Algorithm_Attr, "http://www.w3.org/2001/04/xmlenc#sha256")), new XElement(di + XMLNames.DI_Signature_Reference_DigestValue, "") - ) - ); + ) + ); } protected XElement[] GetDefaultComponentElements(string componentId, string makeAndModel) diff --git a/VectoCore/VectoCore/OutputData/XML/XMLFullReport.cs b/VectoCore/VectoCore/OutputData/XML/XMLFullReport.cs index 2dc022a0de6aefedd23278404165c24ac7b09dd1..e1706b0b50ec110af1abc5b57d8538d22dfb80bf 100644 --- a/VectoCore/VectoCore/OutputData/XML/XMLFullReport.cs +++ b/VectoCore/VectoCore/OutputData/XML/XMLFullReport.cs @@ -90,8 +90,8 @@ namespace TUGraz.VectoCore.OutputData.XML GetAirDragDescription(modelData.AirdragData), GetAxleWheelsDescription(modelData.VehicleData), GetAuxiliariesDescription(modelData.Aux) - ) - ); + ) + ); InputDataIntegrity = new XElement(tns + "InputDataSignature", modelData.InputDataHash == null ? CreateDummySig() : new XElement(modelData.InputDataHash)); } @@ -102,7 +102,7 @@ namespace TUGraz.VectoCore.OutputData.XML new XElement(di + XMLNames.DI_Signature_Reference_DigestMethod, new XAttribute(XMLNames.DI_Signature_Algorithm_Attr, "null")), new XElement(di + XMLNames.DI_Signature_Reference_DigestValue, "NOT AVAILABLE") - ); + ); } private XElement GetTorqueLimits(CombustionEngineData modelData) @@ -133,7 +133,7 @@ namespace TUGraz.VectoCore.OutputData.XML new XElement(tns + XMLNames.Engine_Displacement, engineData.Displacement.ConvertTo().Cubic.Centi.Meter.ToXMLFormat(0)), new XElement(tns + XMLNames.Engine_FuelType, engineData.FuelType.ToXMLFormat()) - ); + ); } private XElement GetGearboxDescription(GearboxData gearboxData) @@ -143,7 +143,7 @@ namespace TUGraz.VectoCore.OutputData.XML new XElement(tns + XMLNames.Gearbox_TransmissionType, gearboxData.Type.ToXMLFormat()), new XElement(tns + "GearsCount", gearboxData.Gears.Count), new XElement(tns + "TransmissionRatioFinalGear", gearboxData.Gears.Last().Value.Ratio.ToXMLFormat(3)) - ); + ); } private XElement GetTorqueConverterDescription(TorqueConverterData torqueConverterData) @@ -186,7 +186,7 @@ namespace TUGraz.VectoCore.OutputData.XML return new XElement(tns + XMLNames.Component_AirDrag, new XElement(tns + "CertificationMethod", airdragData.CertificationMethod.ToXMLFormat()), new XElement(tns + "CdxA", airdragData.DeclaredAirdragArea.ToXMLFormat(2)) - ); + ); } return new XElement(tns + XMLNames.Component_AirDrag, new XElement(tns + XMLNames.Component_Model, airdragData.ModelName), @@ -194,7 +194,7 @@ namespace TUGraz.VectoCore.OutputData.XML new XElement(tns + "CertificationNumber", airdragData.CertificationNumber), new XElement(tns + XMLNames.DI_Signature_Reference_DigestValue, airdragData.DigestValueInput), new XElement(tns + "CdxA", airdragData.DeclaredAirdragArea.ToXMLFormat(2)) - ); + ); } private XElement GetAxleWheelsDescription(VehicleData vehicleData) @@ -302,16 +302,16 @@ namespace TUGraz.VectoCore.OutputData.XML new XElement(tns + "TotalVehicleMass", new XAttribute("unit", "kg"), result.TotalVehicleWeight.ToXMLFormat(0)), new XElement(tns + "Payload", new XAttribute("unit", "kg"), result.Payload.ToXMLFormat(0)), new XElement(tns + "FuelType", result.FuelType.ToXMLFormat()) - ), + ), new XElement(tns + "VehiclePerformance", new XElement(tns + "AverageSpeed", new XAttribute("unit", "km/h"), result.AverageSpeed.AsKmph.ToXMLFormat(1)), new XElement(tns + "MinSpeed", new XAttribute("unit", "km/h"), result.MinSpeed.AsKmph.ToXMLFormat(1)), new XElement(tns + "MaxSpeed", new XAttribute("unit", "km/h"), result.MaxSpeed.AsKmph.ToXMLFormat(1)), new XElement(tns + "MaxDeceleration", new XAttribute("unit", "m/s²"), result.MaxDeceleration.ToXMLFormat(2)), new XElement(tns + "MaxAcceleration", new XAttribute("unit", "m/s²"), result.MaxAcceleration.ToXMLFormat(2)), - new XElement(tns + "FullLoadDrivingtimePercentage", result.FullLoadPercentage.ToXMLFormat(0)), + new XElement(tns + "FullLoadDrivingtimePercentage", result.FullLoadPercentage.ToXMLFormat(2)), new XElement(tns + "GearshiftCount", result.GearshiftCount.ToXMLFormat(0)) - ), + ), //FC XMLDeclarationReport.GetResults(result, tns, true).Cast<object>().ToArray() }; @@ -334,18 +334,18 @@ namespace TUGraz.VectoCore.OutputData.XML var vehicle = new XElement(VehiclePart); vehicle.Add(InputDataIntegrity); retVal.Add(new XElement(tns + "VectoOutput", - new XAttribute("schemaVersion", "0.4"), - new XAttribute(XNamespace.Xmlns + "xsi", xsi.NamespaceName), - new XAttribute("xmlns", tns), - new XAttribute(XNamespace.Xmlns + "di", di), - new XAttribute(xsi + "schemaLocation", - string.Format("{0} {1}VectoOutput.xsd", tns, AbstractXMLWriter.SchemaLocationBaseUrl)), - new XElement(tns + "Data", - vehicle, - results, - GetApplicationInfo()) + new XAttribute("schemaVersion", "0.4"), + new XAttribute(XNamespace.Xmlns + "xsi", xsi.NamespaceName), + new XAttribute("xmlns", tns), + new XAttribute(XNamespace.Xmlns + "di", di), + new XAttribute(xsi + "schemaLocation", + string.Format("{0} {1}VectoOutput.xsd", tns, AbstractXMLWriter.SchemaLocationBaseUrl)), + new XElement(tns + "Data", + vehicle, + results, + GetApplicationInfo()) ) - ); + ); var stream = new MemoryStream(); var writer = new StreamWriter(stream); writer.Write(retVal); diff --git a/VectoCore/VectoCore/Resources/XSD/VectoOutputCustomer.xsd b/VectoCore/VectoCore/Resources/XSD/VectoOutputCustomer.xsd index aeb336e3e43219ec874004f95210c29f7331956e..52463b1c70511d16d264d9b5c9c8a9a3c3d214c1 100644 --- a/VectoCore/VectoCore/Resources/XSD/VectoOutputCustomer.xsd +++ b/VectoCore/VectoCore/Resources/XSD/VectoOutputCustomer.xsd @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- edited with XMLSpy v2016 rel. 2 (x64) (http://www.altova.com) by Helmut Eichlseder (TU Graz/Inst. f. VKM und THD) --> <!--W3C XML Schema generated by XMLSpy vXMLSpy Professional Edition v2016 rel. 2 (x64) (http://www.altova.com)--> -<xs:schema xmlns="urn:tugraz:ivt:VectoAPI:COCOutput:v0.4" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vdecdef="urn:tugraz:ivt:VectoAPI:DeclarationDefinitions:v0.8" targetNamespace="urn:tugraz:ivt:VectoAPI:COCOutput:v0.4" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.4"> - <xs:import namespace="urn:tugraz:ivt:VectoAPI:DeclarationDefinitions:v0.8" schemaLocation="VectoDeclarationDefinitions.0.8.xsd"/> +<xs:schema xmlns="urn:tugraz:ivt:VectoAPI:CustomerOutput:v0.4" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vdecdef="urn:tugraz:ivt:VectoAPI:DeclarationDefinitions:v1.0" targetNamespace="urn:tugraz:ivt:VectoAPI:CustomerOutput:v0.4" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.4"> + <xs:import namespace="urn:tugraz:ivt:VectoAPI:DeclarationDefinitions:v1.0" schemaLocation="VectoDeclarationDefinitions.1.0.xsd"/> <xs:element name="VectoCustomerInformation"> <xs:annotation> <xs:documentation>Comment describing your root element</xs:documentation> diff --git a/VectoCore/VectoCore/Resources/XSD/VectoOutputManufacturer.xsd b/VectoCore/VectoCore/Resources/XSD/VectoOutputManufacturer.xsd index 214b10f49d4ce751414d8730cc79f394d2ca5474..e1bc1a3fa3118ee96b015bc4a3a5cefe2c72689f 100644 --- a/VectoCore/VectoCore/Resources/XSD/VectoOutputManufacturer.xsd +++ b/VectoCore/VectoCore/Resources/XSD/VectoOutputManufacturer.xsd @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- edited with XMLSpy v2016 rel. 2 (x64) (http://www.altova.com) by Helmut Eichlseder (TU Graz/Inst. f. VKM und THD) --> <!--W3C XML Schema generated by XMLSpy vXMLSpy Professional Edition v2016 rel. 2 (x64) (http://www.altova.com)--> -<xs:schema xmlns="urn:tugraz:ivt:VectoAPI:DeclarationOutput:v0.4" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vdecdef="urn:tugraz:ivt:VectoAPI:DeclarationDefinitions:v0.8" targetNamespace="urn:tugraz:ivt:VectoAPI:DeclarationOutput:v0.4" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.4"> - <xs:import namespace="urn:tugraz:ivt:VectoAPI:DeclarationDefinitions:v0.8" schemaLocation="VectoDeclarationDefinitions.0.8.xsd"/> +<xs:schema xmlns="urn:tugraz:ivt:VectoAPI:DeclarationOutput:v0.4" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vdecdef="urn:tugraz:ivt:VectoAPI:DeclarationDefinitions:v1.0" targetNamespace="urn:tugraz:ivt:VectoAPI:DeclarationOutput:v0.4" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.4"> + <xs:import namespace="urn:tugraz:ivt:VectoAPI:DeclarationDefinitions:v1.0" schemaLocation="VectoDeclarationDefinitions.1.0.xsd"/> <xs:element name="VectoOutput"> <xs:annotation> <xs:documentation>Comment describing your root element</xs:documentation> diff --git a/VectoCore/VectoCoreTest/FileIO/JsonTest.cs b/VectoCore/VectoCoreTest/FileIO/JsonTest.cs index 25bd9dda532352fcec1dd26b0776a82f9fb0d67c..c33efbd250ff758d48976aeeab3d394d1e937870 100644 --- a/VectoCore/VectoCoreTest/FileIO/JsonTest.cs +++ b/VectoCore/VectoCoreTest/FileIO/JsonTest.cs @@ -29,420 +29,476 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System.IO; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.InputData.FileIO.JSON; -using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; -using TUGraz.VectoCore.Tests.Utils; - -namespace TUGraz.VectoCore.Tests.FileIO -{ - [TestClass] - public class JsonTest - { - private const string TestJobFile = @"Testdata\Jobs\40t_Long_Haul_Truck.vecto"; - private const string TestVehicleFile = @"Testdata\Components\24t Coach.vveh"; - - [TestMethod] - public void ReadJobTest() - { - var job = JSONInputDataFactory.ReadJsonJob(TestJobFile); - - Assert.IsNotNull(job); - // AssertHelper.Exception<InvalidFileFormatException>(() => ); - } - - [TestMethod] - public void NoEngineFileTest() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - ((JObject)json["Body"]).Property("EngineFile").Remove(); - - AssertHelper.Exception<VectoException>(() => new JSONInputDataV2(json, TestJobFile), - "JobFile: Failed to read Engine file '': Key EngineFile not found"); - } - - [TestMethod] - public void NoGearboxFileTest() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - ((JObject)json["Body"]).Property("GearboxFile").Remove(); - - AssertHelper.Exception<VectoException>(() => new JSONInputDataV2(json, TestJobFile), - "JobFile: Failed to read Gearbox file '': Key GearboxFile not found"); - } - - [TestMethod] - public void NoVehicleFileTest() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - ((JObject)json["Body"]).Property("VehicleFile").Remove(); - - AssertHelper.Exception<VectoException>(() => new JSONInputDataV2(json, TestJobFile), - "JobFile: Failed to read Vehicle file '': Key VehicleFile not found"); - } - - [TestMethod] - public void NoCyclesTest() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - ((JObject)json["Body"]).Property("Cycles").Remove(); - - var tmp = new JSONInputDataV2(json, TestJobFile).Cycles; - Assert.AreEqual(0, tmp.Count); - } - - [TestMethod] - public void NoAuxTest() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - ((JObject)json["Body"]).Property("Aux").Remove(); - - // MK,2016-01-20: Changed for PWheel: aux entry may be missing, and that is ok. - var tmp = new JSONInputDataV2(json, TestJobFile).AuxiliaryInputData().Auxiliaries; - Assert.IsTrue(tmp.Count == 0); - } - - [TestMethod] - public void NoDriverAccCurveTest() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - ((JObject)json["Body"]).Property("VACC").Remove(); - - IEngineeringInputDataProvider input = new JSONInputDataV2(json, TestJobFile); - var tmp = input.DriverInputData.AccelerationCurve; - Assert.IsNull(tmp); - } - - [TestMethod] - public void UseDeclarationDriverAccCurveTest() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - json["Body"]["VACC"] = "Truck"; - - IEngineeringInputDataProvider input = new JSONInputDataV2(json, TestJobFile); - var tmp = input.DriverInputData.AccelerationCurve; - Assert.IsNotNull(tmp); - } - - [TestMethod] - public void NoLookaheadCoastingTest() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - ((JObject)json["Body"]).Property("LAC").Remove(); - - IEngineeringInputDataProvider input = new JSONInputDataV2(json, TestJobFile); - var tmp = input.DriverInputData.Lookahead; - Assert.IsNull(tmp); - } - - [TestMethod] - public void NoOverspeedEcoRollTest() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - ((JObject)json["Body"]).Property("OverSpeedEcoRoll").Remove(); - - AssertHelper.Exception<VectoException>( - () => { var tmp = new JSONInputDataV2(json, TestJobFile).DriverInputData.OverSpeedEcoRoll; }, - "Key OverSpeedEcoRoll not found"); - } - - [TestMethod] - public void ReadGearboxV5() - { - var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\Gearbox_v5.vgbx"); - - var ratios = new[] { 3.0, 1.0, 0.8 }; - Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); - for (int i = 0; i < ratios.Length; i++) { - Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); - } - var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, - MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, - 0.5.SI<Meter>(), - true); - Assert.AreEqual(ratios.Length, gbxData.Gears.Count); - - // interpreted as gearbox with first and second gear using TC (due to gear ratios) - Assert.IsFalse(gbxData.Gears[1].HasLockedGear); - Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); - Assert.IsTrue(gbxData.Gears[2].HasLockedGear); - Assert.IsTrue(gbxData.Gears[2].HasTorqueConverter); - Assert.IsTrue(gbxData.Gears[3].HasLockedGear); - Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); - } - - [TestMethod] - public void ReadGearboxSerialTC() - { - var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\GearboxSerial.vgbx"); - - var ratios = new[] { 3.4, 1.9, 1.42, 1.0, 0.7, 0.62 }; - Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); - for (int i = 0; i < ratios.Length; i++) { - Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); - } - var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, - MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, - 0.5.SI<Meter>(), - true); - Assert.AreEqual(ratios.Length, gbxData.Gears.Count); - - Assert.IsTrue(gbxData.Gears[1].HasLockedGear); - Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); - Assert.IsTrue(gbxData.Gears[2].HasLockedGear); - Assert.IsFalse(gbxData.Gears[2].HasTorqueConverter); - Assert.IsTrue(gbxData.Gears[3].HasLockedGear); - Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); - - var gear = gbxData.Gears[1]; - Assert.AreEqual(gear.Ratio, gear.TorqueConverterRatio); - } - - [TestMethod] - public void ReadGearboxPowersplitTC() - { - var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\GearboxPowerSplit.vgbx"); - - var ratios = new[] { 1.35, 1.0, 0.73 }; - Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); - for (int i = 0; i < ratios.Length; i++) { - Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); - } - var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, - MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, - 0.5.SI<Meter>(), - true); - Assert.AreEqual(ratios.Length, gbxData.Gears.Count); - - Assert.IsTrue(gbxData.Gears[1].HasLockedGear); - Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); - Assert.IsTrue(gbxData.Gears[2].HasLockedGear); - Assert.IsFalse(gbxData.Gears[2].HasTorqueConverter); - Assert.IsTrue(gbxData.Gears[3].HasLockedGear); - Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); - - Assert.AreEqual(1, gbxData.Gears[1].TorqueConverterRatio); - } - - [TestMethod] - public void ReadGearboxDualTC() - { - var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\GearboxSerialDualTC.vgbx"); - - var ratios = new[] { 4.35, 2.4, 1.8, 1.3, 1.0 }; - Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); - for (int i = 0; i < ratios.Length; i++) { - Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); - } - var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, - MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, - 0.5.SI<Meter>(), - true); - Assert.AreEqual(ratios.Length, gbxData.Gears.Count); - - Assert.IsFalse(gbxData.Gears[1].HasLockedGear); - Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); - Assert.IsTrue(gbxData.Gears[2].HasLockedGear); - Assert.IsTrue(gbxData.Gears[2].HasTorqueConverter); - Assert.IsTrue(gbxData.Gears[3].HasLockedGear); - Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); - - - var gear = gbxData.Gears[2]; - Assert.AreEqual(gear.Ratio, gear.TorqueConverterRatio); - } - - //[TestMethod] - //public void TestReadingElectricTechlist() - //{ - // var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); - // ((JArray)json["Body"]["Aux"][3]["TechList"]).Add("LED lights"); - - // var job = new JSONInputDataV2(json, TestJobFile); - // foreach (var aux in job.Auxiliaries) { - // if (aux.ID == "ES") { - // Assert.AreEqual(1, aux.TechList.Count); - // Assert.AreEqual("LED lights", aux.TechList.First()); - // } - // } - //} - - [TestMethod] - public void JSON_Read_AngleGear() - { - var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestVehicleFile))); - var angleGear = json["Body"]["Angledrive"]; - - Assert.AreEqual(AngledriveType.SeparateAngledrive, - angleGear["Type"].Value<string>().ParseEnum<AngledriveType>()); - Assert.AreEqual(3.5, angleGear["Ratio"].Value<double>()); - Assert.AreEqual("AngleGear.vtlm", angleGear["LossMap"].Value<string>()); - } - } - - // [TestClass] - // public class JsonTest - // { - // private const string jsonExpected = @"{ - // ""CreatedBy"": ""Michael Krisper"", - // ""Date"": ""2015-11-17T11:49:03Z"", - // ""AppVersion"": ""3.0.1.320"", - // ""FileVersion"": 7 - //}"; - - // private const string jsonExpected2 = @"{ - // ""CreatedBy"": ""Michael Krisper"", - // ""Date"": ""2015-01-07T11:49:03Z"", - // ""AppVersion"": ""3.0.1.320"", - // ""FileVersion"": 7 - //}"; - - // [TestMethod] - // public void TestJsonHeaderEquality() - // { - // var h1 = new JsonDataHeader { - // AppVersion = "MyVecto3", - // CreatedBy = "UnitTest", - // Date = new DateTime(1970, 1, 1), - // FileVersion = 3 - // }; - // var h2 = new JsonDataHeader { - // AppVersion = "MyVecto3", - // CreatedBy = "UnitTest", - // Date = new DateTime(1970, 1, 1), - // FileVersion = 3 - // }; - // Assert.AreEqual(h1, h1); - // Assert.AreEqual(h1, h2); - // Assert.AreNotEqual(h1, null); - // Assert.AreNotEqual(h1, "hello world"); - // } - - // [TestMethod] - // public void Test_Json_DateFormat_German() - // { - // var json = @"{ - // ""CreatedBy"": ""Michael Krisper"", - // ""Date"": ""17.11.2015 11:49:03"", - // ""AppVersion"": ""3.0.1.320"", - // ""FileVersion"": 7 - //}"; - // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); - - // Assert.AreEqual("3.0.1.320", header.AppVersion); - // Assert.AreEqual(7u, header.FileVersion); - // Assert.AreEqual("Michael Krisper", header.CreatedBy); - // Assert.AreEqual(new DateTime(2015, 11, 17, 11, 49, 3, DateTimeKind.Utc), header.Date); - - // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); - // Assert.AreEqual(jsonExpected, jsonCompare); - // } - - // [TestMethod] - // public void Test_Json_DateFormat_German2() - // { - // var json = @"{ - // ""CreatedBy"": ""Michael Krisper"", - // ""Date"": ""7.1.2015 11:49:03"", - // ""AppVersion"": ""3.0.1.320"", - // ""FileVersion"": 7 - //}"; - // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); - - // Assert.AreEqual("3.0.1.320", header.AppVersion); - // Assert.AreEqual(7u, header.FileVersion); - // Assert.AreEqual("Michael Krisper", header.CreatedBy); - // Assert.AreEqual(new DateTime(2015, 1, 7, 11, 49, 3, DateTimeKind.Utc), header.Date); - - // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); - // Assert.AreEqual(jsonExpected2, jsonCompare); - // } - - // [TestMethod] - // public void Test_Json_DateFormat_English() - // { - // var json = @"{ - // ""CreatedBy"": ""Michael Krisper"", - // ""Date"": ""11/17/2015 11:49:03 AM"", - // ""AppVersion"": ""3.0.1.320"", - // ""FileVersion"": 7 - //}"; - // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); - - // Assert.AreEqual("3.0.1.320", header.AppVersion); - // Assert.AreEqual(7u, header.FileVersion); - // Assert.AreEqual("Michael Krisper", header.CreatedBy); - // Assert.AreEqual(new DateTime(2015, 11, 17, 11, 49, 3, DateTimeKind.Utc), header.Date); - - // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); - // Assert.AreEqual(jsonExpected, jsonCompare); - // } - - // [TestMethod] - // public void Test_Json_DateFormat_English2() - // { - // var json = @"{ - // ""CreatedBy"": ""Michael Krisper"", - // ""Date"": ""1/7/2015 11:49:03 AM"", - // ""AppVersion"": ""3.0.1.320"", - // ""FileVersion"": 7 - //}"; - // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); - - // Assert.AreEqual("3.0.1.320", header.AppVersion); - // Assert.AreEqual(7u, header.FileVersion); - // Assert.AreEqual("Michael Krisper", header.CreatedBy); - // Assert.AreEqual(new DateTime(2015, 1, 7, 11, 49, 3, DateTimeKind.Utc), header.Date); - - // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); - // Assert.AreEqual(jsonExpected2, jsonCompare); - // } - - // [TestMethod] - // public void Test_Json_DateFormat_ISO8601() - // { - // var json = @"{ - // ""CreatedBy"": ""Michael Krisper"", - // ""Date"": ""2015-11-17T11:49:03Z"", - // ""AppVersion"": ""3.0.1.320"", - // ""FileVersion"": 7 - //}"; - // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); - - // Assert.AreEqual("3.0.1.320", header.AppVersion); - // Assert.AreEqual(7u, header.FileVersion); - // Assert.AreEqual("Michael Krisper", header.CreatedBy); - // Assert.AreEqual(new DateTime(2015, 11, 17, 11, 49, 3, DateTimeKind.Utc), header.Date); - - // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); - // Assert.AreEqual(json, jsonCompare); - // } - - // [TestMethod] - // public void Test_Json_DateFormat_ISO8601_CET() - // { - // var json = @"{ - // ""CreatedBy"": ""Michael Krisper"", - // ""Date"": ""2015-11-17T11:49:03+01:00"", - // ""AppVersion"": ""3.0.1.320"", - // ""FileVersion"": 7 - //}"; - // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); - - // Assert.AreEqual("3.0.1.320", header.AppVersion); - // Assert.AreEqual(7u, header.FileVersion); - // Assert.AreEqual("Michael Krisper", header.CreatedBy); - // Assert.AreEqual(new DateTime(2015, 11, 17, 11, 49, 3, DateTimeKind.Utc), header.Date); - - // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); - // Assert.AreEqual(json, jsonCompare); - // } - // } +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.IO; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.FileIO.JSON; +using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; +using TUGraz.VectoCore.Tests.Utils; + +namespace TUGraz.VectoCore.Tests.FileIO +{ + [TestClass] + public class JsonTest + { + private const string TestJobFile = @"Testdata\Jobs\40t_Long_Haul_Truck.vecto"; + private const string TestVehicleFile = @"Testdata\Components\24t Coach.vveh"; + + [TestMethod] + public void ReadJobTest() + { + var job = JSONInputDataFactory.ReadJsonJob(TestJobFile); + + Assert.IsNotNull(job); + // AssertHelper.Exception<InvalidFileFormatException>(() => ); + } + + [TestMethod] + public void NoEngineFileTest() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + ((JObject)json["Body"]).Property("EngineFile").Remove(); + + AssertHelper.Exception<VectoException>(() => new JSONInputDataV2(json, TestJobFile), + "JobFile: Failed to read Engine file '': Key EngineFile not found"); + } + + [TestMethod] + public void NoGearboxFileTest() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + ((JObject)json["Body"]).Property("GearboxFile").Remove(); + + AssertHelper.Exception<VectoException>(() => new JSONInputDataV2(json, TestJobFile), + "JobFile: Failed to read Gearbox file '': Key GearboxFile not found"); + } + + [TestMethod] + public void NoVehicleFileTest() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + ((JObject)json["Body"]).Property("VehicleFile").Remove(); + + AssertHelper.Exception<VectoException>(() => new JSONInputDataV2(json, TestJobFile), + "JobFile: Failed to read Vehicle file '': Key VehicleFile not found"); + } + + [TestMethod] + public void NoCyclesTest() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + ((JObject)json["Body"]).Property("Cycles").Remove(); + + var tmp = new JSONInputDataV2(json, TestJobFile).Cycles; + Assert.AreEqual(0, tmp.Count); + } + + [TestMethod] + public void NoAuxTest() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + ((JObject)json["Body"]).Property("Aux").Remove(); + + // MK,2016-01-20: Changed for PWheel: aux entry may be missing, and that is ok. + var tmp = new JSONInputDataV2(json, TestJobFile).AuxiliaryInputData().Auxiliaries; + Assert.IsTrue(tmp.Count == 0); + } + + [TestMethod] + public void NoDriverAccCurveTest() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + ((JObject)json["Body"]).Property("VACC").Remove(); + + IEngineeringInputDataProvider input = new JSONInputDataV2(json, TestJobFile); + var tmp = input.DriverInputData.AccelerationCurve; + Assert.IsNull(tmp); + } + + [TestMethod] + public void UseDeclarationDriverAccCurveTest() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + json["Body"]["VACC"] = "Truck"; + + IEngineeringInputDataProvider input = new JSONInputDataV2(json, TestJobFile); + var tmp = input.DriverInputData.AccelerationCurve; + Assert.IsNotNull(tmp); + } + + [TestMethod] + public void NoLookaheadCoastingTest() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + ((JObject)json["Body"]).Property("LAC").Remove(); + + IEngineeringInputDataProvider input = new JSONInputDataV2(json, TestJobFile); + var tmp = input.DriverInputData.Lookahead; + Assert.IsNull(tmp); + } + + [TestMethod] + public void NoOverspeedEcoRollTest() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + ((JObject)json["Body"]).Property("OverSpeedEcoRoll").Remove(); + + AssertHelper.Exception<VectoException>( + () => { var tmp = new JSONInputDataV2(json, TestJobFile).DriverInputData.OverSpeedEcoRoll; }, + "Key OverSpeedEcoRoll not found"); + } + + [TestMethod] + public void ReadGearboxV5() + { + var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\Gearbox_v5.vgbx"); + + var ratios = new[] { 3.0, 1.0, 0.8 }; + Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); + for (int i = 0; i < ratios.Length; i++) { + Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); + } + var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, + MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, + 0.5.SI<Meter>(), VehicleCategory.RigidTruck, + true); + Assert.AreEqual(ratios.Length, gbxData.Gears.Count); + + // interpreted as gearbox with first and second gear using TC (due to gear ratios) + Assert.IsFalse(gbxData.Gears[1].HasLockedGear); + Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[2].HasLockedGear); + Assert.IsTrue(gbxData.Gears[2].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[3].HasLockedGear); + Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); + } + + [TestMethod] + public void ReadGearboxSerialTC() + { + var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\GearboxSerial.vgbx"); + + var ratios = new[] { 3.4, 1.9, 1.42, 1.0, 0.7, 0.62 }; + Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); + for (int i = 0; i < ratios.Length; i++) { + Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); + } + var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, + MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, + 0.5.SI<Meter>(), VehicleCategory.RigidTruck, + true); + Assert.AreEqual(ratios.Length, gbxData.Gears.Count); + + Assert.IsTrue(gbxData.Gears[1].HasLockedGear); + Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[2].HasLockedGear); + Assert.IsFalse(gbxData.Gears[2].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[3].HasLockedGear); + Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); + + var gear = gbxData.Gears[1]; + Assert.AreEqual(gear.Ratio, gear.TorqueConverterRatio); + } + + [TestMethod] + public void ReadGearboxPowersplitTC() + { + var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\GearboxPowerSplit.vgbx"); + + var ratios = new[] { 1.35, 1.0, 0.73 }; + Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); + for (int i = 0; i < ratios.Length; i++) { + Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); + } + var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, + MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, + 0.5.SI<Meter>(), VehicleCategory.RigidTruck, + true); + Assert.AreEqual(ratios.Length, gbxData.Gears.Count); + + Assert.IsTrue(gbxData.Gears[1].HasLockedGear); + Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[2].HasLockedGear); + Assert.IsFalse(gbxData.Gears[2].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[3].HasLockedGear); + Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); + + Assert.AreEqual(1, gbxData.Gears[1].TorqueConverterRatio); + } + + [TestMethod] + public void ReadGearboxDualTCTruck() + { + var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\GearboxSerialDualTC.vgbx"); + + var ratios = new[] { 4.35, 2.4, 1.8, 1.3, 1.0 }; + Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); + for (int i = 0; i < ratios.Length; i++) { + Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); + } + var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, + MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, + 0.5.SI<Meter>(), VehicleCategory.RigidTruck, + true); + Assert.AreEqual(ratios.Length, gbxData.Gears.Count); + + Assert.IsFalse(gbxData.Gears[1].HasLockedGear); + Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[2].HasLockedGear); + Assert.IsTrue(gbxData.Gears[2].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[3].HasLockedGear); + Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); + + + var gear = gbxData.Gears[2]; + Assert.AreEqual(gear.Ratio, gear.TorqueConverterRatio); + } + + [TestMethod] + public void ReadGearboxSingleTCBus() + { + var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\GearboxSerialDualTC.vgbx"); + + var ratios = new[] { 4.35, 2.4, 1.8, 1.3, 1.0 }; + Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); + for (int i = 0; i < ratios.Length; i++) { + Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); + } + var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, + MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, + 0.5.SI<Meter>(), VehicleCategory.InterurbanBus, + true); + Assert.AreEqual(ratios.Length, gbxData.Gears.Count); + + Assert.IsTrue(gbxData.Gears[1].HasLockedGear); + Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[2].HasLockedGear); + Assert.IsFalse(gbxData.Gears[2].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[3].HasLockedGear); + Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); + + + var gear = gbxData.Gears[1]; + Assert.AreEqual(gear.Ratio, gear.TorqueConverterRatio); + } + + [TestMethod] + public void ReadGearboxDualTCBus() + { + var inputProvider = JSONInputDataFactory.ReadGearbox(@"TestData\Components\AT_GBX\GearboxSerialDualTCBus.vgbx"); + + var ratios = new[] { 4.58, 2.4, 1.8, 1.3, 1.0 }; + Assert.AreEqual(ratios.Length, inputProvider.Gears.Count); + for (int i = 0; i < ratios.Length; i++) { + Assert.AreEqual(ratios[i], inputProvider.Gears[i].Ratio); + } + var gbxData = new EngineeringDataAdapter().CreateGearboxData(inputProvider, + MockSimulationDataFactory.CreateEngineDataFromFile(@"TestData\Components\AT_GBX\Engine.veng", 0), 2.1, + 0.5.SI<Meter>(), VehicleCategory.InterurbanBus, + true); + Assert.AreEqual(ratios.Length, gbxData.Gears.Count); + + Assert.IsFalse(gbxData.Gears[1].HasLockedGear); + Assert.IsTrue(gbxData.Gears[1].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[2].HasLockedGear); + Assert.IsTrue(gbxData.Gears[2].HasTorqueConverter); + Assert.IsTrue(gbxData.Gears[3].HasLockedGear); + Assert.IsFalse(gbxData.Gears[3].HasTorqueConverter); + + + var gear = gbxData.Gears[2]; + Assert.AreEqual(gear.Ratio, gear.TorqueConverterRatio); + } + + //[TestMethod] + //public void TestReadingElectricTechlist() + //{ + // var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestJobFile))); + // ((JArray)json["Body"]["Aux"][3]["TechList"]).Add("LED lights"); + + // var job = new JSONInputDataV2(json, TestJobFile); + // foreach (var aux in job.Auxiliaries) { + // if (aux.ID == "ES") { + // Assert.AreEqual(1, aux.TechList.Count); + // Assert.AreEqual("LED lights", aux.TechList.First()); + // } + // } + //} + + [TestMethod] + public void JSON_Read_AngleGear() + { + var json = (JObject)JToken.ReadFrom(new JsonTextReader(File.OpenText(TestVehicleFile))); + var angleGear = json["Body"]["Angledrive"]; + + Assert.AreEqual(AngledriveType.SeparateAngledrive, + angleGear["Type"].Value<string>().ParseEnum<AngledriveType>()); + Assert.AreEqual(3.5, angleGear["Ratio"].Value<double>()); + Assert.AreEqual("AngleGear.vtlm", angleGear["LossMap"].Value<string>()); + } + } + + // [TestClass] + // public class JsonTest + // { + // private const string jsonExpected = @"{ + // ""CreatedBy"": ""Michael Krisper"", + // ""Date"": ""2015-11-17T11:49:03Z"", + // ""AppVersion"": ""3.0.1.320"", + // ""FileVersion"": 7 + //}"; + + // private const string jsonExpected2 = @"{ + // ""CreatedBy"": ""Michael Krisper"", + // ""Date"": ""2015-01-07T11:49:03Z"", + // ""AppVersion"": ""3.0.1.320"", + // ""FileVersion"": 7 + //}"; + + // [TestMethod] + // public void TestJsonHeaderEquality() + // { + // var h1 = new JsonDataHeader { + // AppVersion = "MyVecto3", + // CreatedBy = "UnitTest", + // Date = new DateTime(1970, 1, 1), + // FileVersion = 3 + // }; + // var h2 = new JsonDataHeader { + // AppVersion = "MyVecto3", + // CreatedBy = "UnitTest", + // Date = new DateTime(1970, 1, 1), + // FileVersion = 3 + // }; + // Assert.AreEqual(h1, h1); + // Assert.AreEqual(h1, h2); + // Assert.AreNotEqual(h1, null); + // Assert.AreNotEqual(h1, "hello world"); + // } + + // [TestMethod] + // public void Test_Json_DateFormat_German() + // { + // var json = @"{ + // ""CreatedBy"": ""Michael Krisper"", + // ""Date"": ""17.11.2015 11:49:03"", + // ""AppVersion"": ""3.0.1.320"", + // ""FileVersion"": 7 + //}"; + // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); + + // Assert.AreEqual("3.0.1.320", header.AppVersion); + // Assert.AreEqual(7u, header.FileVersion); + // Assert.AreEqual("Michael Krisper", header.CreatedBy); + // Assert.AreEqual(new DateTime(2015, 11, 17, 11, 49, 3, DateTimeKind.Utc), header.Date); + + // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); + // Assert.AreEqual(jsonExpected, jsonCompare); + // } + + // [TestMethod] + // public void Test_Json_DateFormat_German2() + // { + // var json = @"{ + // ""CreatedBy"": ""Michael Krisper"", + // ""Date"": ""7.1.2015 11:49:03"", + // ""AppVersion"": ""3.0.1.320"", + // ""FileVersion"": 7 + //}"; + // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); + + // Assert.AreEqual("3.0.1.320", header.AppVersion); + // Assert.AreEqual(7u, header.FileVersion); + // Assert.AreEqual("Michael Krisper", header.CreatedBy); + // Assert.AreEqual(new DateTime(2015, 1, 7, 11, 49, 3, DateTimeKind.Utc), header.Date); + + // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); + // Assert.AreEqual(jsonExpected2, jsonCompare); + // } + + // [TestMethod] + // public void Test_Json_DateFormat_English() + // { + // var json = @"{ + // ""CreatedBy"": ""Michael Krisper"", + // ""Date"": ""11/17/2015 11:49:03 AM"", + // ""AppVersion"": ""3.0.1.320"", + // ""FileVersion"": 7 + //}"; + // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); + + // Assert.AreEqual("3.0.1.320", header.AppVersion); + // Assert.AreEqual(7u, header.FileVersion); + // Assert.AreEqual("Michael Krisper", header.CreatedBy); + // Assert.AreEqual(new DateTime(2015, 11, 17, 11, 49, 3, DateTimeKind.Utc), header.Date); + + // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); + // Assert.AreEqual(jsonExpected, jsonCompare); + // } + + // [TestMethod] + // public void Test_Json_DateFormat_English2() + // { + // var json = @"{ + // ""CreatedBy"": ""Michael Krisper"", + // ""Date"": ""1/7/2015 11:49:03 AM"", + // ""AppVersion"": ""3.0.1.320"", + // ""FileVersion"": 7 + //}"; + // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); + + // Assert.AreEqual("3.0.1.320", header.AppVersion); + // Assert.AreEqual(7u, header.FileVersion); + // Assert.AreEqual("Michael Krisper", header.CreatedBy); + // Assert.AreEqual(new DateTime(2015, 1, 7, 11, 49, 3, DateTimeKind.Utc), header.Date); + + // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); + // Assert.AreEqual(jsonExpected2, jsonCompare); + // } + + // [TestMethod] + // public void Test_Json_DateFormat_ISO8601() + // { + // var json = @"{ + // ""CreatedBy"": ""Michael Krisper"", + // ""Date"": ""2015-11-17T11:49:03Z"", + // ""AppVersion"": ""3.0.1.320"", + // ""FileVersion"": 7 + //}"; + // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); + + // Assert.AreEqual("3.0.1.320", header.AppVersion); + // Assert.AreEqual(7u, header.FileVersion); + // Assert.AreEqual("Michael Krisper", header.CreatedBy); + // Assert.AreEqual(new DateTime(2015, 11, 17, 11, 49, 3, DateTimeKind.Utc), header.Date); + + // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); + // Assert.AreEqual(json, jsonCompare); + // } + + // [TestMethod] + // public void Test_Json_DateFormat_ISO8601_CET() + // { + // var json = @"{ + // ""CreatedBy"": ""Michael Krisper"", + // ""Date"": ""2015-11-17T11:49:03+01:00"", + // ""AppVersion"": ""3.0.1.320"", + // ""FileVersion"": 7 + //}"; + // var header = JsonConvert.DeserializeObject<JsonDataHeader>(json); + + // Assert.AreEqual("3.0.1.320", header.AppVersion); + // Assert.AreEqual(7u, header.FileVersion); + // Assert.AreEqual("Michael Krisper", header.CreatedBy); + // Assert.AreEqual(new DateTime(2015, 11, 17, 11, 49, 3, DateTimeKind.Utc), header.Date); + + // var jsonCompare = JsonConvert.SerializeObject(header, Formatting.Indented); + // Assert.AreEqual(json, jsonCompare); + // } + // } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Models/Declaration/DeclarationDataTest.cs b/VectoCore/VectoCoreTest/Models/Declaration/DeclarationDataTest.cs index 8647201ea834cd3b2053723081bbfbaa3df38f7c..ffb5f6d5dfca18bda17ec7e5907414defe6cc607 100644 --- a/VectoCore/VectoCoreTest/Models/Declaration/DeclarationDataTest.cs +++ b/VectoCore/VectoCoreTest/Models/Declaration/DeclarationDataTest.cs @@ -29,1573 +29,1604 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using NUnit.Framework; -using System; -using System.IO; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.InputData.FileIO.JSON; -using TUGraz.VectoCore.InputData.Reader.ComponentData; -using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; -using TUGraz.VectoCore.InputData.Reader.Impl; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Tests.Utils; - -namespace TUGraz.VectoCore.Tests.Models.Declaration -{ - [TestFixture] - public class DeclarationDataTest - { - private const double Tolerance = 0.0001; - - private readonly MissionType[] _missions = { - MissionType.LongHaul, - MissionType.RegionalDelivery, - MissionType.UrbanDelivery, - MissionType.MunicipalUtility, - MissionType.Construction, - }; - - [TestCase("285/60 R22.5", 10.6, 0.914, 3.03, 0.440766), - TestCase("285/70 R19.5", 7.9, 0.895, 3.05, 0.434453), - TestCase("395/85 R20", 27.9, 1.18, 3.05, 0.572798)] - public void WheelDataTest(string wheels, double inertia, double wheelsDiameter, double circumferenceFactor, - double expectedDynamicRadius) - { - var tmp = DeclarationData.Wheels.Lookup(wheels); - - AssertHelper.AreRelativeEqual(inertia, tmp.Inertia); - AssertHelper.AreRelativeEqual(wheelsDiameter, tmp.WheelsDiameter); - AssertHelper.AreRelativeEqual(circumferenceFactor, tmp.CircumferenceFactor); - Assert.AreEqual(expectedDynamicRadius, tmp.DynamicTyreRadius.Value(), 1e-6); - } - - [ - // fixed points - TestCase(400, 0), - TestCase(800, 0.47), - TestCase(1000, 0.58), - TestCase(1200, 0.53), - TestCase(1400, 0.46), - TestCase(1500, 0.43), - TestCase(1750, 0.22), - TestCase(1800, 0.2), - TestCase(2000, 0.11), - TestCase(2500, 0.11), - // interpolate - TestCase(600, 0.235), - TestCase(900, 0.525), - TestCase(1100, 0.555), - TestCase(1300, 0.495), - TestCase(1450, 0.445), - TestCase(1625, 0.325), - TestCase(1775, 0.21), - TestCase(1900, 0.155), - TestCase(2250, 0.11), - ] - public void PT1Test(double rpm, double expectedPt1) - { - var pt1 = DeclarationData.PT1.Lookup(rpm.RPMtoRad()); - Assert.AreEqual(expectedPt1, pt1.Value.Value(), Tolerance); - Assert.IsFalse(pt1.Extrapolated); - } - - [TestCase(200), - TestCase(0), - TestCase(3000),] - public void PT1ExceptionsTest(double rpm) - { - // EXTRAPOLATE - var tmp = DeclarationData.PT1.Lookup(rpm.RPMtoRad()); - Assert.IsTrue(tmp.Extrapolated); - } - - [TestCase] - public void WHTCTest() - { - var whtc = DeclarationData.WHTCCorrection; - - var factors = new { - urban = new[] { 0.11, 0.17, 0.69, 0.98, 0.62, 1.0, 1.0, 1.0, 0.45, 0.0 }, - rural = new[] { 0.0, 0.3, 0.27, 0.0, 0.32, 0.0, 0.0, 0.0, 0.36, 0.22 }, - motorway = new[] { 0.89, 0.53, 0.04, 0.02, 0.06, 0.0, 0.0, 0.0, 0.19, 0.78 } - }; - - var r = new Random(); - for (var i = 0; i < _missions.Length; i++) { - var urban = r.NextDouble() * 2; - var rural = r.NextDouble() * 2; - var motorway = r.NextDouble() * 2; - var whtcValue = whtc.Lookup(_missions[i], rural: rural, urban: urban, motorway: motorway); - Assert.AreEqual(urban * factors.urban[i] + rural * factors.rural[i] + motorway * factors.motorway[i], - whtcValue); - } - } - - [TestCase] - public void WHTCLookupTestLongHaul() - { - var expected = 1.015501; - - var rural = 1.0265; - var urban = 1.0948; - var motorway = 1.0057; - - var lookup = DeclarationData.WHTCCorrection.Lookup(MissionType.LongHaul, rural: rural, urban: urban, - motorway: motorway); - Assert.AreEqual(expected, lookup, 1e-8); - } - - [TestCase] - public void WHTCLookupTestRegionalDelivery() - { - var expected = 1.02708700; - - var rural = 1.0265; - var urban = 1.0948; - var motorway = 1.0057; - - var lookup = DeclarationData.WHTCCorrection.Lookup(MissionType.RegionalDelivery, rural: rural, urban: urban, - motorway: motorway); - Assert.AreEqual(expected, lookup, 1e-8); - } - - [TestCase("RigidSolo", 0.013526, 0.017746, -0.000666), - TestCase("RigidTrailer", 0.017125, 0.072275, -0.004148), - TestCase("TractorSemitrailer", 0.030042, 0.040817, -0.00213), - TestCase("CoachBus", -0.000794, 0.02109, -0.00109)] - public void AirDrag_WithStringKey(string key, double a1, double a2, double a3) - { - var value = DeclarationData.AirDrag.Lookup(key); - AssertHelper.AreRelativeEqual(a1, value.A1); - AssertHelper.AreRelativeEqual(a2, value.A2); - AssertHelper.AreRelativeEqual(a3, value.A3); - } - - [TestCase("RigidSolo", 0.013526, 0.017746, -0.000666), - TestCase("TractorSemitrailer", 0.030042, 0.040817, -0.00213), - TestCase("RigidTrailer", 0.017125, 0.072275, -0.004148), - TestCase("CoachBus", -0.000794, 0.02109, -0.00109)] - public void AirDrag_WithVehicleCategory(string parameterSet, double a1, double a2, double a3) - { - var value = DeclarationData.AirDrag.Lookup(parameterSet); - AssertHelper.AreRelativeEqual(a1, value.A1); - AssertHelper.AreRelativeEqual(a2, value.A2); - AssertHelper.AreRelativeEqual(a3, value.A3); - } - - [TestCase("TractorSemitrailer", 6.46, 0, 4.0, 7.71712257), - TestCase("TractorSemitrailer", 6.46, 60, 4.0, 7.71712257), - TestCase("TractorSemitrailer", 6.46, 75, 3.75, 7.35129203), - TestCase("TractorSemitrailer", 6.46, 100, 4.0, 7.03986404), - TestCase("TractorSemitrailer", 6.46, 62.1234, 4.0, 7.65751048), - TestCase("TractorSemitrailer", 6.46, 73.5432, 3.75, 7.37814098), - TestCase("TractorSemitrailer", 6.46, 92.8765, 4.0, 7.11234364), - TestCase("TractorSemitrailer", 6.46, 100.449, 4.0, 7.03571556), - TestCase("TractorSemitrailer", 6.46, 103, 3.6, 6.99454230), - TestCase("TractorSemitrailer", 6.46, 105, 3.9, 6.99177143), - TestCase("TractorSemitrailer", 6.46, 115, 4.0, 6.92267778), - TestCase("TractorSemitrailer", 6.46, 130, 4.0, 6.83867361),] - public void CrossWindCorrectionTest(string parameterSet, double crossSectionArea, double kmph, double height, - double expected) - { - var crossWindCorrectionCurve = new CrosswindCorrectionCdxALookup(crossSectionArea.SI<SquareMeter>(), - DeclarationDataAdapter.GetDeclarationAirResistanceCurve(parameterSet, crossSectionArea.SI<SquareMeter>(), - height.SI<Meter>()), - CrossWindCorrectionMode.DeclarationModeCorrection); - - var tmp = crossWindCorrectionCurve.EffectiveAirDragArea(kmph.KMPHtoMeterPerSecond()); - AssertHelper.AreRelativeEqual(expected, tmp.Value(), toleranceFactor: 1e-3); - } - - [TestCase("TractorSemitrailer", 5.8, 4.0)] - public void CrossWindGetDeclarationAirResistance(string parameterSet, double cdxa0, double height) - { - var curve = - DeclarationDataAdapter.GetDeclarationAirResistanceCurve(parameterSet, cdxa0.SI<SquareMeter>(), height.SI<Meter>()); - - AssertHelper.AreRelativeEqual(60.KMPHtoMeterPerSecond(), curve[1].Velocity); - AssertHelper.AreRelativeEqual(7.0418009.SI<SquareMeter>(), curve[1].EffectiveCrossSectionArea); - - AssertHelper.AreRelativeEqual(65.KMPHtoMeterPerSecond(), curve[2].Velocity); - AssertHelper.AreRelativeEqual(6.90971991.SI<SquareMeter>(), curve[2].EffectiveCrossSectionArea); - - AssertHelper.AreRelativeEqual(85.KMPHtoMeterPerSecond(), curve[6].Velocity); - AssertHelper.AreRelativeEqual(6.54224222.SI<SquareMeter>(), curve[6].EffectiveCrossSectionArea); - - AssertHelper.AreRelativeEqual(100.KMPHtoMeterPerSecond(), curve[9].Velocity); - AssertHelper.AreRelativeEqual(6.37434824.SI<SquareMeter>(), curve[9].EffectiveCrossSectionArea); - - AssertHelper.AreRelativeEqual(105.KMPHtoMeterPerSecond(), curve[10].Velocity); - AssertHelper.AreRelativeEqual(6.33112792.SI<SquareMeter>(), curve[10].EffectiveCrossSectionArea); - - Assert.Greater(20, curve.Count); - } - - [ - TestCase("TractorSemitrailer", 6.46, -0.1, 3.0), - TestCase("TractorSemitrailer", 6.46, 130.1, 3.0), - ] - public void CrossWindCorrectionExceptionTest(string parameterSet, double crossSectionArea, double kmph, double height) - { - var crossWindCorrectionCurve = new CrosswindCorrectionCdxALookup(crossSectionArea.SI<SquareMeter>(), - DeclarationDataAdapter.GetDeclarationAirResistanceCurve(parameterSet, crossSectionArea.SI<SquareMeter>(), - height.SI<Meter>()), - CrossWindCorrectionMode.DeclarationModeCorrection); - - AssertHelper.Exception<VectoException>(() => - crossWindCorrectionCurve.EffectiveAirDragArea(kmph.KMPHtoMeterPerSecond())); - } - - [TestCase(MissionType.LongHaul, "Standard technology", 1200, 0.7), - TestCase(MissionType.RegionalDelivery, "Standard technology", 1000, 0.7), - TestCase(MissionType.UrbanDelivery, "Standard technology", 1000, 0.7), - TestCase(MissionType.MunicipalUtility, "Standard technology", 1000, 0.7), - TestCase(MissionType.Construction, "Standard technology", 1000, 0.7), - TestCase(MissionType.LongHaul, "Standard technology - LED headlights, all", 1150, 0.7), - TestCase(MissionType.RegionalDelivery, "Standard technology - LED headlights, all", 950, 0.7), - TestCase(MissionType.UrbanDelivery, "Standard technology - LED headlights, all", 950, 0.7), - TestCase(MissionType.MunicipalUtility, "Standard technology - LED headlights, all", 950, 0.7), - TestCase(MissionType.Construction, "Standard technology - LED headlights, all", 950, 0.7),] - public void AuxElectricSystemTest(MissionType mission, string technology, double value, double efficiency) - { - AssertHelper.AreRelativeEqual(value / efficiency, DeclarationData.ElectricSystem.Lookup(mission, technology)); - } - - [TestCase(MissionType.Interurban, "Standard technology"), - TestCase(MissionType.LongHaul, "Standard technology - Flux-Compensator")] - public void AuxElectricSystem_NotExistingError(MissionType mission, string technology) - { - AssertHelper.Exception<VectoException>(() => { DeclarationData.ElectricSystem.Lookup(mission, technology); }); - } - - [TestCase("only the drive shaft of the PTO - shift claw, synchronizer, sliding gearwheel", 50), - TestCase("only the drive shaft of the PTO - multi-disc clutch", 1000), - TestCase("only the drive shaft of the PTO - multi-disc clutch, oil pump", 2000), - TestCase("drive shaft and/or up to 2 gear wheels - shift claw, synchronizer, sliding gearwheel", 300), - TestCase("drive shaft and/or up to 2 gear wheels - multi-disc clutch", 1500), - TestCase("drive shaft and/or up to 2 gear wheels - multi-disc clutch, oil pump", 3000), - TestCase("drive shaft and/or more than 2 gear wheels - shift claw, synchronizer, sliding gearwheel", 600), - TestCase("drive shaft and/or more than 2 gear wheels - multi-disc clutch", 2000), - TestCase("drive shaft and/or more than 2 gear wheels - multi-disc clutch, oil pump", 4000), - TestCase("only one engaged gearwheel above oil level", 0)] - public void AuxPTOTransmissionTest(string technology, double value) - { - AssertHelper.AreRelativeEqual(value, DeclarationData.PTOTransmission.Lookup(technology)); - } - - [TestCase("Superfluid")] - public void AuxPTOTransmission_NotExistingError(string technology) - { - AssertHelper.Exception<VectoException>(() => { DeclarationData.PTOTransmission.Lookup(technology); }); - } - - [TestCase("", new[] { 618, 671, 516, 566, 1037 }), - TestCase("Crankshaft mounted - Electronically controlled visco clutch", new[] { 618, 671, 516, 566, 1037 }), - TestCase("Crankshaft mounted - Bimetallic controlled visco clutch", new[] { 818, 871, 676, 766, 1277 }), - TestCase("Crankshaft mounted - Discrete step clutch", new[] { 668, 721, 616, 616, 1157 }), - TestCase("Crankshaft mounted - On/off clutch", new[] { 718, 771, 666, 666, 1237 }), - TestCase("Belt driven or driven via transm. - Electronically controlled visco clutch", - new[] { 989, 1044, 833, 933, 1478 }), - TestCase("Belt driven or driven via transm. - Bimetallic controlled visco clutch", - new[] { 1189, 1244, 993, 1133, 1718 }), - TestCase("Belt driven or driven via transm. - Discrete step clutch", new[] { 1039, 1094, 983, 983, 1598 }), - TestCase("Belt driven or driven via transm. - On/off clutch", new[] { 1089, 1144, 1033, 1033, 1678 }), - TestCase("Hydraulic driven - Variable displacement pump", new[] { 938, 1155, 832, 917, 1872 }), - TestCase("Hydraulic driven - Constant displacement pump", new[] { 1200, 1400, 1000, 1100, 2300 }), - TestCase("Hydraulic driven - Electronically controlled", new[] { 700, 800, 600, 600, 1400 }),] - public void AuxFanTechTest(string technology, int[] expected) - { - for (var i = 0; i < _missions.Length; i++) { - var value = DeclarationData.Fan.Lookup(_missions[i], technology); - Assert.AreEqual(expected[i], value.Value(), Tolerance); - } - } - - [TestCase("Superfluid Hydraulic", MissionType.LongHaul, TestName = "AuxFanTechError( wrong tech )"), - TestCase("Hydraulic driven - Electronically controlled", MissionType.Coach, - TestName = "AuxFanTechError( wrong mission )") - ] - public void AuxFanTechError(string technology, MissionType missionType) - { - AssertHelper.Exception<VectoException>(() => DeclarationData.Fan.Lookup(missionType, technology)); - } - - [TestCase(VehicleClass.Class1, new[] { 0, 150, 150, 0, 0 }), - TestCase(VehicleClass.Class2, new[] { 200, 200, 150, 0, 0 }), - TestCase(VehicleClass.Class3, new[] { 0, 200, 150, 0, 0 }), - TestCase(VehicleClass.Class4, new[] { 350, 200, 0, 300, 0 }), - TestCase(VehicleClass.Class5, new[] { 350, 200, 0, 0, 0 }), - TestCase(VehicleClass.Class9, new[] { 350, 200, 0, 300, 0 }), - TestCase(VehicleClass.Class10, new[] { 350, 200, 0, 0, 0 }), - TestCase(VehicleClass.Class11, new[] { 350, 200, 0, 300, 200 }), - TestCase(VehicleClass.Class12, new[] { 350, 200, 0, 0, 200 }), - TestCase(VehicleClass.Class16, new[] { 0, 0, 0, 0, 200 })] - public void AuxHeatingVentilationAirConditionTest_Default(VehicleClass vehicleClass, int[] expected) - { - for (var i = 0; i < expected.Length; i++) { - if (expected[i] > 0) { - AssertHelper.AreRelativeEqual(expected[i], - DeclarationData.HeatingVentilationAirConditioning.Lookup(_missions[i], "Default", vehicleClass)); - } else { - var i1 = i; - AssertHelper.Exception<VectoException>( - () => DeclarationData.HeatingVentilationAirConditioning.Lookup(_missions[i1], "Default", vehicleClass)); - } - } - } - - [TestCase(VehicleClass.Class1, new[] { 0, 0, 0, 0, 0 }), - TestCase(VehicleClass.Class2, new[] { 0, 0, 0, 0, 0 }), - TestCase(VehicleClass.Class3, new[] { 0, 0, 0, 0, 0 }), - TestCase(VehicleClass.Class4, new[] { 0, 0, 0, 0, 0 }), - TestCase(VehicleClass.Class5, new[] { 0, 0, 0, 0, 0 }), - TestCase(VehicleClass.Class9, new[] { 0, 0, 0, 0, 0 }), - TestCase(VehicleClass.Class10, new[] { 0, 0, 0, 0, 0 }), - TestCase(VehicleClass.Class11, new[] { 0, 0, 0, 0, 0 }), - TestCase(VehicleClass.Class12, new[] { 0, 0, 0, 0, 0 }), - TestCase(VehicleClass.Class16, new[] { 0, 0, 0, 0, 0 })] - public void AuxHeatingVentilationAirConditionTest_None(VehicleClass vehicleClass, int[] expected) - { - for (var i = 0; i < expected.Length; i++) { - AssertHelper.AreRelativeEqual(expected[i], - DeclarationData.HeatingVentilationAirConditioning.Lookup(_missions[i], "None", vehicleClass)); - } - } - - [TestCase()] - public void AuxHetingVentilationAirConditionTechnologyTest() - { - var tech = DeclarationData.HeatingVentilationAirConditioning.GetTechnologies(); - Assert.AreEqual(2, tech.Length); - Assert.IsTrue(tech.Contains("Default")); - Assert.IsTrue(tech.Contains("None")); - } - - [Test, - TestCase("Small", new[] { 1400, 1300, 1200, 1200, 1300 }), - TestCase("Small + ESS", new[] { 900, 800, 800, 800, 800 }), - TestCase("Small + visco clutch", new[] { 800, 700, 700, 700, 700 }), - TestCase("Small + mech. clutch", new[] { 600, 600, 650, 650, 600 }), - TestCase("Small + ESS + AMS", new[] { 500, 400, 500, 500, 400 }), - TestCase("Small + visco clutch + AMS", new[] { 400, 300, 400, 400, 300 }), - TestCase("Small + mech. clutch + AMS", new[] { 200, 200, 350, 350, 200 }), - TestCase("Medium Supply 1-stage", new[] { 1600, 1400, 1350, 1350, 1500 }), - TestCase("Medium Supply 1-stage + ESS", new[] { 1000, 900, 900, 900, 900 }), - TestCase("Medium Supply 1-stage + visco clutch", new[] { 850, 800, 800, 800, 750 }), - TestCase("Medium Supply 1-stage + mech. clutch", new[] { 600, 550, 550, 550, 600 }), - TestCase("Medium Supply 1-stage + ESS + AMS", new[] { 600, 700, 700, 700, 500 }), - TestCase("Medium Supply 1-stage + visco clutch + AMS", new[] { 450, 600, 600, 600, 350 }), - TestCase("Medium Supply 1-stage + mech. clutch + AMS", new[] { 200, 350, 350, 350, 200 }), - TestCase("Medium Supply 2-stage", new[] { 2100, 1750, 1700, 1700, 2100 }), - TestCase("Medium Supply 2-stage + ESS", new[] { 1100, 1050, 1000, 1000, 1000 }), - TestCase("Medium Supply 2-stage + visco clutch", new[] { 1000, 850, 800, 800, 900 }), - TestCase("Medium Supply 2-stage + mech. clutch", new[] { 700, 650, 600, 600, 800 }), - TestCase("Medium Supply 2-stage + ESS + AMS", new[] { 700, 850, 800, 800, 500 }), - TestCase("Medium Supply 2-stage + visco clutch + AMS", new[] { 600, 650, 600, 600, 400 }), - TestCase("Medium Supply 2-stage + mech. clutch + AMS", new[] { 300, 450, 400, 400, 300 }), - TestCase("Large Supply", new[] { 4300, 3600, 3500, 3500, 4100 }), - TestCase("Large Supply + ESS", new[] { 1600, 1300, 1200, 1200, 1500 }), - TestCase("Large Supply + visco clutch", new[] { 1300, 1100, 1000, 1000, 1200 }), - TestCase("Large Supply + mech. clutch", new[] { 800, 800, 700, 700, 900 }), - TestCase("Large Supply + ESS + AMS", new[] { 1100, 1000, 1000, 1000, 1000 }), - TestCase("Large Supply + visco clutch + AMS", new[] { 800, 800, 800, 800, 700 }), - TestCase("Large Supply + mech. clutch + AMS", new[] { 300, 500, 500, 500, 400 }), - TestCase("Vacuum pump", new[] { 190, 160, 130, 130, 130 }), - ] - public void AuxPneumaticSystemTest(string technology, int[] expected) - { - for (var i = 0; i < _missions.Length; i++) { - var value = DeclarationData.PneumaticSystem.Lookup(_missions[i], technology); - AssertHelper.AreRelativeEqual(expected[i], value); - } - } - - [ - TestCase(MissionType.LongHaul, VehicleClass.Class2, 370, "Fixed displacement", null, null, null), - TestCase(MissionType.LongHaul, VehicleClass.Class4, 610, "Fixed displacement", null, null, null), - TestCase(MissionType.LongHaul, VehicleClass.Class5, 720, "Fixed displacement", null, null, null), - TestCase(MissionType.LongHaul, VehicleClass.Class9, 720, "Fixed displacement", null, null, null), - TestCase(MissionType.LongHaul, VehicleClass.Class10, 570, "Fixed displacement", null, null, null), - TestCase(MissionType.LongHaul, VehicleClass.Class11, 720, "Fixed displacement", null, null, null), - TestCase(MissionType.LongHaul, VehicleClass.Class12, 570, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class1, 280, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 340, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class3, 370, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class4, 570, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class5, 670, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class9, 590, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class10, 570, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class11, 590, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class12, 570, "Fixed displacement", null, null, null), - TestCase(MissionType.UrbanDelivery, VehicleClass.Class1, 270, "Fixed displacement", null, null, null), - TestCase(MissionType.UrbanDelivery, VehicleClass.Class2, 310, "Fixed displacement", null, null, null), - TestCase(MissionType.UrbanDelivery, VehicleClass.Class3, 350, "Fixed displacement", null, null, null), - TestCase(MissionType.UrbanDelivery, VehicleClass.Class5, 620, "Fixed displacement", null, null, null), - TestCase(MissionType.MunicipalUtility, VehicleClass.Class4, 510, "Fixed displacement", null, null, null), - TestCase(MissionType.MunicipalUtility, VehicleClass.Class9, 510, "Fixed displacement", null, null, null), - TestCase(MissionType.MunicipalUtility, VehicleClass.Class11, 510, "Fixed displacement", null, null, null), - TestCase(MissionType.Construction, VehicleClass.Class11, 770, "Fixed displacement", null, null, null), - TestCase(MissionType.Construction, VehicleClass.Class12, 770, "Fixed displacement", null, null, null), - TestCase(MissionType.Construction, VehicleClass.Class16, 770, "Fixed displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 325.5, "Fixed displacement with elec. control", null, - null, - null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 289, "Dual displacement", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 255, "Variable displacement mech. controlled", null, - null, - null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 204, "Variable displacement elec. controlled", null, - null, - null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 92.8571, "Electric", null, null, null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 665, "Fixed displacement", "Fixed displacement", null, - null), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 1295, "Fixed displacement", "Fixed displacement", - "Fixed displacement", "Fixed displacement"), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 1021.5, "Dual displacement", - "Variable displacement mech. controlled", "Fixed displacement with elec. control", - "Variable displacement elec. controlled"), - ] - public void Aux_SteeringPumpLookupValues(MissionType mission, VehicleClass hdvClass, double expected, string axle1, - string axle2, string axle3, string axle4) - { - // mk remark: made the test call with 4 axle params, so that the test name is clear in the test explorer. - AssertHelper.AreRelativeEqual(expected, - DeclarationData.SteeringPump.Lookup(mission, hdvClass, - new[] { axle1, axle2, axle3, axle4 }.TakeWhile(a => a != null).ToArray())); - } - - [TestCase(MissionType.LongHaul, VehicleClass.Class1, "Dual displacement", - TestName = "Aux_SteeringPumpLookupFail( No Value )"), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, "Super displacement", - TestName = "Aux_SteeringPumpLookupFail( Wrong Tech )"), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, "Dual displacement", "Dual displacement", - "Dual displacement", "Dual displacement", "Dual displacement", TestName = "Aux_SteeringPumpLookupFail( >4 Techs )"), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, TestName = "Aux_SteeringPumpLookupFail( Null Techs )"), - TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, new string[0], - TestName = "Aux_SteeringPumpLookupFail( 0 Techs )"), - ] - public void Aux_SteeringPumpLookupFail(MissionType mission, VehicleClass hdvClass, params string[] tech) - { - AssertHelper.Exception<VectoException>(() => DeclarationData.SteeringPump.Lookup(mission, hdvClass, tech)); - } - - [ - TestCase(0), - TestCase(1000), - TestCase(3500), - TestCase(7499) - ] - public void SegmentWeightOutOfRange4X2(double weight) - { - AssertHelper.Exception<VectoException>(() => - DeclarationData.Segments.Lookup( - VehicleCategory.RigidTruck, - AxleConfiguration.AxleConfig_4x2, - weight.SI<Kilogram>(), - 0.SI<Kilogram>()), - "Gross vehicle mass must be greater than 7.5 tons"); - } - - [ - TestCase(0), - TestCase(1000), - TestCase(3500), - TestCase(7499) - ] - public void SegmentWeightOutOfRange4X4(double weight) - { - AssertHelper.Exception<VectoException>(() => - DeclarationData.Segments.Lookup( - VehicleCategory.RigidTruck, - AxleConfiguration.AxleConfig_4x4, - weight.SI<Kilogram>(), - 0.SI<Kilogram>()), - "Gross vehicle mass must be greater than 7.5 tons"); - } - - [Test, - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10001, 0, VehicleClass.Class2), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 10001, 0, VehicleClass.Class2), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12001, 0, VehicleClass.Class3), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12001, 0, VehicleClass.Class3), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16001, 0, VehicleClass.Class4), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 99000, 0, VehicleClass.Class4), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16001, 0, VehicleClass.Class5), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 99000, 0, VehicleClass.Class5), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 7500, 0, VehicleClass.Class9), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class9), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class9), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 99000, 0, VehicleClass.Class9), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 7500, 0, VehicleClass.Class10), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class10), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class10), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 99000, 0, VehicleClass.Class10), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 7500, 0, VehicleClass.Class11), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 40000, 0, VehicleClass.Class11), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 7500, 0, VehicleClass.Class12), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 99000, 0, VehicleClass.Class12), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 7500, 0, VehicleClass.Class16), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 99000, 0, VehicleClass.Class16) - ] - public void SegmentLookupTest(VehicleCategory category, AxleConfiguration axleConfiguration, double grossWeight, - double curbWeight, VehicleClass expectedClass) - { - var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), - curbWeight.SI<Kilogram>()); - Assert.AreEqual(expectedClass, segment.VehicleClass); - } - - [TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1, 85), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10001, 0, VehicleClass.Class2, 85), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12001, 0, VehicleClass.Class3, 85), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16001, 0, VehicleClass.Class4, 85), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16001, 0, VehicleClass.Class5, 85), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 7500, 0, VehicleClass.Class9, 85), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 7500, 0, VehicleClass.Class10, 85), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 7500, 0, VehicleClass.Class11, 85), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 7500, 0, VehicleClass.Class12, 85), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 7500, 0, VehicleClass.Class16, 85), - ] - public void SegmentDesignSpeedTest(VehicleCategory category, AxleConfiguration axleConfiguration, double grossWeight, - double curbWeight, VehicleClass expectedClass, double speed) - { - var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), - curbWeight.SI<Kilogram>()); - - Assert.AreEqual(speed.KMPHtoMeterPerSecond(), segment.DesignSpeed); - } - - [Test, - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1, 1600, null, - TestName = "SegmentLookupBodyWeight Class1 Rigid"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1, 1600, null, - TestName = "SegmentLookupBodyWeight Class1 Tractor"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, 1900, 3400, - TestName = "SegmentLookupBodyWeight Class2 Rigid"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, 1900, 3400, - TestName = "SegmentLookupBodyWeight Class2 Tractor"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, 2000, null, - TestName = "SegmentLookupBodyWeight Class3 Rigid"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, 2000, null, - TestName = "SegmentLookupBodyWeight Class3 Tractor"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class4, 2100, 5400, - TestName = "SegmentLookupBodyWeight Class4"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class5, null, 7500, - TestName = "SegmentLookupBodyWeight Class5"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class9, 2200, 5400, - TestName = "SegmentLookupBodyWeight Class9"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class10, null, 7500, - TestName = "SegmentLookupBodyWeight Class10"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 12000, 0, VehicleClass.Class11, 2200, 5400, - TestName = "SegmentLookupBodyWeight Class11"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 12000, 0, VehicleClass.Class12, null, 7500, - TestName = "SegmentLookupBodyWeight Class12"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 12000, 0, VehicleClass.Class16, null, null, - TestName = "SegmentLookupBodyWeight Class16")] - public void SegmentLookupBodyTest(VehicleCategory category, AxleConfiguration axleConfiguration, double grossWeight, - double curbWeight, VehicleClass expectedClass, int? expectedBodyWeight, int? expectedTrailerWeight) - { - var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), - curbWeight.SI<Kilogram>()); - Assert.AreEqual(expectedClass, segment.VehicleClass); - - if (expectedBodyWeight.HasValue) { - Assert.AreEqual(expectedBodyWeight, segment.Missions[0].BodyCurbWeight.Value()); - } - if (expectedTrailerWeight.HasValue) { - var trailerMission = segment.Missions.Where(m => m.Trailer.Count > 0).ToList(); - if (trailerMission.Count > 0) { - Assert.AreEqual(expectedTrailerWeight, trailerMission.First().Trailer.First().TrailerCurbWeight.Value()); - } - } - } - - [Test, - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1, 3.6, - TestName = "SegmentLookupHeight Class1 Rigid"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1, 3.6, - TestName = "SegmentLookupHeight Class1 Tractor"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, 3.75, - TestName = "SegmentLookupHeight Class2 Rigid"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, 3.75, - TestName = "SegmentLookupHeight Class2 Tractor"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, 3.9, - TestName = "SegmentLookupHeight Class3 Rigid"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, 3.9, - TestName = "SegmentLookupHeight Class3 Tractor"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class4, 4.0, - TestName = "SegmentLookupHeight Class4"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class5, 4.0, - TestName = "SegmentLookupHeight Class5"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 10000, 0, VehicleClass.Class9, 3.6, - TestName = "SegmentLookupHeight Class9 - 1"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 12000, 0, VehicleClass.Class9, 3.75, - TestName = "SegmentLookupHeight Class9 - 2"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class9, 3.9, - TestName = "SegmentLookupHeight Class9 - 3"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 18000, 0, VehicleClass.Class9, 4.0, - TestName = "SegmentLookupHeight Class9 - 4"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class9, 4.0, - TestName = "SegmentLookupHeight Class9 - other"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class10, 4.0, - TestName = "SegmentLookupHeight Class10"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 12000, 0, VehicleClass.Class11, 4.0, - TestName = "SegmentLookupHeight Class11"), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 12000, 0, VehicleClass.Class12, 4.0, - TestName = "SegmentLookupHeight Class12"), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 12000, 0, VehicleClass.Class16, 3.6, - TestName = "SegmentLookupHeight Class16")] - public void SegmentLookupHeightTest(VehicleCategory category, AxleConfiguration axleConfiguration, double grossWeight, - double curbWeight, VehicleClass expectedClass, double expectedHeight) - { - var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), - curbWeight.SI<Kilogram>()); - Assert.AreEqual(expectedClass, segment.VehicleClass); - AssertHelper.AreRelativeEqual(expectedHeight, segment.VehicleHeight); - } - - [Test, - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1, - new[] { 36.5, 36.5 }), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1, - new[] { 36.5, 36.5 }), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, - new[] { 85.0, 45.2, 45.2 }), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, - new[] { 85.0, 45.2, 45.2 }), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, - new[] { 47.7, 47.7 }), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, - new[] { 47.7, 47.7 }), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class4, - new[] { 98.9, 49.4, 49.4 }), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class5, - new[] { 91.0, 140.5, 91.0, 140.5 }), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class9, - new[] { 101.4, 142.9, 51.9, 142.9, 51.9 }), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class10, - new[] { 91.0, 140.5, 91.0, 140.5 }), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 40000, 0, VehicleClass.Class11, - new[] { 101.4, 142.9, 51.9, 142.9, 51.9, 51.9 }), - TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 99000, 0, VehicleClass.Class12, - new[] { 91.0, 140.5, 91.0, 140.5, 91.0 }), - TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 99000, 0, VehicleClass.Class16, - new[] { 0.0 }) - ] - public void SegmentLookupCargoVolumeTest(VehicleCategory category, AxleConfiguration axleConfiguration, - double grossWeight, - double curbWeight, VehicleClass expectedClass, double[] expectedCargoVolume) - { - var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), - curbWeight.SI<Kilogram>()); - Assert.AreEqual(expectedClass, segment.VehicleClass); - Assert.AreEqual(expectedCargoVolume.Length, segment.Missions.Length); - for (var i = 0; i < expectedCargoVolume.Length; i++) { - Assert.AreEqual(expectedCargoVolume[i], segment.Missions[i].TotalCargoVolume.Value()); - } - } - - /// <summary> - /// trailer in longhaul, always pc formula - /// </summary> - [TestCase] - public void Segment2Test() - { - var vehicleData = new { - VehicleCategory = VehicleCategory.RigidTruck, - AxleConfiguration = AxleConfiguration.AxleConfig_4x2, - GrossVehicleMassRating = 11900.SI<Kilogram>(), - CurbWeight = 5850.SI<Kilogram>() - }; - - var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, - vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); - - Assert.AreEqual(VehicleClass.Class2, segment.VehicleClass); - - var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); - TestAcceleration(data); - - Assert.AreEqual(3, segment.Missions.Length); - - AssertMission(segment.Missions[0], - vehicleData: vehicleData, - missionType: MissionType.LongHaul, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.225, 0.325 }, - trailerAxleWeightDistribution: new[] { 0.45 }, - trailerAxleCount: new[] { 2 }, - bodyCurbWeight: 1900, - trailerCurbWeight: new[] { 3400.0 }, - trailerType: new[] { TrailerType.T1 }, - lowLoad: 1306.8235, - refLoad: 9813.2353, - trailerGrossVehicleWeight: new[] { 10500.0 }, - deltaCdA: 1.3, - maxLoad: 11250); - - AssertMission(segment.Missions[1], - vehicleData: vehicleData, - missionType: MissionType.RegionalDelivery, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.45, 0.55 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 1900, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 596.8235, - refLoad: 2984.1176, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 4150); - - AssertMission(segment.Missions[2], - vehicleData: vehicleData, - missionType: MissionType.UrbanDelivery, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.45, 0.55 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 1900, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 596.8235, - refLoad: 2984.1176, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 4150); - } - - /// <summary> - /// normal pc formula, no trailer - /// </summary> - [TestCase] - public void Segment3Test() - { - var vehicleData = new { - VehicleCategory = VehicleCategory.RigidTruck, - AxleConfiguration = AxleConfiguration.AxleConfig_4x2, - GrossVehicleMassRating = 14000.SI<Kilogram>(), - CurbWeight = 5850.SI<Kilogram>() - }; - - var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, - vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); - - Assert.AreEqual(VehicleClass.Class3, segment.VehicleClass); - - Assert.AreEqual(2, segment.Missions.Length); - - AssertMission(segment.Missions[0], - vehicleData: vehicleData, - missionType: MissionType.RegionalDelivery, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.4, 0.6 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 2000, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 762.3529, - refLoad: 3811.7647, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 6150); - - AssertMission(segment.Missions[1], - vehicleData: vehicleData, - missionType: MissionType.UrbanDelivery, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.4, 0.6 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 2000, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 762.3529, - refLoad: 3811.7647, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 6150); - } - - /// <summary> - /// fixed reference weight, trailer only in longhaul - /// </summary> - [TestCase] - public void Segment4Test() - { - var vehicleData = new { - VehicleCategory = VehicleCategory.RigidTruck, - AxleConfiguration = AxleConfiguration.AxleConfig_4x2, - GrossVehicleMassRating = 18000.SI<Kilogram>(), - CurbWeight = 7500.SI<Kilogram>() - }; - - var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, - vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); - - Assert.AreEqual(VehicleClass.Class4, segment.VehicleClass); - - var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); - TestAcceleration(data); - - Assert.AreEqual(3, segment.Missions.Length); - - AssertMission(segment.Missions[0], - vehicleData: vehicleData, - missionType: MissionType.LongHaul, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.2, 0.3 }, - trailerAxleWeightDistribution: new[] { 0.5 }, - trailerAxleCount: new[] { 2 }, - bodyCurbWeight: 2100, - trailerCurbWeight: new[] { 5400.0 }, - trailerType: new[] { TrailerType.T2 }, - lowLoad: 1900, - refLoad: 14000, - trailerGrossVehicleWeight: new[] { 18000.0 }, - deltaCdA: 1.5, - maxLoad: 21000); - - AssertMission(segment.Missions[1], - vehicleData: vehicleData, - missionType: MissionType.RegionalDelivery, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.45, 0.55 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 2100, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 900, - refLoad: 4400, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 8400); - - AssertMission(segment.Missions[2], - vehicleData: vehicleData, - missionType: MissionType.MunicipalUtility, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.45, 0.55 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 2100, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 600, - refLoad: 3000, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 8400); - } - - /// <summary> - /// Segment 5: fixed reference weight, trailer always used - /// </summary> - [TestCase] - public void Segment5Test() - { - var vehicleData = new { - VehicleCategory = VehicleCategory.Tractor, - AxleConfiguration = AxleConfiguration.AxleConfig_4x2, - GrossVehicleMassRating = 18000.SI<Kilogram>(), - CurbWeight = 7500.SI<Kilogram>() - }; - - var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, - vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); - - Assert.AreEqual(VehicleClass.Class5, segment.VehicleClass); - - var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); - TestAcceleration(data); - - Assert.AreEqual(4, segment.Missions.Length); - - AssertMission(segment.Missions[0], - vehicleData: vehicleData, - missionType: MissionType.LongHaul, - cosswindCorrection: "TractorSemitrailer", - axleWeightDistribution: new[] { 0.2, 0.25 }, - trailerAxleWeightDistribution: new[] { 0.55 }, - trailerAxleCount: new[] { 3 }, bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0 }, - trailerType: new[] { TrailerType.ST1 }, - lowLoad: 2600, - refLoad: 19300, - trailerGrossVehicleWeight: new[] { 24000.0 }, - deltaCdA: 0, - maxLoad: 25000); - - AssertMission(segment.Missions[1], - vehicleData: vehicleData, - missionType: MissionType.LongHaulEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.15, 0.2 }, - trailerAxleWeightDistribution: new[] { 0.40, 0.25 }, - trailerAxleCount: new[] { 3, 2 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0, 5400 }, - trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, - lowLoad: 3500, - refLoad: 26500, - trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, - deltaCdA: 1.5, - maxLoad: 39600, - ems: true); - - AssertMission(segment.Missions[2], - vehicleData: vehicleData, - missionType: MissionType.RegionalDelivery, - cosswindCorrection: "TractorSemitrailer", - axleWeightDistribution: new[] { 0.25, 0.25 }, - trailerAxleWeightDistribution: new[] { 0.5 }, - trailerAxleCount: new[] { 3 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0 }, - trailerType: new[] { TrailerType.ST1 }, - lowLoad: 2600, - refLoad: 12900, - trailerGrossVehicleWeight: new[] { 24000.0 }, - deltaCdA: 0, maxLoad: 25000); - - AssertMission(segment.Missions[3], - vehicleData: vehicleData, - missionType: MissionType.RegionalDeliveryEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.175, 0.25 }, - trailerAxleWeightDistribution: new[] { 0.35, 0.225 }, - trailerAxleCount: new[] { 3, 2 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0, 5400 }, - trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, - lowLoad: 3500, - refLoad: 17500, - trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, - deltaCdA: 1.5, - maxLoad: 39600, - ems: true); - } - - /// <summary> - /// Segment 9: fixed reference weight, trailer always used - /// </summary> - [TestCase] - public void Segment9Test() - { - var vehicleData = new { - VehicleCategory = VehicleCategory.RigidTruck, - AxleConfiguration = AxleConfiguration.AxleConfig_6x2, - GrossVehicleMassRating = 24000.SI<Kilogram>(), - CurbWeight = 7500.SI<Kilogram>() - }; - - var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, - vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); - - Assert.AreEqual(VehicleClass.Class9, segment.VehicleClass); - - var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); - TestAcceleration(data); - - Assert.AreEqual(5, segment.Missions.Length); - - AssertMission(segment.Missions[0], - vehicleData: vehicleData, - missionType: MissionType.LongHaul, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.2, 0.3, 0.15 }, - trailerAxleWeightDistribution: new[] { 0.35 }, - trailerAxleCount: new[] { 2 }, - bodyCurbWeight: 2200, - trailerCurbWeight: new[] { 5400.0 }, - trailerType: new[] { TrailerType.T2 }, - lowLoad: 2600, - refLoad: 19300, - trailerGrossVehicleWeight: new[] { 18000.0 }, - deltaCdA: 1.5, - maxLoad: 24900); - - AssertMission(segment.Missions[1], - vehicleData: vehicleData, - missionType: MissionType.LongHaulEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.15, 0.2, 0.1 }, - trailerAxleWeightDistribution: new[] { 0.225, 0.325 }, - trailerAxleCount: new[] { 2, 3 }, - bodyCurbWeight: 2200, - trailerCurbWeight: new[] { 2500, 7500.0 }, - trailerType: new[] { TrailerType.Dolly, TrailerType.ST1 }, - lowLoad: 3500, - refLoad: 26500, - trailerGrossVehicleWeight: new[] { 12000.0, 24000 }, - deltaCdA: 2.1, - maxLoad: 40300, - ems: true); - - AssertMission(segment.Missions[2], - vehicleData: vehicleData, - missionType: MissionType.RegionalDelivery, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.35, 0.4, 0.25 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 2200, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 1400, - refLoad: 7100, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 14300); - - AssertMission(segment.Missions[3], - vehicleData: vehicleData, - missionType: MissionType.RegionalDeliveryEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.175, 0.2, 0.1 }, - trailerAxleWeightDistribution: new[] { 0.225, 0.3 }, - trailerAxleCount: new[] { 2, 3 }, - bodyCurbWeight: 2200, - trailerCurbWeight: new[] { 2500, 7500.0 }, - trailerType: new[] { TrailerType.Dolly, TrailerType.ST1 }, - lowLoad: 3500, - refLoad: 17500, - trailerGrossVehicleWeight: new[] { 12000.0, 24000 }, - deltaCdA: 2.1, - maxLoad: 40300, - ems: true); - - AssertMission(segment.Missions[4], - vehicleData: vehicleData, - missionType: MissionType.MunicipalUtility, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.35, 0.4, 0.25 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 2200, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 1200, - refLoad: 6000, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 14300); - } - - /// <summary> - /// Segment 10: fixed reference weight, trailer always used - /// </summary> - [TestCase] - public void Segment10Test() - { - var vehicleData = new { - VehicleCategory = VehicleCategory.Tractor, - AxleConfiguration = AxleConfiguration.AxleConfig_6x2, - GrossVehicleMassRating = 24000.SI<Kilogram>(), - CurbWeight = 7500.SI<Kilogram>() - }; - - var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, - vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); - - Assert.AreEqual(VehicleClass.Class10, segment.VehicleClass); - - var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); - TestAcceleration(data); - - Assert.AreEqual(4, segment.Missions.Length); - - AssertMission(segment.Missions[0], - vehicleData: vehicleData, - missionType: MissionType.LongHaul, - cosswindCorrection: "TractorSemitrailer", - axleWeightDistribution: new[] { 0.15, 0.1, 0.2 }, - trailerAxleWeightDistribution: new[] { 0.55 }, - trailerAxleCount: new[] { 3 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0 }, - trailerType: new[] { TrailerType.ST1 }, - lowLoad: 2600, - refLoad: 19300, - trailerGrossVehicleWeight: new[] { 24000.0 }, - deltaCdA: 0, - maxLoad: 25000); - - AssertMission(segment.Missions[1], - vehicleData: vehicleData, - missionType: MissionType.LongHaulEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.125, 0.15, 0.1 }, - trailerAxleWeightDistribution: new[] { 0.375, 0.25 }, - trailerAxleCount: new[] { 3, 2 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0, 5400 }, - trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, - lowLoad: 3500, - refLoad: 26500, - trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, - deltaCdA: 1.5, - maxLoad: 39600, - ems: true); - - AssertMission(segment.Missions[2], - vehicleData: vehicleData, - missionType: MissionType.RegionalDelivery, - cosswindCorrection: "TractorSemitrailer", - axleWeightDistribution: new[] { 0.2, 0.1, 0.2 }, - trailerAxleWeightDistribution: new[] { 0.5 }, - trailerAxleCount: new[] { 3 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0 }, - trailerType: new[] { TrailerType.ST1 }, - lowLoad: 2600, - refLoad: 12900, - trailerGrossVehicleWeight: new[] { 24000.0 }, - deltaCdA: 0, - maxLoad: 25000); - - AssertMission(segment.Missions[3], - vehicleData: vehicleData, - missionType: MissionType.RegionalDeliveryEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.15, 0.15, 0.1 }, - trailerAxleWeightDistribution: new[] { 0.35, 0.25 }, - trailerAxleCount: new[] { 3, 2 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0, 5400 }, - trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, - lowLoad: 3500, - refLoad: 17500, - trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, - deltaCdA: 1.5, - maxLoad: 39600, - ems: true); - } - - /// <summary> - /// Segment 11: fixed reference weight, trailer always used - /// </summary> - [TestCase] - public void Segment11Test() - { - var vehicleData = new { - VehicleCategory = VehicleCategory.RigidTruck, - AxleConfiguration = AxleConfiguration.AxleConfig_6x4, - GrossVehicleMassRating = 24000.SI<Kilogram>(), - CurbWeight = 7500.SI<Kilogram>() - }; - - var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, - vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); - - Assert.AreEqual(VehicleClass.Class11, segment.VehicleClass); - - var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); - TestAcceleration(data); - - Assert.AreEqual(6, segment.Missions.Length); - - AssertMission(segment.Missions[0], - vehicleData: vehicleData, - missionType: MissionType.LongHaul, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.2, 0.225, 0.225 }, - trailerAxleWeightDistribution: new[] { 0.35 }, - trailerAxleCount: new[] { 2 }, - bodyCurbWeight: 2200, - trailerCurbWeight: new[] { 5400.0 }, - trailerType: new[] { TrailerType.T2 }, - lowLoad: 2600, - refLoad: 19300, - trailerGrossVehicleWeight: new[] { 18000.0 }, - deltaCdA: 1.5, - maxLoad: 24900); - - AssertMission(segment.Missions[1], - vehicleData: vehicleData, - missionType: MissionType.LongHaulEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.15, 0.2, 0.1 }, - trailerAxleWeightDistribution: new[] { 0.225, 0.325 }, - trailerAxleCount: new[] { 2, 3 }, - bodyCurbWeight: 2200, - trailerCurbWeight: new[] { 2500, 7500.0 }, - trailerType: new[] { TrailerType.Dolly, TrailerType.ST1 }, - lowLoad: 3500, - refLoad: 26500, - trailerGrossVehicleWeight: new[] { 12000.0, 24000 }, - deltaCdA: 2.1, - maxLoad: 40300, - ems: true); - - AssertMission(segment.Missions[2], - vehicleData: vehicleData, - missionType: MissionType.RegionalDelivery, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.35, 0.35, 0.3 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, bodyCurbWeight: 2200, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 1400, - refLoad: 7100, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 14300); - - AssertMission(segment.Missions[3], - vehicleData: vehicleData, - missionType: MissionType.RegionalDeliveryEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.175, 0.2, 0.1 }, - trailerAxleWeightDistribution: new[] { 0.225, 0.3 }, - trailerAxleCount: new[] { 2, 3 }, - bodyCurbWeight: 2200, - trailerCurbWeight: new[] { 2500, 7500.0 }, - trailerType: new[] { TrailerType.Dolly, TrailerType.ST1 }, - lowLoad: 3500, - refLoad: 17500, - trailerGrossVehicleWeight: new[] { 12000.0, 24000 }, - deltaCdA: 2.1, - maxLoad: 40300, - ems: true); - - AssertMission(segment.Missions[4], - vehicleData: vehicleData, - missionType: MissionType.MunicipalUtility, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.35, 0.35, 0.3 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 2200, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 1200, - refLoad: 6000, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 14300); - - AssertMission(segment.Missions[5], - vehicleData: vehicleData, - missionType: MissionType.Construction, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.35, 0.35, 0.3 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 2200, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 1400, - refLoad: 7100, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 14300); - } - - /// <summary> - /// Segment 10: fixed reference weight, trailer always used - /// </summary> - [TestCase] - public void Segment12Test() - { - var vehicleData = new { - VehicleCategory = VehicleCategory.Tractor, - AxleConfiguration = AxleConfiguration.AxleConfig_6x4, - GrossVehicleMassRating = 24000.SI<Kilogram>(), - CurbWeight = 7500.SI<Kilogram>() - }; - - var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, - vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); - - Assert.AreEqual(VehicleClass.Class12, segment.VehicleClass); - - var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); - TestAcceleration(data); - - Assert.AreEqual(5, segment.Missions.Length); - - AssertMission(segment.Missions[0], - vehicleData: vehicleData, - missionType: MissionType.LongHaul, - cosswindCorrection: "TractorSemitrailer", - axleWeightDistribution: new[] { 0.15, 0.15, 0.15 }, - trailerAxleWeightDistribution: new[] { 0.55 }, - trailerAxleCount: new[] { 3 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0 }, - trailerType: new[] { TrailerType.ST1 }, - lowLoad: 2600, - refLoad: 19300, - trailerGrossVehicleWeight: new[] { 24000.0 }, - deltaCdA: 0, - maxLoad: 25000); - - AssertMission(segment.Missions[1], - vehicleData: vehicleData, - missionType: MissionType.LongHaulEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.125, 0.15, 0.1 }, - trailerAxleWeightDistribution: new[] { 0.375, 0.25 }, - trailerAxleCount: new[] { 3, 2 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0, 5400 }, - trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, - lowLoad: 3500, - refLoad: 26500, - trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, - deltaCdA: 1.5, - maxLoad: 39600, - ems: true); - - AssertMission(segment.Missions[2], - vehicleData: vehicleData, - missionType: MissionType.RegionalDelivery, - cosswindCorrection: "TractorSemitrailer", - axleWeightDistribution: new[] { 0.2, 0.15, 0.15 }, - trailerAxleWeightDistribution: new[] { 0.5 }, - trailerAxleCount: new[] { 3 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0 }, - trailerType: new[] { TrailerType.ST1 }, - lowLoad: 2600, - refLoad: 12900, - trailerGrossVehicleWeight: new[] { 24000.0 }, - deltaCdA: 0, - maxLoad: 25000); - - AssertMission(segment.Missions[3], - vehicleData: vehicleData, - missionType: MissionType.RegionalDeliveryEMS, - cosswindCorrection: "RigidTrailer", - axleWeightDistribution: new[] { 0.15, 0.15, 0.1 }, - trailerAxleWeightDistribution: new[] { 0.35, 0.25 }, - trailerAxleCount: new[] { 3, 2 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0, 5400 }, - trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, - lowLoad: 3500, - refLoad: 17500, - trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, - deltaCdA: 1.5, - maxLoad: 39600, - ems: true); - - AssertMission(segment.Missions[4], - vehicleData: vehicleData, - missionType: MissionType.Construction, - cosswindCorrection: "TractorSemitrailer", - axleWeightDistribution: new[] { 0.2, 0.15, 0.15 }, - trailerAxleWeightDistribution: new[] { 0.5 }, - trailerAxleCount: new[] { 3 }, - bodyCurbWeight: 0, - trailerCurbWeight: new[] { 7500.0 }, - trailerType: new[] { TrailerType.ST1 }, - lowLoad: 2600, - refLoad: 12900, - trailerGrossVehicleWeight: new[] { 24000.0 }, - deltaCdA: 0, - maxLoad: 25000, - ems: false); - } - - /// <summary> - /// Segment 9: fixed reference weight, trailer always used - /// </summary> - [TestCase] - public void Segment16Test() - { - var vehicleData = new { - VehicleCategory = VehicleCategory.RigidTruck, - AxleConfiguration = AxleConfiguration.AxleConfig_8x4, - GrossVehicleMassRating = 36000.SI<Kilogram>(), - CurbWeight = 7500.SI<Kilogram>() - }; - - var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, - vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); - - Assert.AreEqual(VehicleClass.Class16, segment.VehicleClass); - - var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); - TestAcceleration(data); - - Assert.AreEqual(1, segment.Missions.Length); - - AssertMission(segment.Missions[0], - vehicleData: vehicleData, - missionType: MissionType.Construction, - cosswindCorrection: "RigidSolo", - axleWeightDistribution: new[] { 0.25, 0.25, 0.25, 0.25 }, - trailerAxleWeightDistribution: new double[] { }, - trailerAxleCount: new int[] { }, - bodyCurbWeight: 0, - trailerCurbWeight: new double[] { }, - trailerType: new TrailerType[] { }, - lowLoad: 2600, - refLoad: 12900, - trailerGrossVehicleWeight: new double[] { }, - deltaCdA: 0, - maxLoad: 28500); - } - - public static void AssertMission(Mission m, dynamic vehicleData, MissionType missionType, string cosswindCorrection, - double[] axleWeightDistribution, double[] trailerAxleWeightDistribution, int[] trailerAxleCount, - double bodyCurbWeight, double[] trailerCurbWeight, TrailerType[] trailerType, double lowLoad, double refLoad, - double maxLoad, double[] trailerGrossVehicleWeight, double deltaCdA, bool ems = false) - { - Assert.AreEqual(missionType, m.MissionType); - Assert.AreEqual(cosswindCorrection, m.CrossWindCorrectionParameters); - CollectionAssert.AreEqual(axleWeightDistribution, m.AxleWeightDistribution, - "Axle distribution not equal.\nexpected: {0}\nactual: {1}", string.Join(",", axleWeightDistribution), - string.Join(",", m.AxleWeightDistribution)); - CollectionAssert.AreEqual(trailerAxleWeightDistribution, m.Trailer.Select(t => t.TrailerAxleWeightShare), - "Trailer axle distribution not equal.\nexpected: {0}\nactual: {1}", string.Join(",", trailerAxleWeightDistribution), - string.Join(",", m.Trailer.Select(t => t.TrailerAxleWeightShare))); - Assert.AreEqual(bodyCurbWeight.SI<Kilogram>(), m.BodyCurbWeight); - CollectionAssert.AreEqual(trailerCurbWeight, m.Trailer.Select(t => t.TrailerCurbWeight.Value())); - CollectionAssert.AreEqual(trailerType, m.Trailer.Select(t => t.TrailerType)); - CollectionAssert.AreEqual(trailerAxleCount, m.Trailer.Select(t => t.TrailerWheels.Count)); - Assert.IsNotNull(m.CycleFile); - Assert.IsTrue(!string.IsNullOrEmpty(new StreamReader(m.CycleFile).ReadLine())); - Assert.AreEqual(0.SI<Kilogram>(), m.MinLoad); - AssertHelper.AreRelativeEqual(lowLoad, m.LowLoad); - AssertHelper.AreRelativeEqual(refLoad, m.RefLoad); - Assert.AreEqual(maxLoad.SI<Kilogram>(), m.MaxLoad); - CollectionAssert.AreEqual(trailerGrossVehicleWeight, m.Trailer.Select(t => t.TrailerGrossVehicleWeight.Value())); - Assert.AreEqual( - VectoMath.Min( - vehicleData.GrossVehicleMassRating + - m.Trailer.Sum(t => t.TrailerGrossVehicleWeight).DefaultIfNull(0), - ems ? 60000.SI<Kilogram>() : 40000.SI<Kilogram>()) - - m.BodyCurbWeight - m.Trailer.Sum(t => t.TrailerCurbWeight).DefaultIfNull(0) - - vehicleData.CurbWeight, - m.MaxLoad); - Assert.AreEqual(deltaCdA.SI<SquareMeter>(), - m.Trailer.Sum(t => t.DeltaCdA).DefaultIfNull(0)); - } - - private static void EqualAcceleration(AccelerationCurveData data, double velocity, double acceleration, - double deceleration) - { - var entry = data.Lookup(velocity.KMPHtoMeterPerSecond()); - Assert.AreEqual(entry.Acceleration.Value(), acceleration, Tolerance); - Assert.AreEqual(entry.Deceleration.Value(), deceleration, Tolerance); - } - - private static void TestAcceleration(AccelerationCurveData data) - { - // FIXED POINTS - EqualAcceleration(data, 0, 1, -1); - EqualAcceleration(data, 25, 1, -1); - EqualAcceleration(data, 50, 0.642857143, -1); - EqualAcceleration(data, 60, 0.5, -0.5); - EqualAcceleration(data, 120, 0.5, -0.5); - - // INTERPOLATED POINTS - EqualAcceleration(data, 20, 1, -1); - EqualAcceleration(data, 40, 0.785714286, -1); - EqualAcceleration(data, 55, 0.571428572, -0.75); - EqualAcceleration(data, 80, 0.5, -0.5); - EqualAcceleration(data, 100, 0.5, -0.5); - - // EXTRAPOLATE - EqualAcceleration(data, -20, 1, -1); - EqualAcceleration(data, 140, 0.5, -0.5); - } - - [TestCase] - public void Declaration_WheelsForT1_Class2() - { - var dataProvider = - JSONInputDataFactory.ReadJsonJob(@"TestData\Jobs\12t Delivery Truck.vecto") as IDeclarationInputDataProvider; - var dataReader = new DeclarationModeVectoRunDataFactory(dataProvider, null); - - var runs = dataReader.NextRun().ToList(); - Assert.AreEqual(6, runs.Count); - var withT1 = new[] { 6.0, 6.0, 4.5, 4.5 }; - - CollectionAssert.AreEqual(withT1, runs[0].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(withT1, runs[1].VehicleData.AxleData.Select(a => a.Inertia.Value())); - - var bodyOnly = new[] { 6.0, 6.0 }; - - CollectionAssert.AreEqual(bodyOnly, runs[2].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(bodyOnly, runs[3].VehicleData.AxleData.Select(a => a.Inertia.Value())); - - CollectionAssert.AreEqual(bodyOnly, runs[4].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(bodyOnly, runs[5].VehicleData.AxleData.Select(a => a.Inertia.Value())); - } - - [TestCase] - public void Declaration_WheelsForT2_Class4() - { - var dataProvider = - JSONInputDataFactory.ReadJsonJob( - @"TestData\Jobs\Class4_40t_Long_Haul_Truck.vecto") as IDeclarationInputDataProvider; - var dataReader = new DeclarationModeVectoRunDataFactory(dataProvider, null); - - var runs = dataReader.NextRun().ToList(); - Assert.AreEqual(6, runs.Count); - var withT1 = new[] { 14.9, 14.9, 19.2, 19.2 }; - CollectionAssert.AreEqual(withT1, runs[0].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(withT1, runs[1].VehicleData.AxleData.Select(a => a.Inertia.Value())); - - var bodyOnly = new[] { 14.9, 14.9 }; - CollectionAssert.AreEqual(bodyOnly, runs[2].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(bodyOnly, runs[3].VehicleData.AxleData.Select(a => a.Inertia.Value())); - - CollectionAssert.AreEqual(bodyOnly, runs[4].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(bodyOnly, runs[5].VehicleData.AxleData.Select(a => a.Inertia.Value())); - } - - [TestCase] - public void Declaration_WheelsForDefault_Class5() - { - var dataProvider = - JSONInputDataFactory.ReadJsonJob(@"TestData\Jobs\40t_Long_Haul_Truck.vecto") as IDeclarationInputDataProvider; - var dataReader = new DeclarationModeVectoRunDataFactory(dataProvider, null); - - var runs = dataReader.NextRun().ToList(); - - Assert.AreEqual(VehicleClass.Class5, runs[0].VehicleData.VehicleClass); - Assert.AreEqual(8, runs.Count); - - //var bodyOnly = new[] { 14.9, 14.9 }; - var withST1 = new[] { 14.9, 14.9, 19.2, 19.2, 19.2 }; - var withST1andT2 = new[] { 14.9, 14.9, 19.2, 19.2, 19.2, 19.2, 19.2 }; - - CollectionAssert.AreEqual(withST1, runs[0].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(withST1, runs[1].VehicleData.AxleData.Select(a => a.Inertia.Value())); - - CollectionAssert.AreEqual(withST1andT2, runs[2].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(withST1andT2, runs[3].VehicleData.AxleData.Select(a => a.Inertia.Value())); - - CollectionAssert.AreEqual(withST1, runs[4].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(withST1, runs[5].VehicleData.AxleData.Select(a => a.Inertia.Value())); - - CollectionAssert.AreEqual(withST1andT2, runs[6].VehicleData.AxleData.Select(a => a.Inertia.Value())); - CollectionAssert.AreEqual(withST1andT2, runs[7].VehicleData.AxleData.Select(a => a.Inertia.Value())); - } - } +using NUnit.Framework; +using System; +using System.IO; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.FileIO.JSON; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; +using TUGraz.VectoCore.InputData.Reader.Impl; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Tests.Utils; + +namespace TUGraz.VectoCore.Tests.Models.Declaration +{ + [TestFixture] + public class DeclarationDataTest + { + private const double Tolerance = 0.0001; + + private readonly MissionType[] _missions = { + MissionType.LongHaul, + MissionType.RegionalDelivery, + MissionType.UrbanDelivery, + MissionType.MunicipalUtility, + MissionType.Construction, + }; + + [TestCase("285/60 R22.5", 10.6, 0.914, 3.03, 0.440766), + TestCase("285/70 R19.5", 7.9, 0.895, 3.05, 0.434453), + TestCase("395/85 R20", 27.9, 1.18, 3.05, 0.572798)] + public void WheelDataTest(string wheels, double inertia, double wheelsDiameter, double circumferenceFactor, + double expectedDynamicRadius) + { + var tmp = DeclarationData.Wheels.Lookup(wheels); + + AssertHelper.AreRelativeEqual(inertia, tmp.Inertia); + AssertHelper.AreRelativeEqual(wheelsDiameter, tmp.WheelsDiameter); + AssertHelper.AreRelativeEqual(circumferenceFactor, tmp.CircumferenceFactor); + Assert.AreEqual(expectedDynamicRadius, tmp.DynamicTyreRadius.Value(), 1e-6); + } + + [ + // fixed points + TestCase(400, 0), + TestCase(800, 0.47), + TestCase(1000, 0.58), + TestCase(1200, 0.53), + TestCase(1400, 0.46), + TestCase(1500, 0.43), + TestCase(1750, 0.22), + TestCase(1800, 0.2), + TestCase(2000, 0.11), + TestCase(2500, 0.11), + // interpolate + TestCase(600, 0.235), + TestCase(900, 0.525), + TestCase(1100, 0.555), + TestCase(1300, 0.495), + TestCase(1450, 0.445), + TestCase(1625, 0.325), + TestCase(1775, 0.21), + TestCase(1900, 0.155), + TestCase(2250, 0.11), + ] + public void PT1Test(double rpm, double expectedPt1) + { + var pt1 = DeclarationData.PT1.Lookup(rpm.RPMtoRad()); + Assert.AreEqual(expectedPt1, pt1.Value.Value(), Tolerance); + Assert.IsFalse(pt1.Extrapolated); + } + + [TestCase(200), + TestCase(0), + TestCase(3000),] + public void PT1ExceptionsTest(double rpm) + { + // EXTRAPOLATE + var tmp = DeclarationData.PT1.Lookup(rpm.RPMtoRad()); + Assert.IsTrue(tmp.Extrapolated); + } + + [TestCase] + public void WHTCTest() + { + var whtc = DeclarationData.WHTCCorrection; + + var factors = new { + urban = new[] { 0.11, 0.17, 0.69, 0.98, 0.62, 1.0, 1.0, 1.0, 0.45, 0.0 }, + rural = new[] { 0.0, 0.3, 0.27, 0.0, 0.32, 0.0, 0.0, 0.0, 0.36, 0.22 }, + motorway = new[] { 0.89, 0.53, 0.04, 0.02, 0.06, 0.0, 0.0, 0.0, 0.19, 0.78 } + }; + + var r = new Random(); + for (var i = 0; i < _missions.Length; i++) { + var urban = r.NextDouble() * 2; + var rural = r.NextDouble() * 2; + var motorway = r.NextDouble() * 2; + var whtcValue = whtc.Lookup(_missions[i], rural: rural, urban: urban, motorway: motorway); + Assert.AreEqual(urban * factors.urban[i] + rural * factors.rural[i] + motorway * factors.motorway[i], + whtcValue); + } + } + + [TestCase] + public void WHTCLookupTestLongHaul() + { + var expected = 1.015501; + + var rural = 1.0265; + var urban = 1.0948; + var motorway = 1.0057; + + var lookup = DeclarationData.WHTCCorrection.Lookup(MissionType.LongHaul, rural: rural, urban: urban, + motorway: motorway); + Assert.AreEqual(expected, lookup, 1e-8); + } + + [TestCase] + public void WHTCLookupTestRegionalDelivery() + { + var expected = 1.02708700; + + var rural = 1.0265; + var urban = 1.0948; + var motorway = 1.0057; + + var lookup = DeclarationData.WHTCCorrection.Lookup(MissionType.RegionalDelivery, rural: rural, urban: urban, + motorway: motorway); + Assert.AreEqual(expected, lookup, 1e-8); + } + + [TestCase("RigidSolo", 0.013526, 0.017746, -0.000666), + TestCase("RigidTrailer", 0.017125, 0.072275, -0.004148), + TestCase("TractorSemitrailer", 0.030042, 0.040817, -0.00213), + TestCase("CoachBus", -0.000794, 0.02109, -0.00109)] + public void AirDrag_WithStringKey(string key, double a1, double a2, double a3) + { + var value = DeclarationData.AirDrag.Lookup(key); + AssertHelper.AreRelativeEqual(a1, value.A1); + AssertHelper.AreRelativeEqual(a2, value.A2); + AssertHelper.AreRelativeEqual(a3, value.A3); + } + + [TestCase("RigidSolo", 0.013526, 0.017746, -0.000666), + TestCase("TractorSemitrailer", 0.030042, 0.040817, -0.00213), + TestCase("RigidTrailer", 0.017125, 0.072275, -0.004148), + TestCase("CoachBus", -0.000794, 0.02109, -0.00109)] + public void AirDrag_WithVehicleCategory(string parameterSet, double a1, double a2, double a3) + { + var value = DeclarationData.AirDrag.Lookup(parameterSet); + AssertHelper.AreRelativeEqual(a1, value.A1); + AssertHelper.AreRelativeEqual(a2, value.A2); + AssertHelper.AreRelativeEqual(a3, value.A3); + } + + [TestCase("TractorSemitrailer", 6.46, 0, 4.0, 7.71712257), + TestCase("TractorSemitrailer", 6.46, 60, 4.0, 7.71712257), + TestCase("TractorSemitrailer", 6.46, 75, 3.75, 7.35129203), + TestCase("TractorSemitrailer", 6.46, 100, 4.0, 7.03986404), + TestCase("TractorSemitrailer", 6.46, 62.1234, 4.0, 7.65751048), + TestCase("TractorSemitrailer", 6.46, 73.5432, 3.75, 7.37814098), + TestCase("TractorSemitrailer", 6.46, 92.8765, 4.0, 7.11234364), + TestCase("TractorSemitrailer", 6.46, 100.449, 4.0, 7.03571556), + TestCase("TractorSemitrailer", 6.46, 103, 3.6, 6.99454230), + TestCase("TractorSemitrailer", 6.46, 105, 3.9, 6.99177143), + TestCase("TractorSemitrailer", 6.46, 115, 4.0, 6.92267778), + TestCase("TractorSemitrailer", 6.46, 130, 4.0, 6.83867361),] + public void CrossWindCorrectionTest(string parameterSet, double crossSectionArea, double kmph, double height, + double expected) + { + var crossWindCorrectionCurve = new CrosswindCorrectionCdxALookup(crossSectionArea.SI<SquareMeter>(), + DeclarationDataAdapter.GetDeclarationAirResistanceCurve(parameterSet, crossSectionArea.SI<SquareMeter>(), + height.SI<Meter>()), + CrossWindCorrectionMode.DeclarationModeCorrection); + + var tmp = crossWindCorrectionCurve.EffectiveAirDragArea(kmph.KMPHtoMeterPerSecond()); + AssertHelper.AreRelativeEqual(expected, tmp.Value(), toleranceFactor: 1e-3); + } + + [TestCase("TractorSemitrailer", 5.8, 4.0)] + public void CrossWindGetDeclarationAirResistance(string parameterSet, double cdxa0, double height) + { + var curve = + DeclarationDataAdapter.GetDeclarationAirResistanceCurve(parameterSet, cdxa0.SI<SquareMeter>(), height.SI<Meter>()); + + AssertHelper.AreRelativeEqual(60.KMPHtoMeterPerSecond(), curve[1].Velocity); + AssertHelper.AreRelativeEqual(7.0418009.SI<SquareMeter>(), curve[1].EffectiveCrossSectionArea); + + AssertHelper.AreRelativeEqual(65.KMPHtoMeterPerSecond(), curve[2].Velocity); + AssertHelper.AreRelativeEqual(6.90971991.SI<SquareMeter>(), curve[2].EffectiveCrossSectionArea); + + AssertHelper.AreRelativeEqual(85.KMPHtoMeterPerSecond(), curve[6].Velocity); + AssertHelper.AreRelativeEqual(6.54224222.SI<SquareMeter>(), curve[6].EffectiveCrossSectionArea); + + AssertHelper.AreRelativeEqual(100.KMPHtoMeterPerSecond(), curve[9].Velocity); + AssertHelper.AreRelativeEqual(6.37434824.SI<SquareMeter>(), curve[9].EffectiveCrossSectionArea); + + AssertHelper.AreRelativeEqual(105.KMPHtoMeterPerSecond(), curve[10].Velocity); + AssertHelper.AreRelativeEqual(6.33112792.SI<SquareMeter>(), curve[10].EffectiveCrossSectionArea); + + Assert.Greater(20, curve.Count); + } + + [ + TestCase("TractorSemitrailer", 6.46, -0.1, 3.0), + TestCase("TractorSemitrailer", 6.46, 130.1, 3.0), + ] + public void CrossWindCorrectionExceptionTest(string parameterSet, double crossSectionArea, double kmph, double height) + { + var crossWindCorrectionCurve = new CrosswindCorrectionCdxALookup(crossSectionArea.SI<SquareMeter>(), + DeclarationDataAdapter.GetDeclarationAirResistanceCurve(parameterSet, crossSectionArea.SI<SquareMeter>(), + height.SI<Meter>()), + CrossWindCorrectionMode.DeclarationModeCorrection); + + AssertHelper.Exception<VectoException>(() => + crossWindCorrectionCurve.EffectiveAirDragArea(kmph.KMPHtoMeterPerSecond())); + } + + [TestCase] + public void CrossWindAreaCdxANotSet_DeclarationMode() + { + var airDrag = new AirdragData() { + CrossWindCorrectionMode = CrossWindCorrectionMode.DeclarationModeCorrection, + CrossWindCorrectionCurve = + new CrosswindCorrectionCdxALookup(null, null, CrossWindCorrectionMode.DeclarationModeCorrection) + }; + + Assert.IsTrue(airDrag.IsValid(), + "In Speed Dependent (Declaration Mode) Crosswind Correction the CdxA Value can be empty."); + } + + [TestCase] + public void CrossWindAreaCdxANotSet_Other() + { + foreach (var correctionMode in EnumHelper.GetValues<CrossWindCorrectionMode>()) { + if (correctionMode == CrossWindCorrectionMode.DeclarationModeCorrection) + continue; + + var airDrag = new AirdragData { + CrossWindCorrectionMode = correctionMode, + CrossWindCorrectionCurve = + new CrosswindCorrectionCdxALookup(null, null, correctionMode) + }; + + Assert.IsFalse(airDrag.IsValid(), + "Only in Speed Dependent (Declaration Mode) Crosswind Correction the CdxA Value can be empty."); + } + } + + [TestCase(MissionType.LongHaul, "Standard technology", 1200, 0.7), + TestCase(MissionType.RegionalDelivery, "Standard technology", 1000, 0.7), + TestCase(MissionType.UrbanDelivery, "Standard technology", 1000, 0.7), + TestCase(MissionType.MunicipalUtility, "Standard technology", 1000, 0.7), + TestCase(MissionType.Construction, "Standard technology", 1000, 0.7), + TestCase(MissionType.LongHaul, "Standard technology - LED headlights, all", 1150, 0.7), + TestCase(MissionType.RegionalDelivery, "Standard technology - LED headlights, all", 950, 0.7), + TestCase(MissionType.UrbanDelivery, "Standard technology - LED headlights, all", 950, 0.7), + TestCase(MissionType.MunicipalUtility, "Standard technology - LED headlights, all", 950, 0.7), + TestCase(MissionType.Construction, "Standard technology - LED headlights, all", 950, 0.7),] + public void AuxElectricSystemTest(MissionType mission, string technology, double value, double efficiency) + { + AssertHelper.AreRelativeEqual(value / efficiency, DeclarationData.ElectricSystem.Lookup(mission, technology)); + } + + [TestCase(MissionType.Interurban, "Standard technology"), + TestCase(MissionType.LongHaul, "Standard technology - Flux-Compensator")] + public void AuxElectricSystem_NotExistingError(MissionType mission, string technology) + { + AssertHelper.Exception<VectoException>(() => { DeclarationData.ElectricSystem.Lookup(mission, technology); }); + } + + [TestCase("only the drive shaft of the PTO - shift claw, synchronizer, sliding gearwheel", 50), + TestCase("only the drive shaft of the PTO - multi-disc clutch", 1000), + TestCase("only the drive shaft of the PTO - multi-disc clutch, oil pump", 2000), + TestCase("drive shaft and/or up to 2 gear wheels - shift claw, synchronizer, sliding gearwheel", 300), + TestCase("drive shaft and/or up to 2 gear wheels - multi-disc clutch", 1500), + TestCase("drive shaft and/or up to 2 gear wheels - multi-disc clutch, oil pump", 3000), + TestCase("drive shaft and/or more than 2 gear wheels - shift claw, synchronizer, sliding gearwheel", 600), + TestCase("drive shaft and/or more than 2 gear wheels - multi-disc clutch", 2000), + TestCase("drive shaft and/or more than 2 gear wheels - multi-disc clutch, oil pump", 4000), + TestCase("only one engaged gearwheel above oil level", 0)] + public void AuxPTOTransmissionTest(string technology, double value) + { + AssertHelper.AreRelativeEqual(value, DeclarationData.PTOTransmission.Lookup(technology)); + } + + [TestCase("Superfluid")] + public void AuxPTOTransmission_NotExistingError(string technology) + { + AssertHelper.Exception<VectoException>(() => { DeclarationData.PTOTransmission.Lookup(technology); }); + } + + [TestCase("", new[] { 618, 671, 516, 566, 1037 }), + TestCase("Crankshaft mounted - Electronically controlled visco clutch", new[] { 618, 671, 516, 566, 1037 }), + TestCase("Crankshaft mounted - Bimetallic controlled visco clutch", new[] { 818, 871, 676, 766, 1277 }), + TestCase("Crankshaft mounted - Discrete step clutch", new[] { 668, 721, 616, 616, 1157 }), + TestCase("Crankshaft mounted - On/off clutch", new[] { 718, 771, 666, 666, 1237 }), + TestCase("Belt driven or driven via transm. - Electronically controlled visco clutch", + new[] { 989, 1044, 833, 933, 1478 }), + TestCase("Belt driven or driven via transm. - Bimetallic controlled visco clutch", + new[] { 1189, 1244, 993, 1133, 1718 }), + TestCase("Belt driven or driven via transm. - Discrete step clutch", new[] { 1039, 1094, 983, 983, 1598 }), + TestCase("Belt driven or driven via transm. - On/off clutch", new[] { 1089, 1144, 1033, 1033, 1678 }), + TestCase("Hydraulic driven - Variable displacement pump", new[] { 938, 1155, 832, 917, 1872 }), + TestCase("Hydraulic driven - Constant displacement pump", new[] { 1200, 1400, 1000, 1100, 2300 }), + TestCase("Hydraulic driven - Electronically controlled", new[] { 700, 800, 600, 600, 1400 }),] + public void AuxFanTechTest(string technology, int[] expected) + { + for (var i = 0; i < _missions.Length; i++) { + var value = DeclarationData.Fan.Lookup(_missions[i], technology); + Assert.AreEqual(expected[i], value.Value(), Tolerance); + } + } + + [TestCase("Superfluid Hydraulic", MissionType.LongHaul, TestName = "AuxFanTechError( wrong tech )"), + TestCase("Hydraulic driven - Electronically controlled", MissionType.Coach, + TestName = "AuxFanTechError( wrong mission )") + ] + public void AuxFanTechError(string technology, MissionType missionType) + { + AssertHelper.Exception<VectoException>(() => DeclarationData.Fan.Lookup(missionType, technology)); + } + + [TestCase(VehicleClass.Class1, new[] { 0, 150, 150, 0, 0 }), + TestCase(VehicleClass.Class2, new[] { 200, 200, 150, 0, 0 }), + TestCase(VehicleClass.Class3, new[] { 0, 200, 150, 0, 0 }), + TestCase(VehicleClass.Class4, new[] { 350, 200, 0, 300, 0 }), + TestCase(VehicleClass.Class5, new[] { 350, 200, 0, 0, 0 }), + TestCase(VehicleClass.Class9, new[] { 350, 200, 0, 300, 0 }), + TestCase(VehicleClass.Class10, new[] { 350, 200, 0, 0, 0 }), + TestCase(VehicleClass.Class11, new[] { 350, 200, 0, 300, 200 }), + TestCase(VehicleClass.Class12, new[] { 350, 200, 0, 0, 200 }), + TestCase(VehicleClass.Class16, new[] { 0, 0, 0, 0, 200 })] + public void AuxHeatingVentilationAirConditionTest_Default(VehicleClass vehicleClass, int[] expected) + { + for (var i = 0; i < expected.Length; i++) { + if (expected[i] > 0) { + AssertHelper.AreRelativeEqual(expected[i], + DeclarationData.HeatingVentilationAirConditioning.Lookup(_missions[i], "Default", vehicleClass)); + } else { + var i1 = i; + AssertHelper.Exception<VectoException>( + () => DeclarationData.HeatingVentilationAirConditioning.Lookup(_missions[i1], "Default", vehicleClass)); + } + } + } + + [TestCase(VehicleClass.Class1, new[] { 0, 0, 0, 0, 0 }), + TestCase(VehicleClass.Class2, new[] { 0, 0, 0, 0, 0 }), + TestCase(VehicleClass.Class3, new[] { 0, 0, 0, 0, 0 }), + TestCase(VehicleClass.Class4, new[] { 0, 0, 0, 0, 0 }), + TestCase(VehicleClass.Class5, new[] { 0, 0, 0, 0, 0 }), + TestCase(VehicleClass.Class9, new[] { 0, 0, 0, 0, 0 }), + TestCase(VehicleClass.Class10, new[] { 0, 0, 0, 0, 0 }), + TestCase(VehicleClass.Class11, new[] { 0, 0, 0, 0, 0 }), + TestCase(VehicleClass.Class12, new[] { 0, 0, 0, 0, 0 }), + TestCase(VehicleClass.Class16, new[] { 0, 0, 0, 0, 0 })] + public void AuxHeatingVentilationAirConditionTest_None(VehicleClass vehicleClass, int[] expected) + { + for (var i = 0; i < expected.Length; i++) { + AssertHelper.AreRelativeEqual(expected[i], + DeclarationData.HeatingVentilationAirConditioning.Lookup(_missions[i], "None", vehicleClass)); + } + } + + [TestCase()] + public void AuxHetingVentilationAirConditionTechnologyTest() + { + var tech = DeclarationData.HeatingVentilationAirConditioning.GetTechnologies(); + Assert.AreEqual(2, tech.Length); + Assert.IsTrue(tech.Contains("Default")); + Assert.IsTrue(tech.Contains("None")); + } + + [Test, + TestCase("Small", new[] { 1400, 1300, 1200, 1200, 1300 }), + TestCase("Small + ESS", new[] { 900, 800, 800, 800, 800 }), + TestCase("Small + visco clutch", new[] { 800, 700, 700, 700, 700 }), + TestCase("Small + mech. clutch", new[] { 600, 600, 650, 650, 600 }), + TestCase("Small + ESS + AMS", new[] { 500, 400, 500, 500, 400 }), + TestCase("Small + visco clutch + AMS", new[] { 400, 300, 400, 400, 300 }), + TestCase("Small + mech. clutch + AMS", new[] { 200, 200, 350, 350, 200 }), + TestCase("Medium Supply 1-stage", new[] { 1600, 1400, 1350, 1350, 1500 }), + TestCase("Medium Supply 1-stage + ESS", new[] { 1000, 900, 900, 900, 900 }), + TestCase("Medium Supply 1-stage + visco clutch", new[] { 850, 800, 800, 800, 750 }), + TestCase("Medium Supply 1-stage + mech. clutch", new[] { 600, 550, 550, 550, 600 }), + TestCase("Medium Supply 1-stage + ESS + AMS", new[] { 600, 700, 700, 700, 500 }), + TestCase("Medium Supply 1-stage + visco clutch + AMS", new[] { 450, 600, 600, 600, 350 }), + TestCase("Medium Supply 1-stage + mech. clutch + AMS", new[] { 200, 350, 350, 350, 200 }), + TestCase("Medium Supply 2-stage", new[] { 2100, 1750, 1700, 1700, 2100 }), + TestCase("Medium Supply 2-stage + ESS", new[] { 1100, 1050, 1000, 1000, 1000 }), + TestCase("Medium Supply 2-stage + visco clutch", new[] { 1000, 850, 800, 800, 900 }), + TestCase("Medium Supply 2-stage + mech. clutch", new[] { 700, 650, 600, 600, 800 }), + TestCase("Medium Supply 2-stage + ESS + AMS", new[] { 700, 850, 800, 800, 500 }), + TestCase("Medium Supply 2-stage + visco clutch + AMS", new[] { 600, 650, 600, 600, 400 }), + TestCase("Medium Supply 2-stage + mech. clutch + AMS", new[] { 300, 450, 400, 400, 300 }), + TestCase("Large Supply", new[] { 4300, 3600, 3500, 3500, 4100 }), + TestCase("Large Supply + ESS", new[] { 1600, 1300, 1200, 1200, 1500 }), + TestCase("Large Supply + visco clutch", new[] { 1300, 1100, 1000, 1000, 1200 }), + TestCase("Large Supply + mech. clutch", new[] { 800, 800, 700, 700, 900 }), + TestCase("Large Supply + ESS + AMS", new[] { 1100, 1000, 1000, 1000, 1000 }), + TestCase("Large Supply + visco clutch + AMS", new[] { 800, 800, 800, 800, 700 }), + TestCase("Large Supply + mech. clutch + AMS", new[] { 300, 500, 500, 500, 400 }), + TestCase("Vacuum pump", new[] { 190, 160, 130, 130, 130 }), + ] + public void AuxPneumaticSystemTest(string technology, int[] expected) + { + for (var i = 0; i < _missions.Length; i++) { + var value = DeclarationData.PneumaticSystem.Lookup(_missions[i], technology); + AssertHelper.AreRelativeEqual(expected[i], value); + } + } + + [ + TestCase(MissionType.LongHaul, VehicleClass.Class2, 370, "Fixed displacement", null, null, null), + TestCase(MissionType.LongHaul, VehicleClass.Class4, 610, "Fixed displacement", null, null, null), + TestCase(MissionType.LongHaul, VehicleClass.Class5, 720, "Fixed displacement", null, null, null), + TestCase(MissionType.LongHaul, VehicleClass.Class9, 720, "Fixed displacement", null, null, null), + TestCase(MissionType.LongHaul, VehicleClass.Class10, 570, "Fixed displacement", null, null, null), + TestCase(MissionType.LongHaul, VehicleClass.Class11, 720, "Fixed displacement", null, null, null), + TestCase(MissionType.LongHaul, VehicleClass.Class12, 570, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class1, 280, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 340, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class3, 370, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class4, 570, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class5, 670, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class9, 590, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class10, 570, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class11, 590, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class12, 570, "Fixed displacement", null, null, null), + TestCase(MissionType.UrbanDelivery, VehicleClass.Class1, 270, "Fixed displacement", null, null, null), + TestCase(MissionType.UrbanDelivery, VehicleClass.Class2, 310, "Fixed displacement", null, null, null), + TestCase(MissionType.UrbanDelivery, VehicleClass.Class3, 350, "Fixed displacement", null, null, null), + TestCase(MissionType.UrbanDelivery, VehicleClass.Class5, 620, "Fixed displacement", null, null, null), + TestCase(MissionType.MunicipalUtility, VehicleClass.Class4, 510, "Fixed displacement", null, null, null), + TestCase(MissionType.MunicipalUtility, VehicleClass.Class9, 510, "Fixed displacement", null, null, null), + TestCase(MissionType.MunicipalUtility, VehicleClass.Class11, 510, "Fixed displacement", null, null, null), + TestCase(MissionType.Construction, VehicleClass.Class11, 770, "Fixed displacement", null, null, null), + TestCase(MissionType.Construction, VehicleClass.Class12, 770, "Fixed displacement", null, null, null), + TestCase(MissionType.Construction, VehicleClass.Class16, 770, "Fixed displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 325.5, "Fixed displacement with elec. control", null, + null, + null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 289, "Dual displacement", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 255, "Variable displacement mech. controlled", null, + null, + null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 204, "Variable displacement elec. controlled", null, + null, + null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 92.8571, "Electric", null, null, null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 665, "Fixed displacement", "Fixed displacement", null, + null), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 1295, "Fixed displacement", "Fixed displacement", + "Fixed displacement", "Fixed displacement"), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, 1021.5, "Dual displacement", + "Variable displacement mech. controlled", "Fixed displacement with elec. control", + "Variable displacement elec. controlled"), + ] + public void Aux_SteeringPumpLookupValues(MissionType mission, VehicleClass hdvClass, double expected, string axle1, + string axle2, string axle3, string axle4) + { + // mk remark: made the test call with 4 axle params, so that the test name is clear in the test explorer. + AssertHelper.AreRelativeEqual(expected, + DeclarationData.SteeringPump.Lookup(mission, hdvClass, + new[] { axle1, axle2, axle3, axle4 }.TakeWhile(a => a != null).ToArray())); + } + + [TestCase(MissionType.LongHaul, VehicleClass.Class1, "Dual displacement", + TestName = "Aux_SteeringPumpLookupFail( No Value )"), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, "Super displacement", + TestName = "Aux_SteeringPumpLookupFail( Wrong Tech )"), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, "Dual displacement", "Dual displacement", + "Dual displacement", "Dual displacement", "Dual displacement", TestName = "Aux_SteeringPumpLookupFail( >4 Techs )"), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, TestName = "Aux_SteeringPumpLookupFail( Null Techs )"), + TestCase(MissionType.RegionalDelivery, VehicleClass.Class2, new string[0], + TestName = "Aux_SteeringPumpLookupFail( 0 Techs )"), + ] + public void Aux_SteeringPumpLookupFail(MissionType mission, VehicleClass hdvClass, params string[] tech) + { + AssertHelper.Exception<VectoException>(() => DeclarationData.SteeringPump.Lookup(mission, hdvClass, tech)); + } + + [ + TestCase(0), + TestCase(1000), + TestCase(3500), + TestCase(7499) + ] + public void SegmentWeightOutOfRange4X2(double weight) + { + AssertHelper.Exception<VectoException>(() => + DeclarationData.Segments.Lookup( + VehicleCategory.RigidTruck, + AxleConfiguration.AxleConfig_4x2, + weight.SI<Kilogram>(), + 0.SI<Kilogram>()), + "Gross vehicle mass must be greater than 7.5 tons"); + } + + [ + TestCase(0), + TestCase(1000), + TestCase(3500), + TestCase(7499) + ] + public void SegmentWeightOutOfRange4X4(double weight) + { + AssertHelper.Exception<VectoException>(() => + DeclarationData.Segments.Lookup( + VehicleCategory.RigidTruck, + AxleConfiguration.AxleConfig_4x4, + weight.SI<Kilogram>(), + 0.SI<Kilogram>()), + "Gross vehicle mass must be greater than 7.5 tons"); + } + + [Test, + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10001, 0, VehicleClass.Class2), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 10001, 0, VehicleClass.Class2), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12001, 0, VehicleClass.Class3), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12001, 0, VehicleClass.Class3), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16001, 0, VehicleClass.Class4), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 99000, 0, VehicleClass.Class4), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16001, 0, VehicleClass.Class5), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 99000, 0, VehicleClass.Class5), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 7500, 0, VehicleClass.Class9), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class9), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class9), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 99000, 0, VehicleClass.Class9), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 7500, 0, VehicleClass.Class10), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class10), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class10), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 99000, 0, VehicleClass.Class10), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 7500, 0, VehicleClass.Class11), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 40000, 0, VehicleClass.Class11), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 7500, 0, VehicleClass.Class12), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 99000, 0, VehicleClass.Class12), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 7500, 0, VehicleClass.Class16), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 99000, 0, VehicleClass.Class16) + ] + public void SegmentLookupTest(VehicleCategory category, AxleConfiguration axleConfiguration, double grossWeight, + double curbWeight, VehicleClass expectedClass) + { + var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), + curbWeight.SI<Kilogram>()); + Assert.AreEqual(expectedClass, segment.VehicleClass); + } + + [TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1, 85), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10001, 0, VehicleClass.Class2, 85), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12001, 0, VehicleClass.Class3, 85), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16001, 0, VehicleClass.Class4, 85), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16001, 0, VehicleClass.Class5, 85), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 7500, 0, VehicleClass.Class9, 85), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 7500, 0, VehicleClass.Class10, 85), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 7500, 0, VehicleClass.Class11, 85), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 7500, 0, VehicleClass.Class12, 85), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 7500, 0, VehicleClass.Class16, 85), + ] + public void SegmentDesignSpeedTest(VehicleCategory category, AxleConfiguration axleConfiguration, double grossWeight, + double curbWeight, VehicleClass expectedClass, double speed) + { + var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), + curbWeight.SI<Kilogram>()); + + Assert.AreEqual(speed.KMPHtoMeterPerSecond(), segment.DesignSpeed); + } + + [Test, + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1, 1600, null, + TestName = "SegmentLookupBodyWeight Class1 Rigid"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1, 1600, null, + TestName = "SegmentLookupBodyWeight Class1 Tractor"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, 1900, 3400, + TestName = "SegmentLookupBodyWeight Class2 Rigid"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, 1900, 3400, + TestName = "SegmentLookupBodyWeight Class2 Tractor"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, 2000, null, + TestName = "SegmentLookupBodyWeight Class3 Rigid"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, 2000, null, + TestName = "SegmentLookupBodyWeight Class3 Tractor"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class4, 2100, 5400, + TestName = "SegmentLookupBodyWeight Class4"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class5, null, 7500, + TestName = "SegmentLookupBodyWeight Class5"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class9, 2200, 5400, + TestName = "SegmentLookupBodyWeight Class9"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class10, null, 7500, + TestName = "SegmentLookupBodyWeight Class10"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 12000, 0, VehicleClass.Class11, 2200, 5400, + TestName = "SegmentLookupBodyWeight Class11"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 12000, 0, VehicleClass.Class12, null, 7500, + TestName = "SegmentLookupBodyWeight Class12"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 12000, 0, VehicleClass.Class16, null, null, + TestName = "SegmentLookupBodyWeight Class16")] + public void SegmentLookupBodyTest(VehicleCategory category, AxleConfiguration axleConfiguration, double grossWeight, + double curbWeight, VehicleClass expectedClass, int? expectedBodyWeight, int? expectedTrailerWeight) + { + var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), + curbWeight.SI<Kilogram>()); + Assert.AreEqual(expectedClass, segment.VehicleClass); + + if (expectedBodyWeight.HasValue) { + Assert.AreEqual(expectedBodyWeight, segment.Missions[0].BodyCurbWeight.Value()); + } + if (expectedTrailerWeight.HasValue) { + var trailerMission = segment.Missions.Where(m => m.Trailer.Count > 0).ToList(); + if (trailerMission.Count > 0) { + Assert.AreEqual(expectedTrailerWeight, trailerMission.First().Trailer.First().TrailerCurbWeight.Value()); + } + } + } + + [Test, + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1, 3.6, + TestName = "SegmentLookupHeight Class1 Rigid"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 10000, 0, VehicleClass.Class1, 3.6, + TestName = "SegmentLookupHeight Class1 Tractor"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, 3.75, + TestName = "SegmentLookupHeight Class2 Rigid"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, 3.75, + TestName = "SegmentLookupHeight Class2 Tractor"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, 3.9, + TestName = "SegmentLookupHeight Class3 Rigid"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, 3.9, + TestName = "SegmentLookupHeight Class3 Tractor"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class4, 4.0, + TestName = "SegmentLookupHeight Class4"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class5, 4.0, + TestName = "SegmentLookupHeight Class5"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 10000, 0, VehicleClass.Class9, 3.6, + TestName = "SegmentLookupHeight Class9 - 1"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 12000, 0, VehicleClass.Class9, 3.75, + TestName = "SegmentLookupHeight Class9 - 2"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class9, 3.9, + TestName = "SegmentLookupHeight Class9 - 3"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 18000, 0, VehicleClass.Class9, 4.0, + TestName = "SegmentLookupHeight Class9 - 4"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class9, 4.0, + TestName = "SegmentLookupHeight Class9 - other"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 40000, 0, VehicleClass.Class10, 4.0, + TestName = "SegmentLookupHeight Class10"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 12000, 0, VehicleClass.Class11, 4.0, + TestName = "SegmentLookupHeight Class11"), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 12000, 0, VehicleClass.Class12, 4.0, + TestName = "SegmentLookupHeight Class12"), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 12000, 0, VehicleClass.Class16, 3.6, + TestName = "SegmentLookupHeight Class16")] + public void SegmentLookupHeightTest(VehicleCategory category, AxleConfiguration axleConfiguration, double grossWeight, + double curbWeight, VehicleClass expectedClass, double expectedHeight) + { + var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), + curbWeight.SI<Kilogram>()); + Assert.AreEqual(expectedClass, segment.VehicleClass); + AssertHelper.AreRelativeEqual(expectedHeight, segment.VehicleHeight); + } + + [Test, + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1, + new[] { 36.5, 36.5 }), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 7500, 0, VehicleClass.Class1, + new[] { 36.5, 36.5 }), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, + new[] { 85.0, 45.2, 45.2 }), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 12000, 0, VehicleClass.Class2, + new[] { 85.0, 45.2, 45.2 }), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, + new[] { 47.7, 47.7 }), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 16000, 0, VehicleClass.Class3, + new[] { 47.7, 47.7 }), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class4, + new[] { 98.9, 49.4, 49.4 }), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_4x2, 18000, 0, VehicleClass.Class5, + new[] { 91.0, 140.5, 91.0, 140.5 }), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class9, + new[] { 101.4, 142.9, 51.9, 142.9, 51.9 }), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x2, 16000, 0, VehicleClass.Class10, + new[] { 91.0, 140.5, 91.0, 140.5 }), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_6x4, 40000, 0, VehicleClass.Class11, + new[] { 101.4, 142.9, 51.9, 142.9, 51.9, 51.9 }), + TestCase(VehicleCategory.Tractor, AxleConfiguration.AxleConfig_6x4, 99000, 0, VehicleClass.Class12, + new[] { 91.0, 140.5, 91.0, 140.5, 91.0 }), + TestCase(VehicleCategory.RigidTruck, AxleConfiguration.AxleConfig_8x4, 99000, 0, VehicleClass.Class16, + new[] { 0.0 }) + ] + public void SegmentLookupCargoVolumeTest(VehicleCategory category, AxleConfiguration axleConfiguration, + double grossWeight, + double curbWeight, VehicleClass expectedClass, double[] expectedCargoVolume) + { + var segment = DeclarationData.Segments.Lookup(category, axleConfiguration, grossWeight.SI<Kilogram>(), + curbWeight.SI<Kilogram>()); + Assert.AreEqual(expectedClass, segment.VehicleClass); + Assert.AreEqual(expectedCargoVolume.Length, segment.Missions.Length); + for (var i = 0; i < expectedCargoVolume.Length; i++) { + Assert.AreEqual(expectedCargoVolume[i], segment.Missions[i].TotalCargoVolume.Value()); + } + } + + /// <summary> + /// trailer in longhaul, always pc formula + /// </summary> + [TestCase] + public void Segment2Test() + { + var vehicleData = new { + VehicleCategory = VehicleCategory.RigidTruck, + AxleConfiguration = AxleConfiguration.AxleConfig_4x2, + GrossVehicleMassRating = 11900.SI<Kilogram>(), + CurbWeight = 5850.SI<Kilogram>() + }; + + var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, + vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); + + Assert.AreEqual(VehicleClass.Class2, segment.VehicleClass); + + var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); + TestAcceleration(data); + + Assert.AreEqual(3, segment.Missions.Length); + + AssertMission(segment.Missions[0], + vehicleData: vehicleData, + missionType: MissionType.LongHaul, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.225, 0.325 }, + trailerAxleWeightDistribution: new[] { 0.45 }, + trailerAxleCount: new[] { 2 }, + bodyCurbWeight: 1900, + trailerCurbWeight: new[] { 3400.0 }, + trailerType: new[] { TrailerType.T1 }, + lowLoad: 1306.8235, + refLoad: 9813.2353, + trailerGrossVehicleWeight: new[] { 10500.0 }, + deltaCdA: 1.3, + maxLoad: 11250); + + AssertMission(segment.Missions[1], + vehicleData: vehicleData, + missionType: MissionType.RegionalDelivery, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.45, 0.55 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 1900, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 596.8235, + refLoad: 2984.1176, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 4150); + + AssertMission(segment.Missions[2], + vehicleData: vehicleData, + missionType: MissionType.UrbanDelivery, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.45, 0.55 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 1900, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 596.8235, + refLoad: 2984.1176, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 4150); + } + + /// <summary> + /// normal pc formula, no trailer + /// </summary> + [TestCase] + public void Segment3Test() + { + var vehicleData = new { + VehicleCategory = VehicleCategory.RigidTruck, + AxleConfiguration = AxleConfiguration.AxleConfig_4x2, + GrossVehicleMassRating = 14000.SI<Kilogram>(), + CurbWeight = 5850.SI<Kilogram>() + }; + + var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, + vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); + + Assert.AreEqual(VehicleClass.Class3, segment.VehicleClass); + + Assert.AreEqual(2, segment.Missions.Length); + + AssertMission(segment.Missions[0], + vehicleData: vehicleData, + missionType: MissionType.RegionalDelivery, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.4, 0.6 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 2000, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 762.3529, + refLoad: 3811.7647, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 6150); + + AssertMission(segment.Missions[1], + vehicleData: vehicleData, + missionType: MissionType.UrbanDelivery, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.4, 0.6 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 2000, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 762.3529, + refLoad: 3811.7647, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 6150); + } + + /// <summary> + /// fixed reference weight, trailer only in longhaul + /// </summary> + [TestCase] + public void Segment4Test() + { + var vehicleData = new { + VehicleCategory = VehicleCategory.RigidTruck, + AxleConfiguration = AxleConfiguration.AxleConfig_4x2, + GrossVehicleMassRating = 18000.SI<Kilogram>(), + CurbWeight = 7500.SI<Kilogram>() + }; + + var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, + vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); + + Assert.AreEqual(VehicleClass.Class4, segment.VehicleClass); + + var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); + TestAcceleration(data); + + Assert.AreEqual(3, segment.Missions.Length); + + AssertMission(segment.Missions[0], + vehicleData: vehicleData, + missionType: MissionType.LongHaul, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.2, 0.3 }, + trailerAxleWeightDistribution: new[] { 0.5 }, + trailerAxleCount: new[] { 2 }, + bodyCurbWeight: 2100, + trailerCurbWeight: new[] { 5400.0 }, + trailerType: new[] { TrailerType.T2 }, + lowLoad: 1900, + refLoad: 14000, + trailerGrossVehicleWeight: new[] { 18000.0 }, + deltaCdA: 1.5, + maxLoad: 21000); + + AssertMission(segment.Missions[1], + vehicleData: vehicleData, + missionType: MissionType.RegionalDelivery, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.45, 0.55 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 2100, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 900, + refLoad: 4400, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 8400); + + AssertMission(segment.Missions[2], + vehicleData: vehicleData, + missionType: MissionType.MunicipalUtility, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.45, 0.55 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 2100, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 600, + refLoad: 3000, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 8400); + } + + /// <summary> + /// Segment 5: fixed reference weight, trailer always used + /// </summary> + [TestCase] + public void Segment5Test() + { + var vehicleData = new { + VehicleCategory = VehicleCategory.Tractor, + AxleConfiguration = AxleConfiguration.AxleConfig_4x2, + GrossVehicleMassRating = 18000.SI<Kilogram>(), + CurbWeight = 7500.SI<Kilogram>() + }; + + var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, + vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); + + Assert.AreEqual(VehicleClass.Class5, segment.VehicleClass); + + var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); + TestAcceleration(data); + + Assert.AreEqual(4, segment.Missions.Length); + + AssertMission(segment.Missions[0], + vehicleData: vehicleData, + missionType: MissionType.LongHaul, + cosswindCorrection: "TractorSemitrailer", + axleWeightDistribution: new[] { 0.2, 0.25 }, + trailerAxleWeightDistribution: new[] { 0.55 }, + trailerAxleCount: new[] { 3 }, bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0 }, + trailerType: new[] { TrailerType.ST1 }, + lowLoad: 2600, + refLoad: 19300, + trailerGrossVehicleWeight: new[] { 24000.0 }, + deltaCdA: 0, + maxLoad: 25000); + + AssertMission(segment.Missions[1], + vehicleData: vehicleData, + missionType: MissionType.LongHaulEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.15, 0.2 }, + trailerAxleWeightDistribution: new[] { 0.40, 0.25 }, + trailerAxleCount: new[] { 3, 2 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0, 5400 }, + trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, + lowLoad: 3500, + refLoad: 26500, + trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, + deltaCdA: 1.5, + maxLoad: 39600, + ems: true); + + AssertMission(segment.Missions[2], + vehicleData: vehicleData, + missionType: MissionType.RegionalDelivery, + cosswindCorrection: "TractorSemitrailer", + axleWeightDistribution: new[] { 0.25, 0.25 }, + trailerAxleWeightDistribution: new[] { 0.5 }, + trailerAxleCount: new[] { 3 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0 }, + trailerType: new[] { TrailerType.ST1 }, + lowLoad: 2600, + refLoad: 12900, + trailerGrossVehicleWeight: new[] { 24000.0 }, + deltaCdA: 0, maxLoad: 25000); + + AssertMission(segment.Missions[3], + vehicleData: vehicleData, + missionType: MissionType.RegionalDeliveryEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.175, 0.25 }, + trailerAxleWeightDistribution: new[] { 0.35, 0.225 }, + trailerAxleCount: new[] { 3, 2 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0, 5400 }, + trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, + lowLoad: 3500, + refLoad: 17500, + trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, + deltaCdA: 1.5, + maxLoad: 39600, + ems: true); + } + + /// <summary> + /// Segment 9: fixed reference weight, trailer always used + /// </summary> + [TestCase] + public void Segment9Test() + { + var vehicleData = new { + VehicleCategory = VehicleCategory.RigidTruck, + AxleConfiguration = AxleConfiguration.AxleConfig_6x2, + GrossVehicleMassRating = 24000.SI<Kilogram>(), + CurbWeight = 7500.SI<Kilogram>() + }; + + var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, + vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); + + Assert.AreEqual(VehicleClass.Class9, segment.VehicleClass); + + var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); + TestAcceleration(data); + + Assert.AreEqual(5, segment.Missions.Length); + + AssertMission(segment.Missions[0], + vehicleData: vehicleData, + missionType: MissionType.LongHaul, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.2, 0.3, 0.15 }, + trailerAxleWeightDistribution: new[] { 0.35 }, + trailerAxleCount: new[] { 2 }, + bodyCurbWeight: 2200, + trailerCurbWeight: new[] { 5400.0 }, + trailerType: new[] { TrailerType.T2 }, + lowLoad: 2600, + refLoad: 19300, + trailerGrossVehicleWeight: new[] { 18000.0 }, + deltaCdA: 1.5, + maxLoad: 24900); + + AssertMission(segment.Missions[1], + vehicleData: vehicleData, + missionType: MissionType.LongHaulEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.15, 0.2, 0.1 }, + trailerAxleWeightDistribution: new[] { 0.225, 0.325 }, + trailerAxleCount: new[] { 2, 3 }, + bodyCurbWeight: 2200, + trailerCurbWeight: new[] { 2500, 7500.0 }, + trailerType: new[] { TrailerType.Dolly, TrailerType.ST1 }, + lowLoad: 3500, + refLoad: 26500, + trailerGrossVehicleWeight: new[] { 12000.0, 24000 }, + deltaCdA: 2.1, + maxLoad: 40300, + ems: true); + + AssertMission(segment.Missions[2], + vehicleData: vehicleData, + missionType: MissionType.RegionalDelivery, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.35, 0.4, 0.25 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 2200, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 1400, + refLoad: 7100, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 14300); + + AssertMission(segment.Missions[3], + vehicleData: vehicleData, + missionType: MissionType.RegionalDeliveryEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.175, 0.2, 0.1 }, + trailerAxleWeightDistribution: new[] { 0.225, 0.3 }, + trailerAxleCount: new[] { 2, 3 }, + bodyCurbWeight: 2200, + trailerCurbWeight: new[] { 2500, 7500.0 }, + trailerType: new[] { TrailerType.Dolly, TrailerType.ST1 }, + lowLoad: 3500, + refLoad: 17500, + trailerGrossVehicleWeight: new[] { 12000.0, 24000 }, + deltaCdA: 2.1, + maxLoad: 40300, + ems: true); + + AssertMission(segment.Missions[4], + vehicleData: vehicleData, + missionType: MissionType.MunicipalUtility, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.35, 0.4, 0.25 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 2200, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 1200, + refLoad: 6000, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 14300); + } + + /// <summary> + /// Segment 10: fixed reference weight, trailer always used + /// </summary> + [TestCase] + public void Segment10Test() + { + var vehicleData = new { + VehicleCategory = VehicleCategory.Tractor, + AxleConfiguration = AxleConfiguration.AxleConfig_6x2, + GrossVehicleMassRating = 24000.SI<Kilogram>(), + CurbWeight = 7500.SI<Kilogram>() + }; + + var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, + vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); + + Assert.AreEqual(VehicleClass.Class10, segment.VehicleClass); + + var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); + TestAcceleration(data); + + Assert.AreEqual(4, segment.Missions.Length); + + AssertMission(segment.Missions[0], + vehicleData: vehicleData, + missionType: MissionType.LongHaul, + cosswindCorrection: "TractorSemitrailer", + axleWeightDistribution: new[] { 0.15, 0.1, 0.2 }, + trailerAxleWeightDistribution: new[] { 0.55 }, + trailerAxleCount: new[] { 3 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0 }, + trailerType: new[] { TrailerType.ST1 }, + lowLoad: 2600, + refLoad: 19300, + trailerGrossVehicleWeight: new[] { 24000.0 }, + deltaCdA: 0, + maxLoad: 25000); + + AssertMission(segment.Missions[1], + vehicleData: vehicleData, + missionType: MissionType.LongHaulEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.125, 0.15, 0.1 }, + trailerAxleWeightDistribution: new[] { 0.375, 0.25 }, + trailerAxleCount: new[] { 3, 2 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0, 5400 }, + trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, + lowLoad: 3500, + refLoad: 26500, + trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, + deltaCdA: 1.5, + maxLoad: 39600, + ems: true); + + AssertMission(segment.Missions[2], + vehicleData: vehicleData, + missionType: MissionType.RegionalDelivery, + cosswindCorrection: "TractorSemitrailer", + axleWeightDistribution: new[] { 0.2, 0.1, 0.2 }, + trailerAxleWeightDistribution: new[] { 0.5 }, + trailerAxleCount: new[] { 3 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0 }, + trailerType: new[] { TrailerType.ST1 }, + lowLoad: 2600, + refLoad: 12900, + trailerGrossVehicleWeight: new[] { 24000.0 }, + deltaCdA: 0, + maxLoad: 25000); + + AssertMission(segment.Missions[3], + vehicleData: vehicleData, + missionType: MissionType.RegionalDeliveryEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.15, 0.15, 0.1 }, + trailerAxleWeightDistribution: new[] { 0.35, 0.25 }, + trailerAxleCount: new[] { 3, 2 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0, 5400 }, + trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, + lowLoad: 3500, + refLoad: 17500, + trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, + deltaCdA: 1.5, + maxLoad: 39600, + ems: true); + } + + /// <summary> + /// Segment 11: fixed reference weight, trailer always used + /// </summary> + [TestCase] + public void Segment11Test() + { + var vehicleData = new { + VehicleCategory = VehicleCategory.RigidTruck, + AxleConfiguration = AxleConfiguration.AxleConfig_6x4, + GrossVehicleMassRating = 24000.SI<Kilogram>(), + CurbWeight = 7500.SI<Kilogram>() + }; + + var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, + vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); + + Assert.AreEqual(VehicleClass.Class11, segment.VehicleClass); + + var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); + TestAcceleration(data); + + Assert.AreEqual(6, segment.Missions.Length); + + AssertMission(segment.Missions[0], + vehicleData: vehicleData, + missionType: MissionType.LongHaul, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.2, 0.225, 0.225 }, + trailerAxleWeightDistribution: new[] { 0.35 }, + trailerAxleCount: new[] { 2 }, + bodyCurbWeight: 2200, + trailerCurbWeight: new[] { 5400.0 }, + trailerType: new[] { TrailerType.T2 }, + lowLoad: 2600, + refLoad: 19300, + trailerGrossVehicleWeight: new[] { 18000.0 }, + deltaCdA: 1.5, + maxLoad: 24900); + + AssertMission(segment.Missions[1], + vehicleData: vehicleData, + missionType: MissionType.LongHaulEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.15, 0.2, 0.1 }, + trailerAxleWeightDistribution: new[] { 0.225, 0.325 }, + trailerAxleCount: new[] { 2, 3 }, + bodyCurbWeight: 2200, + trailerCurbWeight: new[] { 2500, 7500.0 }, + trailerType: new[] { TrailerType.Dolly, TrailerType.ST1 }, + lowLoad: 3500, + refLoad: 26500, + trailerGrossVehicleWeight: new[] { 12000.0, 24000 }, + deltaCdA: 2.1, + maxLoad: 40300, + ems: true); + + AssertMission(segment.Missions[2], + vehicleData: vehicleData, + missionType: MissionType.RegionalDelivery, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.35, 0.35, 0.3 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, bodyCurbWeight: 2200, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 1400, + refLoad: 7100, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 14300); + + AssertMission(segment.Missions[3], + vehicleData: vehicleData, + missionType: MissionType.RegionalDeliveryEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.175, 0.2, 0.1 }, + trailerAxleWeightDistribution: new[] { 0.225, 0.3 }, + trailerAxleCount: new[] { 2, 3 }, + bodyCurbWeight: 2200, + trailerCurbWeight: new[] { 2500, 7500.0 }, + trailerType: new[] { TrailerType.Dolly, TrailerType.ST1 }, + lowLoad: 3500, + refLoad: 17500, + trailerGrossVehicleWeight: new[] { 12000.0, 24000 }, + deltaCdA: 2.1, + maxLoad: 40300, + ems: true); + + AssertMission(segment.Missions[4], + vehicleData: vehicleData, + missionType: MissionType.MunicipalUtility, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.35, 0.35, 0.3 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 2200, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 1200, + refLoad: 6000, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 14300); + + AssertMission(segment.Missions[5], + vehicleData: vehicleData, + missionType: MissionType.Construction, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.35, 0.35, 0.3 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 2200, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 1400, + refLoad: 7100, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 14300); + } + + /// <summary> + /// Segment 10: fixed reference weight, trailer always used + /// </summary> + [TestCase] + public void Segment12Test() + { + var vehicleData = new { + VehicleCategory = VehicleCategory.Tractor, + AxleConfiguration = AxleConfiguration.AxleConfig_6x4, + GrossVehicleMassRating = 24000.SI<Kilogram>(), + CurbWeight = 7500.SI<Kilogram>() + }; + + var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, + vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); + + Assert.AreEqual(VehicleClass.Class12, segment.VehicleClass); + + var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); + TestAcceleration(data); + + Assert.AreEqual(5, segment.Missions.Length); + + AssertMission(segment.Missions[0], + vehicleData: vehicleData, + missionType: MissionType.LongHaul, + cosswindCorrection: "TractorSemitrailer", + axleWeightDistribution: new[] { 0.15, 0.15, 0.15 }, + trailerAxleWeightDistribution: new[] { 0.55 }, + trailerAxleCount: new[] { 3 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0 }, + trailerType: new[] { TrailerType.ST1 }, + lowLoad: 2600, + refLoad: 19300, + trailerGrossVehicleWeight: new[] { 24000.0 }, + deltaCdA: 0, + maxLoad: 25000); + + AssertMission(segment.Missions[1], + vehicleData: vehicleData, + missionType: MissionType.LongHaulEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.125, 0.15, 0.1 }, + trailerAxleWeightDistribution: new[] { 0.375, 0.25 }, + trailerAxleCount: new[] { 3, 2 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0, 5400 }, + trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, + lowLoad: 3500, + refLoad: 26500, + trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, + deltaCdA: 1.5, + maxLoad: 39600, + ems: true); + + AssertMission(segment.Missions[2], + vehicleData: vehicleData, + missionType: MissionType.RegionalDelivery, + cosswindCorrection: "TractorSemitrailer", + axleWeightDistribution: new[] { 0.2, 0.15, 0.15 }, + trailerAxleWeightDistribution: new[] { 0.5 }, + trailerAxleCount: new[] { 3 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0 }, + trailerType: new[] { TrailerType.ST1 }, + lowLoad: 2600, + refLoad: 12900, + trailerGrossVehicleWeight: new[] { 24000.0 }, + deltaCdA: 0, + maxLoad: 25000); + + AssertMission(segment.Missions[3], + vehicleData: vehicleData, + missionType: MissionType.RegionalDeliveryEMS, + cosswindCorrection: "RigidTrailer", + axleWeightDistribution: new[] { 0.15, 0.15, 0.1 }, + trailerAxleWeightDistribution: new[] { 0.35, 0.25 }, + trailerAxleCount: new[] { 3, 2 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0, 5400 }, + trailerType: new[] { TrailerType.ST1, TrailerType.T2 }, + lowLoad: 3500, + refLoad: 17500, + trailerGrossVehicleWeight: new[] { 24000.0, 18000 }, + deltaCdA: 1.5, + maxLoad: 39600, + ems: true); + + AssertMission(segment.Missions[4], + vehicleData: vehicleData, + missionType: MissionType.Construction, + cosswindCorrection: "TractorSemitrailer", + axleWeightDistribution: new[] { 0.2, 0.15, 0.15 }, + trailerAxleWeightDistribution: new[] { 0.5 }, + trailerAxleCount: new[] { 3 }, + bodyCurbWeight: 0, + trailerCurbWeight: new[] { 7500.0 }, + trailerType: new[] { TrailerType.ST1 }, + lowLoad: 2600, + refLoad: 12900, + trailerGrossVehicleWeight: new[] { 24000.0 }, + deltaCdA: 0, + maxLoad: 25000, + ems: false); + } + + /// <summary> + /// Segment 9: fixed reference weight, trailer always used + /// </summary> + [TestCase] + public void Segment16Test() + { + var vehicleData = new { + VehicleCategory = VehicleCategory.RigidTruck, + AxleConfiguration = AxleConfiguration.AxleConfig_8x4, + GrossVehicleMassRating = 36000.SI<Kilogram>(), + CurbWeight = 7500.SI<Kilogram>() + }; + + var segment = DeclarationData.Segments.Lookup(vehicleData.VehicleCategory, vehicleData.AxleConfiguration, + vehicleData.GrossVehicleMassRating, vehicleData.CurbWeight); + + Assert.AreEqual(VehicleClass.Class16, segment.VehicleClass); + + var data = AccelerationCurveReader.ReadFromStream(segment.AccelerationFile); + TestAcceleration(data); + + Assert.AreEqual(1, segment.Missions.Length); + + AssertMission(segment.Missions[0], + vehicleData: vehicleData, + missionType: MissionType.Construction, + cosswindCorrection: "RigidSolo", + axleWeightDistribution: new[] { 0.25, 0.25, 0.25, 0.25 }, + trailerAxleWeightDistribution: new double[] { }, + trailerAxleCount: new int[] { }, + bodyCurbWeight: 0, + trailerCurbWeight: new double[] { }, + trailerType: new TrailerType[] { }, + lowLoad: 2600, + refLoad: 12900, + trailerGrossVehicleWeight: new double[] { }, + deltaCdA: 0, + maxLoad: 28500); + } + + public static void AssertMission(Mission m, dynamic vehicleData, MissionType missionType, string cosswindCorrection, + double[] axleWeightDistribution, double[] trailerAxleWeightDistribution, int[] trailerAxleCount, + double bodyCurbWeight, double[] trailerCurbWeight, TrailerType[] trailerType, double lowLoad, double refLoad, + double maxLoad, double[] trailerGrossVehicleWeight, double deltaCdA, bool ems = false) + { + Assert.AreEqual(missionType, m.MissionType); + Assert.AreEqual(cosswindCorrection, m.CrossWindCorrectionParameters); + CollectionAssert.AreEqual(axleWeightDistribution, m.AxleWeightDistribution, + "Axle distribution not equal.\nexpected: {0}\nactual: {1}", string.Join(",", axleWeightDistribution), + string.Join(",", m.AxleWeightDistribution)); + CollectionAssert.AreEqual(trailerAxleWeightDistribution, m.Trailer.Select(t => t.TrailerAxleWeightShare), + "Trailer axle distribution not equal.\nexpected: {0}\nactual: {1}", string.Join(",", trailerAxleWeightDistribution), + string.Join(",", m.Trailer.Select(t => t.TrailerAxleWeightShare))); + Assert.AreEqual(bodyCurbWeight.SI<Kilogram>(), m.BodyCurbWeight); + CollectionAssert.AreEqual(trailerCurbWeight, m.Trailer.Select(t => t.TrailerCurbWeight.Value())); + CollectionAssert.AreEqual(trailerType, m.Trailer.Select(t => t.TrailerType)); + CollectionAssert.AreEqual(trailerAxleCount, m.Trailer.Select(t => t.TrailerWheels.Count)); + Assert.IsNotNull(m.CycleFile); + Assert.IsTrue(!string.IsNullOrEmpty(new StreamReader(m.CycleFile).ReadLine())); + Assert.AreEqual(0.SI<Kilogram>(), m.MinLoad); + AssertHelper.AreRelativeEqual(lowLoad, m.LowLoad); + AssertHelper.AreRelativeEqual(refLoad, m.RefLoad); + Assert.AreEqual(maxLoad.SI<Kilogram>(), m.MaxLoad); + CollectionAssert.AreEqual(trailerGrossVehicleWeight, m.Trailer.Select(t => t.TrailerGrossVehicleWeight.Value())); + Assert.AreEqual( + VectoMath.Min( + vehicleData.GrossVehicleMassRating + + m.Trailer.Sum(t => t.TrailerGrossVehicleWeight).DefaultIfNull(0), + ems ? 60000.SI<Kilogram>() : 40000.SI<Kilogram>()) + - m.BodyCurbWeight - m.Trailer.Sum(t => t.TrailerCurbWeight).DefaultIfNull(0) - + vehicleData.CurbWeight, + m.MaxLoad); + Assert.AreEqual(deltaCdA.SI<SquareMeter>(), + m.Trailer.Sum(t => t.DeltaCdA).DefaultIfNull(0)); + } + + private static void EqualAcceleration(AccelerationCurveData data, double velocity, double acceleration, + double deceleration) + { + var entry = data.Lookup(velocity.KMPHtoMeterPerSecond()); + Assert.AreEqual(entry.Acceleration.Value(), acceleration, Tolerance); + Assert.AreEqual(entry.Deceleration.Value(), deceleration, Tolerance); + } + + private static void TestAcceleration(AccelerationCurveData data) + { + // FIXED POINTS + EqualAcceleration(data, 0, 1, -1); + EqualAcceleration(data, 25, 1, -1); + EqualAcceleration(data, 50, 0.642857143, -1); + EqualAcceleration(data, 60, 0.5, -0.5); + EqualAcceleration(data, 120, 0.5, -0.5); + + // INTERPOLATED POINTS + EqualAcceleration(data, 20, 1, -1); + EqualAcceleration(data, 40, 0.785714286, -1); + EqualAcceleration(data, 55, 0.571428572, -0.75); + EqualAcceleration(data, 80, 0.5, -0.5); + EqualAcceleration(data, 100, 0.5, -0.5); + + // EXTRAPOLATE + EqualAcceleration(data, -20, 1, -1); + EqualAcceleration(data, 140, 0.5, -0.5); + } + + [TestCase] + public void Declaration_WheelsForT1_Class2() + { + var dataProvider = + JSONInputDataFactory.ReadJsonJob(@"TestData\Jobs\12t Delivery Truck.vecto") as IDeclarationInputDataProvider; + var dataReader = new DeclarationModeVectoRunDataFactory(dataProvider, null); + + var runs = dataReader.NextRun().ToList(); + Assert.AreEqual(6, runs.Count); + var withT1 = new[] { 6.0, 6.0, 4.5, 4.5 }; + + CollectionAssert.AreEqual(withT1, runs[0].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(withT1, runs[1].VehicleData.AxleData.Select(a => a.Inertia.Value())); + + var bodyOnly = new[] { 6.0, 6.0 }; + + CollectionAssert.AreEqual(bodyOnly, runs[2].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(bodyOnly, runs[3].VehicleData.AxleData.Select(a => a.Inertia.Value())); + + CollectionAssert.AreEqual(bodyOnly, runs[4].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(bodyOnly, runs[5].VehicleData.AxleData.Select(a => a.Inertia.Value())); + } + + [TestCase] + public void Declaration_WheelsForT2_Class4() + { + var dataProvider = + JSONInputDataFactory.ReadJsonJob( + @"TestData\Jobs\Class4_40t_Long_Haul_Truck.vecto") as IDeclarationInputDataProvider; + var dataReader = new DeclarationModeVectoRunDataFactory(dataProvider, null); + + var runs = dataReader.NextRun().ToList(); + Assert.AreEqual(6, runs.Count); + var withT1 = new[] { 14.9, 14.9, 19.2, 19.2 }; + CollectionAssert.AreEqual(withT1, runs[0].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(withT1, runs[1].VehicleData.AxleData.Select(a => a.Inertia.Value())); + + var bodyOnly = new[] { 14.9, 14.9 }; + CollectionAssert.AreEqual(bodyOnly, runs[2].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(bodyOnly, runs[3].VehicleData.AxleData.Select(a => a.Inertia.Value())); + + CollectionAssert.AreEqual(bodyOnly, runs[4].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(bodyOnly, runs[5].VehicleData.AxleData.Select(a => a.Inertia.Value())); + } + + [TestCase] + public void Declaration_WheelsForDefault_Class5() + { + var dataProvider = + JSONInputDataFactory.ReadJsonJob(@"TestData\Jobs\40t_Long_Haul_Truck.vecto") as IDeclarationInputDataProvider; + var dataReader = new DeclarationModeVectoRunDataFactory(dataProvider, null); + + var runs = dataReader.NextRun().ToList(); + + Assert.AreEqual(VehicleClass.Class5, runs[0].VehicleData.VehicleClass); + Assert.AreEqual(8, runs.Count); + + //var bodyOnly = new[] { 14.9, 14.9 }; + var withST1 = new[] { 14.9, 14.9, 19.2, 19.2, 19.2 }; + var withST1andT2 = new[] { 14.9, 14.9, 19.2, 19.2, 19.2, 19.2, 19.2 }; + + CollectionAssert.AreEqual(withST1, runs[0].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(withST1, runs[1].VehicleData.AxleData.Select(a => a.Inertia.Value())); + + CollectionAssert.AreEqual(withST1andT2, runs[2].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(withST1andT2, runs[3].VehicleData.AxleData.Select(a => a.Inertia.Value())); + + CollectionAssert.AreEqual(withST1, runs[4].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(withST1, runs[5].VehicleData.AxleData.Select(a => a.Inertia.Value())); + + CollectionAssert.AreEqual(withST1andT2, runs[6].VehicleData.AxleData.Select(a => a.Inertia.Value())); + CollectionAssert.AreEqual(withST1andT2, runs[7].VehicleData.AxleData.Select(a => a.Inertia.Value())); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs b/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs index 2467116af3c24bf893d8cb08daadc902671ddac9..b2d433c1ccd20dc90c3892fda5ff95220b93c23e 100644 --- a/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs +++ b/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs @@ -29,177 +29,177 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.IO; -using System.Text; -using System.Data; -using System.Linq; -using System.Collections.Generic; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Tests.Utils; -using TUGraz.VectoCore.InputData.Reader; -using TUGraz.VectoCore.OutputData.FileIO; -using TUGraz.VectoCore.InputData.FileIO.JSON; -using TUGraz.VectoCore.Models.Simulation.Impl; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; -using TUGraz.VectoCore.Models.SimulationComponent.Impl; - -namespace TUGraz.VectoCore.Tests.Models.Simulation -{ - [TestClass] - public class PwheelModeTests - { - /// <summary> - /// Test if the cycle file can be read. - /// </summary> - /// <remarks>VECTO-177</remarks> - [TestMethod] - public void Pwheel_ReadCycle_Test() - { - var container = new VehicleContainer(ExecutionMode.Engineering); - var inputData = @"<t>,<Pwheel>,<gear>,<n>,<Padd> - 1,89,2,1748,1.300 - 2,120,2,1400,0.4"; - - var cycleFile = new MemoryStream(Encoding.UTF8.GetBytes(inputData)); - var drivingCycle = DrivingCycleDataReader.ReadFromStream(cycleFile, CycleType.PWheel, "", false); - - var gearbox = new CycleGearbox(container, new VectoRunData() { - GearboxData = new GearboxData { - Gears = new Dictionary<uint, GearData> { { 1, new GearData { Ratio = 2.0 } }, { 2, new GearData { Ratio = 3.5 } } } - } - }); - - var cycle = new PWheelCycle(container, drivingCycle, 2.3, null, - gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio)); - - Assert.AreEqual(container.CycleData.LeftSample.Time, 1.SI<Second>()); - Assert.AreEqual(container.CycleData.RightSample.Time, 2.SI<Second>()); - - Assert.AreEqual(1748.RPMtoRad() / (2.3 * 3.5), container.CycleData.LeftSample.WheelAngularVelocity); - Assert.AreEqual(1400.RPMtoRad() / (2.3 * 3.5), container.CycleData.RightSample.WheelAngularVelocity); - - Assert.AreEqual(89.SI().Kilo.Watt, container.CycleData.LeftSample.PWheel); - Assert.AreEqual(120.SI().Kilo.Watt, container.CycleData.RightSample.PWheel); - - Assert.AreEqual(2u, container.CycleData.LeftSample.Gear); - Assert.AreEqual(2u, container.CycleData.RightSample.Gear); - - Assert.AreEqual(1300.SI<Watt>(), container.CycleData.LeftSample.AdditionalAuxPowerDemand); - Assert.AreEqual(400.SI<Watt>(), container.CycleData.RightSample.AdditionalAuxPowerDemand); - - Assert.AreEqual(89.SI().Kilo.Watt / (1748.RPMtoRad() / (2.3 * 3.5)), container.CycleData.LeftSample.Torque); - Assert.AreEqual(120.SI().Kilo.Watt / (1400.RPMtoRad() / (2.3 * 3.5)), container.CycleData.RightSample.Torque); - } - - /// <summary> - /// Tests if the powertrain can be created in P_wheel_in mode. - /// </summary> - /// <remarks>VECTO-177</remarks> - [TestMethod] - public void Pwheel_CreatePowertrain_Test() - { - // prepare input data - var inputData = @"<t>,<Pwheel>,<gear>,<n>, <Padd> - 1, 89, 2, 1748, 1.3 - 2, 120, 2, 1400, 0.4"; - - var cycleFile = new MemoryStream(Encoding.UTF8.GetBytes(inputData)); - var drivingCycle = DrivingCycleDataReader.ReadFromStream(cycleFile, CycleType.PWheel, "", false); - - var fuelConsumption = new DataTable(); - fuelConsumption.Columns.Add(""); - fuelConsumption.Columns.Add(""); - fuelConsumption.Columns.Add(""); - fuelConsumption.Rows.Add("1", "1", "1"); - fuelConsumption.Rows.Add("2", "2", "2"); - fuelConsumption.Rows.Add("3", "3", "3"); - - var fullLoad = new DataTable(); - fullLoad.Columns.Add("Engine speed"); - fullLoad.Columns.Add("max torque"); - fullLoad.Columns.Add("drag torque"); - fullLoad.Columns.Add("PT1"); - fullLoad.Rows.Add("0", "5000", "-5000", "0"); - fullLoad.Rows.Add("3000", "5000", "-5000", "0"); - - var fullLoadCurve = FullLoadCurveReader.Create(fullLoad); - var data = new VectoRunData { - Cycle = drivingCycle, - AxleGearData = new AxleGearData { AxleGear = new GearData { Ratio = 2.3 } }, - EngineData = - new CombustionEngineData { - IdleSpeed = 560.RPMtoRad(), - FullLoadCurves = new Dictionary<uint, EngineFullLoadCurve>() { { 0, fullLoadCurve }, { 1, fullLoadCurve } } - }, - GearboxData = new GearboxData { Gears = new Dictionary<uint, GearData> { { 2, new GearData { Ratio = 3.5 } } } }, - Retarder = new RetarderData() - }; - - // call builder (actual test) - var builder = new PowertrainBuilder(new MockModalDataContainer()); - var jobContainer = builder.Build(data); - } - - /// <summary> - /// Tests if the simulation works and the modfile and sumfile are correct in P_wheel_in mode. - /// </summary> - /// <remarks>VECTO-177</remarks> - [TestMethod] - public void Pwheel_Run_Test() - { - var jobFile = @"TestData\Pwheel\Pwheel.vecto"; - var fileWriter = new FileOutputWriter(jobFile); - var sumWriter = new SummaryDataContainer(fileWriter); - var jobContainer = new JobContainer(sumWriter); - - var inputData = JSONInputDataFactory.ReadJsonJob(jobFile); - var runsFactory = new SimulatorFactory(ExecutionMode.Engineering, inputData, fileWriter); - - jobContainer.AddRuns(runsFactory); - jobContainer.Execute(); - - jobContainer.WaitFinished(); - - Assert.IsTrue(jobContainer.Runs.All(r => r.Success), string.Concat(jobContainer.Runs.Select(r => r.ExecException))); - - ResultFileHelper.TestSumFile(@"TestData\Pwheel\Results\Pwheel.vsum", @"TestData\Pwheel\Pwheel.vsum"); - - ResultFileHelper.TestModFile(@"TestData\Pwheel\Results\Pwheel_Gear2_pt1_rep1_actual.vmod", - @"TestData\Pwheel\Pwheel_Gear2_pt1_rep1_actual.vmod"); - } - - /// <summary> - /// Tests if the simulation works and the modfile and sumfile are correct in P_wheel_in mode. - /// </summary> - /// <remarks>VECTO-177</remarks> - [TestMethod] - public void Pwheel_ultimate_Run_Test() - { - var jobFile = @"TestData\Pwheel\Pwheel_ultimate.vecto"; - var fileWriter = new FileOutputWriter(jobFile); - var sumWriter = new SummaryDataContainer(fileWriter); - var jobContainer = new JobContainer(sumWriter); - - var inputData = JSONInputDataFactory.ReadJsonJob(jobFile); - var runsFactory = new SimulatorFactory(ExecutionMode.Engineering, inputData, fileWriter); - - jobContainer.AddRuns(runsFactory); - jobContainer.Execute(); - - jobContainer.WaitFinished(); - - Assert.IsTrue(jobContainer.Runs.All(r => r.Success), string.Concat(jobContainer.Runs.Select(r => r.ExecException))); - - ResultFileHelper.TestSumFile(@"TestData\Pwheel\Results\Pwheel_ultimate.vsum", @"TestData\Pwheel\Pwheel_ultimate.vsum"); - - ResultFileHelper.TestModFile(@"TestData\Pwheel\Results\Pwheel_ultimate_RD_#1_Pwheel_AuxStd.vmod", - @"TestData\Pwheel\Pwheel_ultimate_RD_#1_Pwheel_AuxStd.vmod"); - } - } +using System.IO; +using System.Text; +using System.Data; +using System.Linq; +using System.Collections.Generic; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Tests.Utils; +using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.OutputData.FileIO; +using TUGraz.VectoCore.InputData.FileIO.JSON; +using TUGraz.VectoCore.Models.Simulation.Impl; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; + +namespace TUGraz.VectoCore.Tests.Models.Simulation +{ + [TestClass] + public class PwheelModeTests + { + /// <summary> + /// Test if the cycle file can be read. + /// </summary> + /// <remarks>VECTO-177</remarks> + [TestMethod] + public void Pwheel_ReadCycle_Test() + { + var container = new VehicleContainer(ExecutionMode.Engineering); + var inputData = @"<t>,<Pwheel>,<gear>,<n>,<Padd> + 1,89,2,1748,1.300 + 2,120,2,1400,0.4"; + + var cycleFile = new MemoryStream(Encoding.UTF8.GetBytes(inputData)); + var drivingCycle = DrivingCycleDataReader.ReadFromStream(cycleFile, CycleType.PWheel, "", false); + + var gearbox = new CycleGearbox(container, new VectoRunData() { + GearboxData = new GearboxData { + Gears = new Dictionary<uint, GearData> { { 1, new GearData { Ratio = 2.0 } }, { 2, new GearData { Ratio = 3.5 } } } + } + }); + + var cycle = new PWheelCycle(container, drivingCycle, 2.3, null, + gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio)); + + Assert.AreEqual(container.CycleData.LeftSample.Time, 1.SI<Second>()); + Assert.AreEqual(container.CycleData.RightSample.Time, 2.SI<Second>()); + + Assert.AreEqual(1748.RPMtoRad() / (2.3 * 3.5), container.CycleData.LeftSample.WheelAngularVelocity); + Assert.AreEqual(1400.RPMtoRad() / (2.3 * 3.5), container.CycleData.RightSample.WheelAngularVelocity); + + Assert.AreEqual(89.SI().Kilo.Watt, container.CycleData.LeftSample.PWheel); + Assert.AreEqual(120.SI().Kilo.Watt, container.CycleData.RightSample.PWheel); + + Assert.AreEqual(2u, container.CycleData.LeftSample.Gear); + Assert.AreEqual(2u, container.CycleData.RightSample.Gear); + + Assert.AreEqual(1300.SI<Watt>(), container.CycleData.LeftSample.AdditionalAuxPowerDemand); + Assert.AreEqual(400.SI<Watt>(), container.CycleData.RightSample.AdditionalAuxPowerDemand); + + Assert.AreEqual(89.SI().Kilo.Watt / (1748.RPMtoRad() / (2.3 * 3.5)), container.CycleData.LeftSample.Torque); + Assert.AreEqual(120.SI().Kilo.Watt / (1400.RPMtoRad() / (2.3 * 3.5)), container.CycleData.RightSample.Torque); + } + + /// <summary> + /// Tests if the powertrain can be created in P_wheel_in mode. + /// </summary> + /// <remarks>VECTO-177</remarks> + [TestMethod] + public void Pwheel_CreatePowertrain_Test() + { + // prepare input data + var inputData = @"<t>,<Pwheel>,<gear>,<n>, <Padd> + 1, 89, 2, 1748, 1.3 + 2, 120, 2, 1400, 0.4"; + + var cycleFile = new MemoryStream(Encoding.UTF8.GetBytes(inputData)); + var drivingCycle = DrivingCycleDataReader.ReadFromStream(cycleFile, CycleType.PWheel, "", false); + + var fuelConsumption = new DataTable(); + fuelConsumption.Columns.Add(""); + fuelConsumption.Columns.Add(""); + fuelConsumption.Columns.Add(""); + fuelConsumption.Rows.Add("1", "1", "1"); + fuelConsumption.Rows.Add("2", "2", "2"); + fuelConsumption.Rows.Add("3", "3", "3"); + + var fullLoad = new DataTable(); + fullLoad.Columns.Add("Engine speed"); + fullLoad.Columns.Add("max torque"); + fullLoad.Columns.Add("drag torque"); + fullLoad.Columns.Add("PT1"); + fullLoad.Rows.Add("0", "5000", "-5000", "0"); + fullLoad.Rows.Add("3000", "5000", "-5000", "0"); + + var fullLoadCurve = FullLoadCurveReader.Create(fullLoad); + var data = new VectoRunData { + Cycle = drivingCycle, + AxleGearData = new AxleGearData { AxleGear = new GearData { Ratio = 2.3 } }, + EngineData = + new CombustionEngineData { + IdleSpeed = 560.RPMtoRad(), + FullLoadCurves = new Dictionary<uint, EngineFullLoadCurve>() { { 0, fullLoadCurve }, { 1, fullLoadCurve } } + }, + GearboxData = new GearboxData { Gears = new Dictionary<uint, GearData> { { 2, new GearData { Ratio = 3.5 } } } }, + Retarder = new RetarderData() + }; + + // call builder (actual test) + var builder = new PowertrainBuilder(new MockModalDataContainer()); + var jobContainer = builder.Build(data); + } + + /// <summary> + /// Tests if the simulation works and the modfile and sumfile are correct in P_wheel_in mode. + /// </summary> + /// <remarks>VECTO-177</remarks> + [TestMethod] + public void Pwheel_Run_Test() + { + var jobFile = @"TestData\Pwheel\Pwheel.vecto"; + var fileWriter = new FileOutputWriter(jobFile); + var sumWriter = new SummaryDataContainer(fileWriter); + var jobContainer = new JobContainer(sumWriter); + + var inputData = JSONInputDataFactory.ReadJsonJob(jobFile); + var runsFactory = new SimulatorFactory(ExecutionMode.Engineering, inputData, fileWriter); + + jobContainer.AddRuns(runsFactory); + jobContainer.Execute(); + + jobContainer.WaitFinished(); + + Assert.IsTrue(jobContainer.Runs.All(r => r.Success), string.Concat(jobContainer.Runs.Select(r => r.ExecException))); + + ResultFileHelper.TestSumFile(@"TestData\Pwheel\Results\Pwheel.vsum", @"TestData\Pwheel\Pwheel.vsum"); + + ResultFileHelper.TestModFile(@"TestData\Pwheel\Results\Pwheel_Gear2_pt1_rep1_actual.vmod", + @"TestData\Pwheel\Pwheel_Gear2_pt1_rep1_actual.vmod"); + } + + /// <summary> + /// Tests if the simulation works and the modfile and sumfile are correct in P_wheel_in mode. + /// </summary> + /// <remarks>VECTO-177</remarks> + [TestMethod] + public void Pwheel_ultimate_Run_Test() + { + var jobFile = @"TestData\Pwheel\Pwheel_ultimate.vecto"; + var fileWriter = new FileOutputWriter(jobFile); + var sumWriter = new SummaryDataContainer(fileWriter); + var jobContainer = new JobContainer(sumWriter); + + var inputData = JSONInputDataFactory.ReadJsonJob(jobFile); + var runsFactory = new SimulatorFactory(ExecutionMode.Engineering, inputData, fileWriter); + + jobContainer.AddRuns(runsFactory); + jobContainer.Execute(); + + jobContainer.WaitFinished(); + + Assert.IsTrue(jobContainer.Runs.All(r => r.Success), string.Concat(jobContainer.Runs.Select(r => r.ExecException))); + + ResultFileHelper.TestSumFile(@"TestData\Pwheel\Results\Pwheel_ultimate.vsum", @"TestData\Pwheel\Pwheel_ultimate.vsum"); + + ResultFileHelper.TestModFile(@"TestData\Pwheel\Results\Pwheel_ultimate_RD_#1_Pwheel_AuxStd.vmod", + @"TestData\Pwheel\Pwheel_ultimate_RD_#1_Pwheel_AuxStd.vmod"); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponent/ATGearboxTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponent/ATGearboxTest.cs index f0c12bd791d2c05813804a0ec23572c6f94fed24..a93409ff24f34a6922b33b23fa94139e533f9b6a 100644 --- a/VectoCore/VectoCoreTest/Models/SimulationComponent/ATGearboxTest.cs +++ b/VectoCore/VectoCoreTest/Models/SimulationComponent/ATGearboxTest.cs @@ -29,140 +29,140 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using NUnit.Framework; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Models.Connector.Ports.Impl; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.Impl; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Impl; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.OutputData.FileIO; -using TUGraz.VectoCore.Tests.Integration; -using TUGraz.VectoCore.Tests.Utils; - -namespace TUGraz.VectoCore.Tests.Models.SimulationComponent -{ - [TestFixture] - public class ATGearboxTest - { - public const string EngineDataFile = @"TestData\Components\AT_GBX\Engine.veng"; - public const string GearboxDataFile = @"TestData\Components\AT_GBX\GearboxSerial.vgbx"; - - [Test, - TestCase(0, 100, 1), - TestCase(0, 200, 1), - TestCase(5, 100, 1), - TestCase(5, 300, 1), - TestCase(5, 600, 1), - TestCase(15, 100, 3), - TestCase(15, 300, 3), - TestCase(15, 600, 3), - TestCase(40, 100, 6), - TestCase(40, 300, 6), - TestCase(40, 600, 6), - TestCase(70, 100, 6), - TestCase(70, 300, 6), - TestCase(70, 600, 6), - ] - public void TestATGearInitialize(double vehicleSpeed, double torque, int expectedGear) - { - var gearboxData = MockSimulationDataFactory.CreateGearboxDataFromFile(GearboxDataFile, EngineDataFile, false); - var vehicleContainer = new MockVehicleContainer(); //(ExecutionMode.Engineering); - var engineData = MockSimulationDataFactory.CreateEngineDataFromFile(EngineDataFile, gearboxData.Gears.Count); - vehicleContainer.Engine = new CombustionEngine(vehicleContainer, engineData); - var runData = new VectoRunData() { GearboxData = gearboxData }; - var gearbox = new ATGearbox(vehicleContainer, new ATShiftStrategy(gearboxData, vehicleContainer), runData); - - vehicleContainer.VehicleSpeed = vehicleSpeed.KMPHtoMeterPerSecond(); - - var tnPort = new MockTnOutPort(); - gearbox.Connect(tnPort); - - // r_dyn = 0.465m, i_axle = 6.2 - var angularVelocity = vehicleSpeed.KMPHtoMeterPerSecond() / 0.465.SI<Meter>() * 6.2; - var response = gearbox.Initialize(torque.SI<NewtonMeter>(), angularVelocity); - - Assert.IsInstanceOf(typeof(ResponseSuccess), response); - Assert.AreEqual(expectedGear, gearbox.Gear); - Assert.AreEqual(vehicleSpeed.IsEqual(0), gearbox.Disengaged); - } - - [Test, - TestCase(GearboxType.ATSerial, TestName = "Drive TorqueConverter - Serial"), - TestCase(GearboxType.ATPowerSplit, TestName = "Drive TorqueConverter - PowerSplit")] - public void TestATGearboxDriveTorqueConverter(GearboxType gbxType) - { - var cycleData = @" 0, 0, 0, 2 - 20, 8, 0, 0 - 200, 0, 0, 2"; - var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); - var run = ATPowerTrain.CreateEngineeringRun(cycle, gbxType, - string.Format("AT_Vehicle_Drive-TC-{0}.vmod", gbxType == GearboxType.ATSerial ? "ser" : "ps")); - - run.Run(); - Assert.IsTrue(run.FinishedWithoutErrors); - } - - [Test, - TestCase(GearboxType.ATSerial, TestName = "ShiftUp TorqueConverter - Serial"), - TestCase(GearboxType.ATPowerSplit, TestName = "ShiftUp TorqueConverter - PowerSplit")] - public void TestATGearboxShiftUp(GearboxType gbxType) - { - var cycleData = @" 0, 0, 0, 2 - 500, 40, 0, 0"; - var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); - var run = ATPowerTrain.CreateEngineeringRun(cycle, gbxType, - string.Format("AT_Vehicle_Drive-TC_shiftup-{0}.vmod", gbxType == GearboxType.ATSerial ? "ser" : "ps")); - - run.Run(); - Assert.IsTrue(run.FinishedWithoutErrors); - } - - [Test, - TestCase(GearboxType.ATSerial, TestName = "ShiftDown TorqueConverter - Serial"), - TestCase(GearboxType.ATPowerSplit, TestName = "ShiftDown TorqueConverter - PowerSplit")] - public void TestATGearboxShiftDown(GearboxType gbxType) - { - var cycleData = @" 0, 70, 0, 0 - 500, 0, 0, 2"; - var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); - var run = ATPowerTrain.CreateEngineeringRun(cycle, gbxType, - string.Format("AT_Vehicle_Drive-TC_shiftdown-{0}.vmod", gbxType == GearboxType.ATSerial ? "ser" : "ps")); - - run.Run(); - Assert.IsTrue(run.FinishedWithoutErrors); - } - - - [Test, - TestCase("Urban", GearboxType.ATSerial), - TestCase("Suburban", GearboxType.ATSerial), - TestCase("Interurban", GearboxType.ATSerial), - TestCase("HeavyUrban", GearboxType.ATSerial), - TestCase("Urban", GearboxType.ATPowerSplit), - TestCase("Suburban", GearboxType.ATPowerSplit), - TestCase("Interurban", GearboxType.ATPowerSplit), - TestCase("HeavyUrban", GearboxType.ATPowerSplit) - ] - public void TestATGearboxDriveCycle(string cycleName, GearboxType gbxType) - { - Assert.IsTrue(gbxType.AutomaticTransmission()); - var cycle = SimpleDrivingCycles.ReadDeclarationCycle(cycleName); - var run = ATPowerTrain.CreateEngineeringRun(cycle, gbxType, - string.Format("AT_Vehicle_Drive-TC_{0}-{1}.vmod", cycleName, gbxType == GearboxType.ATSerial ? "ser" : "ps")); - - var sumWriter = - new SummaryDataContainer( - new FileOutputWriter(string.Format("AT_Vehicle_Drive-TC_{0}-{1}", cycleName, - gbxType == GearboxType.ATSerial ? "ser" : "ps"))); - ((VehicleContainer)run.GetContainer()).WriteSumData = (modData) => - sumWriter.Write(run.GetContainer().ModalData, 0, 0, run.GetContainer().RunData); - run.Run(); - sumWriter.Finish(); - Assert.IsTrue(run.FinishedWithoutErrors); - } - } +using NUnit.Framework; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.OutputData.FileIO; +using TUGraz.VectoCore.Tests.Integration; +using TUGraz.VectoCore.Tests.Utils; + +namespace TUGraz.VectoCore.Tests.Models.SimulationComponent +{ + [TestFixture] + public class ATGearboxTest + { + public const string EngineDataFile = @"TestData\Components\AT_GBX\Engine.veng"; + public const string GearboxDataFile = @"TestData\Components\AT_GBX\GearboxSerial.vgbx"; + + [Test, + TestCase(0, 100, 1), + TestCase(0, 200, 1), + TestCase(5, 100, 1), + TestCase(5, 300, 1), + TestCase(5, 600, 1), + TestCase(15, 100, 3), + TestCase(15, 300, 3), + TestCase(15, 600, 3), + TestCase(40, 100, 6), + TestCase(40, 300, 6), + TestCase(40, 600, 6), + TestCase(70, 100, 6), + TestCase(70, 300, 6), + TestCase(70, 600, 6), + ] + public void TestATGearInitialize(double vehicleSpeed, double torque, int expectedGear) + { + var gearboxData = MockSimulationDataFactory.CreateGearboxDataFromFile(GearboxDataFile, EngineDataFile, false); + var vehicleContainer = new MockVehicleContainer(); //(ExecutionMode.Engineering); + var engineData = MockSimulationDataFactory.CreateEngineDataFromFile(EngineDataFile, gearboxData.Gears.Count); + vehicleContainer.Engine = new CombustionEngine(vehicleContainer, engineData); + var runData = new VectoRunData() { GearboxData = gearboxData }; + var gearbox = new ATGearbox(vehicleContainer, new ATShiftStrategy(gearboxData, vehicleContainer), runData); + + vehicleContainer.VehicleSpeed = vehicleSpeed.KMPHtoMeterPerSecond(); + + var tnPort = new MockTnOutPort(); + gearbox.Connect(tnPort); + + // r_dyn = 0.465m, i_axle = 6.2 + var angularVelocity = vehicleSpeed.KMPHtoMeterPerSecond() / 0.465.SI<Meter>() * 6.2; + var response = gearbox.Initialize(torque.SI<NewtonMeter>(), angularVelocity); + + Assert.IsInstanceOf(typeof(ResponseSuccess), response); + Assert.AreEqual(expectedGear, gearbox.Gear); + Assert.AreEqual(vehicleSpeed.IsEqual(0), gearbox.Disengaged); + } + + [Test, + TestCase(GearboxType.ATSerial, TestName = "Drive TorqueConverter - Serial"), + TestCase(GearboxType.ATPowerSplit, TestName = "Drive TorqueConverter - PowerSplit")] + public void TestATGearboxDriveTorqueConverter(GearboxType gbxType) + { + var cycleData = @" 0, 0, 0, 2 + 20, 8, 0, 0 + 200, 0, 0, 2"; + var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); + var run = ATPowerTrain.CreateEngineeringRun(cycle, gbxType, + string.Format("AT_Vehicle_Drive-TC-{0}.vmod", gbxType == GearboxType.ATSerial ? "ser" : "ps")); + + run.Run(); + Assert.IsTrue(run.FinishedWithoutErrors); + } + + [Test, + TestCase(GearboxType.ATSerial, TestName = "ShiftUp TorqueConverter - Serial"), + TestCase(GearboxType.ATPowerSplit, TestName = "ShiftUp TorqueConverter - PowerSplit")] + public void TestATGearboxShiftUp(GearboxType gbxType) + { + var cycleData = @" 0, 0, 0, 2 + 500, 40, 0, 0"; + var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); + var run = ATPowerTrain.CreateEngineeringRun(cycle, gbxType, + string.Format("AT_Vehicle_Drive-TC_shiftup-{0}.vmod", gbxType == GearboxType.ATSerial ? "ser" : "ps")); + + run.Run(); + Assert.IsTrue(run.FinishedWithoutErrors); + } + + [Test, + TestCase(GearboxType.ATSerial, TestName = "ShiftDown TorqueConverter - Serial"), + TestCase(GearboxType.ATPowerSplit, TestName = "ShiftDown TorqueConverter - PowerSplit")] + public void TestATGearboxShiftDown(GearboxType gbxType) + { + var cycleData = @" 0, 70, 0, 0 + 500, 0, 0, 2"; + var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); + var run = ATPowerTrain.CreateEngineeringRun(cycle, gbxType, + string.Format("AT_Vehicle_Drive-TC_shiftdown-{0}.vmod", gbxType == GearboxType.ATSerial ? "ser" : "ps")); + + run.Run(); + Assert.IsTrue(run.FinishedWithoutErrors); + } + + + [Test, + TestCase("Urban", GearboxType.ATSerial), + TestCase("Suburban", GearboxType.ATSerial), + TestCase("Interurban", GearboxType.ATSerial), + TestCase("HeavyUrban", GearboxType.ATSerial), + TestCase("Urban", GearboxType.ATPowerSplit), + TestCase("Suburban", GearboxType.ATPowerSplit), + TestCase("Interurban", GearboxType.ATPowerSplit), + TestCase("HeavyUrban", GearboxType.ATPowerSplit) + ] + public void TestATGearboxDriveCycle(string cycleName, GearboxType gbxType) + { + Assert.IsTrue(gbxType.AutomaticTransmission()); + var cycle = SimpleDrivingCycles.ReadDeclarationCycle(cycleName); + var run = ATPowerTrain.CreateEngineeringRun(cycle, gbxType, + string.Format("AT_Vehicle_Drive-TC_{0}-{1}.vmod", cycleName, gbxType == GearboxType.ATSerial ? "ser" : "ps")); + + var sumWriter = + new SummaryDataContainer( + new FileOutputWriter(string.Format("AT_Vehicle_Drive-TC_{0}-{1}", cycleName, + gbxType == GearboxType.ATSerial ? "ser" : "ps"))); + ((VehicleContainer)run.GetContainer()).WriteSumData = (modData) => + sumWriter.Write(run.GetContainer().ModalData, 0, 0, run.GetContainer().RunData); + run.Run(); + sumWriter.Finish(); + Assert.IsTrue(run.FinishedWithoutErrors); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Reports/ModDataTest.cs b/VectoCore/VectoCoreTest/Reports/ModDataTest.cs index 5ed3af872f8f3e5b03d2f8f18c1ea0d7d75a19d0..660c3311774a1ec69c9a3647edf6765bd8c858cb 100644 --- a/VectoCore/VectoCoreTest/Reports/ModDataTest.cs +++ b/VectoCore/VectoCoreTest/Reports/ModDataTest.cs @@ -29,475 +29,480 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using NUnit.Framework; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.InputData.FileIO.JSON; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.Impl; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; -using TUGraz.VectoCore.Models.SimulationComponent.Impl; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.OutputData.FileIO; -using TUGraz.VectoCore.Tests.Integration; -using TUGraz.VectoCore.Tests.Utils; -using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert; - -namespace TUGraz.VectoCore.Tests.Reports -{ - [TestFixture] - public class ModDataTest - { - [TestCase()] - public void ModDataIntegritySimpleTest() - { - var cycleData = new[] { - // <s>,<v>,<grad>,<stop> - " 0, 20, 0, 0", - " 100, 60, 0, 0", - "1000, 60, 0, 0", - "1500, 40, 1, 0", - "2000, 50,-1, 0", - "2500, 0, 0, 2" - }; - var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); - var sumData = new SummaryDataContainer(null); - var run = Truck40tPowerTrain.CreateEngineeringRun(cycle, "Truck_ModDataIntegrity.vmod"); - - var engineData = MockSimulationDataFactory.CreateEngineDataFromFile(Truck40tPowerTrain.EngineFile, 0); - - // get a reference to the mod-data because the modaldata container clears it after simulation - var modData = ((ModalDataContainer)run.GetContainer().ModalData).Data; - var auxKeys = ((ModalDataContainer)run.GetContainer().ModalData).Auxiliaries; - - run.Run(); - Assert.IsTrue(run.FinishedWithoutErrors); - - AssertModDataIntegrity(modData, auxKeys, cycle.Entries.Last().Distance, engineData.ConsumptionMap); - } - - [TestCase(@"TestData\Integration\DeclarationMode\Class2_RigidTruck_4x2\Class2_RigidTruck_DECL.vecto")] - public void TestFullCycleModDataIntegrityDeclMT(string jobName) - { - RunSimulation(jobName, ExecutionMode.Declaration); - } - - [TestCase(@"TestData\Integration\EngineeringMode\Class2_RigidTruck_4x2\Class2_RigidTruck_ENG.vecto"), - TestCase(@"TestData\Integration\EngineeringMode\Class5_Tractor_4x2\Class5_Tractor_ENG.vecto"), - TestCase(@"TestData\Integration\EngineeringMode\Class9_RigidTruck_6x2_PTO\Class9_RigidTruck_ENG_PTO.vecto"),] - public void TestFullCycleModDataIntegrityMT(string jobName) - { - RunSimulation(jobName, ExecutionMode.Engineering); - } - - private static void RunSimulation(string jobName, ExecutionMode mode) - { - var fileWriter = new FileOutputWriter(jobName); - var sumData = new SummaryDataContainer(fileWriter); - - var jobContainer = new JobContainer(sumData); - var inputData = JSONInputDataFactory.ReadJsonJob(jobName); - - var runsFactory = new SimulatorFactory(mode, inputData, fileWriter) { WriteModalResults = true }; - - jobContainer.AddRuns(runsFactory); - var modData = new List<Tuple<ModalResults, Meter>>(); - foreach (var run in jobContainer.Runs) { - modData.Add(Tuple.Create(((ModalDataContainer)run.Run.GetContainer().ModalData).Data, - ((DistanceBasedDrivingCycle)((VehicleContainer)run.Run.GetContainer()).DrivingCycle).Data.Entries.Last() - .Distance)); - } - var auxKeys = - new Dictionary<string, DataColumn>( - ((ModalDataContainer)jobContainer.Runs.First().Run.GetContainer().ModalData).Auxiliaries); - jobContainer.Execute(); - jobContainer.WaitFinished(); - - // mod files will be stored in e.g. - // VectoCoreTest\bin\Debug\TestData\Integration\EngineeringMode\Class2_RigidTruck_4x2\Class2_RigidTruck_ENG.vecto_00.vmod - //fileWriter.WriteModData(Path.GetFileName(jobName), "0", "0", modData[0].Item1); - //fileWriter.WriteModData(Path.GetFileName(jobName), "1", "1", modData[1].Item1); - - foreach (var modalResults in modData) { - AssertModDataIntegrity(modalResults.Item1, auxKeys, modalResults.Item2, - FuelConsumptionMapReader.Create(((IEngineeringInputDataProvider)inputData).EngineInputData.FuelConsumptionMap)); - } - - AssertSumDataIntegrity(sumData, mode); - } - - private static void AssertSumDataIntegrity(SummaryDataContainer sumData, ExecutionMode mode) - { - Assert.IsTrue(sumData.Table.Rows.Count > 0); - - var ptoTransmissionColumn = - sumData.Table.Columns.Contains(string.Format(SummaryDataContainer.E_FORMAT, - Constants.Auxiliaries.IDs.PTOTransmission)) - ? string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOTransmission) - : null; - var ptoConsumerColumn = - sumData.Table.Columns.Contains(string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOConsumer)) - ? string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOConsumer) - : null; - - foreach (DataRow row in sumData.Table.Rows) { - var inputFile = row[SummaryDataContainer.INPUTFILE].ToString(); - var cycle = row[SummaryDataContainer.CYCLE].ToString(); - var loading = row[SummaryDataContainer.LOADING].ToString(); - var eFcMapPos = ((SI)row[SummaryDataContainer.E_FCMAP_POS]).Value(); - var eFcMapNeg = ((SI)row[SummaryDataContainer.E_FCMAP_NEG]).Value(); - var ePowertrainInertia = ((SI)row[SummaryDataContainer.E_POWERTRAIN_INERTIA]).Value(); - var eAux = ((SI)row[SummaryDataContainer.E_AUX]).Value(); - var eClutchLoss = ((SI)row[SummaryDataContainer.E_CLUTCH_LOSS]).Value(); - var eTcLoss = ((SI)row[SummaryDataContainer.E_TC_LOSS]).Value(); - //var eShiftLoss = ((SI)row[SummaryDataContainer.E_SHIFT_LOSS]).Value(); - var eGbxLoss = ((SI)row[SummaryDataContainer.E_GBX_LOSS]).Value(); - var eRetLoss = ((SI)row[SummaryDataContainer.E_RET_LOSS]).Value(); - var eAngleLoss = ((SI)row[SummaryDataContainer.E_ANGLE_LOSS]).Value(); - var eAxlLoss = ((SI)row[SummaryDataContainer.E_AXL_LOSS]).Value(); - var eBrakeLoss = ((SI)row[SummaryDataContainer.E_BRAKE]).Value(); - var eVehInertia = ((SI)row[SummaryDataContainer.E_VEHICLE_INERTIA]).Value(); - var eAir = ((SI)row[SummaryDataContainer.E_AIR]).Value(); - var eRoll = ((SI)row[SummaryDataContainer.E_ROLL]).Value(); - var eGrad = ((SI)row[SummaryDataContainer.E_GRAD]).Value(); - var cargoVolume = mode == ExecutionMode.Engineering ? 0 : ((SI)row[SummaryDataContainer.CARGO_VOLUME]).Value(); - - var loadingValue = ((SI)row[SummaryDataContainer.LOADING]).Value() / 1000; - var fcPer100km = ((SI)row[SummaryDataContainer.FCFINAL_LITERPER100KM]).Value(); - var fcPerVolume = mode == ExecutionMode.Engineering - ? 0 - : ((SI)row[SummaryDataContainer.FCFINAL_LiterPer100M3KM]).Value(); - var fcPerLoad = loadingValue > 0 ? ((SI)row[SummaryDataContainer.FCFINAL_LITERPER100TKM]).Value() : 0; - var co2Per100km = ((SI)row[SummaryDataContainer.CO2_KM]).Value(); - var co2PerVolume = mode == ExecutionMode.Engineering ? 0 : ((SI)row[SummaryDataContainer.CO2_M3KM]).Value(); - var co2PerLoad = loadingValue > 0 ? ((SI)row[SummaryDataContainer.CO2_TKM]).Value() : 0; - - var ePTOtransm = ptoTransmissionColumn != null ? ((SI)row[ptoTransmissionColumn]).Value() : 0; - var ePTOconsumer = ptoConsumerColumn != null ? ((SI)row[ptoConsumerColumn]).Value() : 0; - - // E_fcmap_pos = E_fcmap_neg + E_powertrain_inertia + E_aux_xxx + E_aux_sum + E_clutch_loss + E_tc_loss + E_gbx_loss + E_shift_loss + E_ret_loss + E_angle_loss + E_axl_loss + E_brake + E_vehicle_inertia + E_air + E_roll + E_grad + E_PTO_CONSUM + E_PTO_TRANSM - Assert.AreEqual(eFcMapPos, - eFcMapNeg + ePowertrainInertia + eAux + eClutchLoss + eTcLoss + eGbxLoss + eRetLoss + eAngleLoss + - eAxlLoss + eBrakeLoss + eVehInertia + eAir + eRoll + eGrad + ePTOconsumer + ePTOtransm, 1e-5, - "input file: {0} cycle: {1} loading: {2}", - inputFile, cycle, loading); - - var pFcmapPos = ((SI)row[SummaryDataContainer.P_FCMAP_POS]).Value(); - var time = ((SI)row[SummaryDataContainer.TIME]).Value(); - - // E_fcmap_pos = P_fcmap_pos * t - Assert.AreEqual(eFcMapPos, pFcmapPos * (time / 3600), 1e-3, "input file: {0} cycle: {1} loading: {2}", inputFile, - cycle, loading); - - if (cargoVolume > 0) { - Assert.AreEqual(fcPerVolume, fcPer100km / cargoVolume, 1e-3, "input file: {0} cycle: {1} loading: {2}", inputFile, - cycle, loading); - - Assert.AreEqual(co2PerVolume, co2Per100km / cargoVolume, 1e-3, "input file: {0} cycle: {1} loading: {2}", - inputFile, - cycle, loading); - } - - if (loadingValue > 0) { - Assert.AreEqual(co2PerLoad, co2Per100km / loadingValue, 1e-3, "input file: {0} cycle: {1} loading: {2}", - inputFile, cycle, loading); - Assert.AreEqual(fcPerLoad, fcPer100km / loadingValue, 1e-3, "input file: {0} cycle: {1} loading: {2}", - inputFile, cycle, loading); - } - - var stopTimeShare = ((SI)row[SummaryDataContainer.STOP_TIMESHARE]).Value(); - var accTimeShare = ((SI)row[SummaryDataContainer.ACC_TIMESHARE]).Value(); - var decTimeShare = ((SI)row[SummaryDataContainer.DEC_TIMESHARE]).Value(); - var cruiseTimeShare = ((SI)row[SummaryDataContainer.CRUISE_TIMESHARE]).Value(); - - Assert.AreEqual(100, stopTimeShare + accTimeShare + decTimeShare + cruiseTimeShare, 1e-3, - "input file: {0} cycle: {1} loading: {2}", inputFile, cycle, loading); - - Assert.IsTrue(((SI)row[SummaryDataContainer.ACC_POS]).Value() > 0); - Assert.IsTrue(((SI)row[SummaryDataContainer.ACC_NEG]).Value() < 0); - } - } - - private static void AssertModDataIntegrity(ModalResults modData, Dictionary<string, DataColumn> auxKeys, - Meter totalDistance, FuelConsumptionMap consumptionMap) - { - Assert.IsTrue(modData.Rows.Count > 0); - - var ptoTransmissionColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOTransmission) - ? auxKeys[Constants.Auxiliaries.IDs.PTOTransmission] - : null; - var ptoConsumerColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOConsumer) - ? auxKeys[Constants.Auxiliaries.IDs.PTOConsumer] - : null; - foreach (DataRow row in modData.Rows) { - if (totalDistance.IsEqual(((Meter)row[(int)ModalResultField.dist]))) { - continue; - } - var gear = (uint)row[(int)ModalResultField.Gear]; - var time = (Second)row[(int)ModalResultField.time]; - - var distance = (Meter)row[(int)ModalResultField.dist]; - var tqEngFcmap = (NewtonMeter)row[(int)ModalResultField.T_eng_fcmap]; - var nEngFcMap = (PerSecond)row[(int)ModalResultField.n_eng_avg]; - - // check fuel consumption interpolation - var fuelConsumption = (SI)row[(int)ModalResultField.FCMap]; - Assert.AreEqual(fuelConsumption.Value(), - consumptionMap.GetFuelConsumption(tqEngFcmap, nEngFcMap).Value.Value(), 1E-3, "time: {0} distance: {1}", - time, distance); - - // check P_eng_FCmap = T_eng_fcmap * n_eng - var pEngFcmap = (SI)row[(int)ModalResultField.P_eng_fcmap]; - Assert.AreEqual(pEngFcmap.Value(), (tqEngFcmap * nEngFcMap).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - var pWheelIn = (Watt)row[(int)ModalResultField.P_wheel_in]; - var pAir = (Watt)row[(int)ModalResultField.P_air]; - var pRoll = (Watt)row[(int)ModalResultField.P_roll]; - var pGrad = (Watt)row[(int)ModalResultField.P_slope]; - var pVehInertia = (Watt)row[(int)ModalResultField.P_veh_inertia]; - var pTrac = (Watt)row[(int)ModalResultField.P_trac]; - - // P_eng_out = P_wheel + P_lossgearbox + P_lossaxle + P_lossretarder + P_agbx + Pa_eng + P_aux - P_brake_loss - var pEngOut = (Watt)row[(int)ModalResultField.P_eng_out]; - var pLossGbx = (Watt)row[(int)ModalResultField.P_gbx_loss]; - var pGbxIn = (Watt)row[(int)ModalResultField.P_gbx_in]; - var pLossAxle = (Watt)row[(int)ModalResultField.P_axle_loss]; - var pLossAngle = row[(int)ModalResultField.P_angle_loss] is DBNull - ? 0.SI<Watt>() - : (Watt)row[(int)ModalResultField.P_angle_loss]; - var pAxleIn = (Watt)row[(int)ModalResultField.P_axle_in]; - var pLossRet = (Watt)row[(int)ModalResultField.P_ret_loss]; - var pRetIn = (Watt)row[(int)ModalResultField.P_retarder_in]; - var pGbxInertia = (Watt)row[(int)ModalResultField.P_gbx_inertia]; - var pShiftLoss = row[(int)ModalResultField.P_gbx_shift_loss] is DBNull - ? 0.SI<Watt>() - : (Watt)row[(int)ModalResultField.P_gbx_shift_loss]; - var pEngInertia = (Watt)row[(int)ModalResultField.P_eng_inertia]; - var pAux = - (Watt)(row[(int)ModalResultField.P_aux] != DBNull.Value ? row[(int)ModalResultField.P_aux] : 0.SI<Watt>()); - var pBrakeLoss = (Watt)row[(int)ModalResultField.P_brake_loss]; - var pBrakeIn = (Watt)row[(int)ModalResultField.P_brake_in]; - - var pWheelInertia = (Watt)row[(int)ModalResultField.P_wheel_inertia]; - var pPTOconsumer = ptoConsumerColumn == null || row[ptoConsumerColumn.ColumnName] is DBNull - ? 0.SI<Watt>() - : (Watt)row[ptoConsumerColumn.ColumnName]; - var pPTOtransm = ptoTransmissionColumn == null || row[ptoTransmissionColumn.ColumnName] is DBNull - ? 0.SI<Watt>() - : (Watt)row[ptoTransmissionColumn.ColumnName]; - // P_trac = P_veh_inertia + P_roll + P_air + P_slope - Assert.AreEqual(pTrac.Value(), (pAir + pRoll + pGrad + pVehInertia).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - // P_wheel_in = P_trac + P_wheel_inertia - Assert.AreEqual(pWheelIn.Value(), (pTrac + pWheelInertia).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pBrakeIn.Value(), (pWheelIn + pBrakeLoss).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pAxleIn.Value(), (pBrakeIn + pLossAxle).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pRetIn.Value(), (pAxleIn + pLossRet).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - var pClutchLoss = (Watt)(row[(int)ModalResultField.P_clutch_loss] != DBNull.Value - ? row[(int)ModalResultField.P_clutch_loss] - : 0.SI<Watt>()); - - var pClutchOut = row[(int)ModalResultField.P_clutch_out]; - if (pClutchOut != DBNull.Value) { - Assert.AreEqual(pGbxIn.Value(), (pClutchOut as Watt).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - Assert.AreEqual(pEngOut.Value(), (pClutchOut as Watt + pClutchLoss).Value(), 1E-3, "time: {0} distance: {1}", - time, distance); - } - - var pTC_Loss = (Watt)(row[(int)ModalResultField.P_TC_loss] != DBNull.Value - ? row[(int)ModalResultField.P_TC_loss] - : 0.SI<Watt>()); - - var pTCOut = row[(int)ModalResultField.P_clutch_out]; - if (pTCOut != DBNull.Value) { - Assert.AreEqual(pGbxIn.Value(), (pTCOut as Watt).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - //Assert.AreEqual(pEngOut.Value(), (pTCOut as Watt + pTC_Loss).Value(), 1E-3, "time: {0} distance: {1}", - // time, distance); - } - - Assert.IsTrue(pLossGbx.IsGreaterOrEqual(pShiftLoss + pGbxInertia), "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pGbxIn.Value(), (pRetIn + pLossGbx + pGbxInertia).Value(), gear != 0 ? 1E-3 : 0.5, - "time: {0} distance: {1}", time, - distance); - - // P_eng_fcmap = P_eng_out + P_AUX + P_eng_inertia ( + P_PTO_Transm + P_PTO_Consumer ) - Assert.AreEqual(pEngFcmap.Value(), (pEngOut + pAux + pEngInertia + pPTOtransm + pPTOconsumer).Value(), 0.5, - "time: {0} distance: {1}", time, distance); - - // P_eng_fcmap = sum(Losses Powertrain) - var pLossTot = pClutchLoss + pTC_Loss + pLossGbx + pLossRet + pGbxInertia + pLossAngle + pLossAxle + pBrakeLoss + - pWheelInertia + pAir + pRoll + pGrad + pVehInertia + pPTOconsumer + pPTOtransm; - var pEngFcmapCalc = (pLossTot + pEngInertia + pAux).Value(); - Assert.AreEqual(pEngFcmap.Value(), pEngFcmapCalc, 0.5, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pEngFcmap.Value(), - (pTrac + pWheelInertia + pBrakeLoss + pLossAxle + pLossRet + pLossGbx + pGbxInertia + pEngInertia + pAux + - pClutchLoss + pTC_Loss + pPTOtransm + pPTOconsumer).Value(), 0.5, "time: {0} distance: {1}", time, distance); - } - } - - [ - TestCase(@"TestData\Integration\EngineeringMode\CityBus_AT\CityBus_AT_Ser.vecto"), - TestCase(@"TestData\Integration\EngineeringMode\CityBus_AT\CityBus_AT_PS.vecto")] - public void TestFullCycleModDataIntegrityAT(string jobName) - { - var fileWriter = new FileOutputWriter(jobName); - var sumData = new SummaryDataContainer(fileWriter); - - var jobContainer = new JobContainer(sumData); - var inputData = JSONInputDataFactory.ReadJsonJob(jobName); - - var runsFactory = - new SimulatorFactory(ExecutionMode.Engineering, inputData, fileWriter) { WriteModalResults = true }; - - jobContainer.AddRuns(runsFactory); - var modData = new List<Tuple<ModalResults, Meter>>(); - foreach (var run in jobContainer.Runs) { - modData.Add(Tuple.Create(((ModalDataContainer)run.Run.GetContainer().ModalData).Data, - ((DistanceBasedDrivingCycle)((VehicleContainer)run.Run.GetContainer()).DrivingCycle).Data.Entries.Last() - .Distance)); - } - var auxKeys = - new Dictionary<string, DataColumn>( - ((ModalDataContainer)jobContainer.Runs.First().Run.GetContainer().ModalData).Auxiliaries); - jobContainer.Execute(); - jobContainer.WaitFinished(); - - foreach (var modalResults in modData) { - AssertModDataIntegrityAT(modalResults.Item1, auxKeys, modalResults.Item2, - FuelConsumptionMapReader.Create(((IEngineeringInputDataProvider)inputData).EngineInputData.FuelConsumptionMap)); - } - - AssertSumDataIntegrity(sumData, ExecutionMode.Engineering); - } - - private static void AssertModDataIntegrityAT(ModalResults modData, Dictionary<string, DataColumn> auxKeys, - Meter totalDistance, FuelConsumptionMap consumptionMap) - { - Assert.IsTrue(modData.Rows.Count > 0); - - var ptoTransmissionColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOTransmission) - ? auxKeys[Constants.Auxiliaries.IDs.PTOTransmission] - : null; - var ptoConsumerColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOConsumer) - ? auxKeys[Constants.Auxiliaries.IDs.PTOConsumer] - : null; - foreach (DataRow row in modData.Rows) { - if (totalDistance.IsEqual(((Meter)row[(int)ModalResultField.dist]))) { - continue; - } - var gear = (uint)row[(int)ModalResultField.Gear]; - var time = (Second)row[(int)ModalResultField.time]; - - var distance = (Meter)row[(int)ModalResultField.dist]; - var tqEngFcmap = (NewtonMeter)row[(int)ModalResultField.T_eng_fcmap]; - var nEngFcMap = (PerSecond)row[(int)ModalResultField.n_eng_avg]; - - // check fuel consumption interpolation - var fuelConsumption = (SI)row[(int)ModalResultField.FCMap]; - Assert.AreEqual(fuelConsumption.Value(), - consumptionMap.GetFuelConsumption(tqEngFcmap, nEngFcMap).Value.Value(), 1E-3, "time: {0} distance: {1}", - time, distance); - - // check P_eng_FCmap = T_eng_fcmap * n_eng - var pEngFcmap = (SI)row[(int)ModalResultField.P_eng_fcmap]; - Assert.AreEqual(pEngFcmap.Value(), (tqEngFcmap * nEngFcMap).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - var pWheelIn = (Watt)row[(int)ModalResultField.P_wheel_in]; - var pAir = (Watt)row[(int)ModalResultField.P_air]; - var pRoll = (Watt)row[(int)ModalResultField.P_roll]; - var pGrad = (Watt)row[(int)ModalResultField.P_slope]; - var pVehInertia = (Watt)row[(int)ModalResultField.P_veh_inertia]; - var pTrac = (Watt)row[(int)ModalResultField.P_trac]; - - // Pe_eng = P_wheel + P_lossgearbox + P_lossaxle + P_lossretarder + P_agbx + Pa_eng + P_aux - P_brake_loss - var pEngOut = (Watt)row[(int)ModalResultField.P_eng_out]; - var pLossGbx = (Watt)row[(int)ModalResultField.P_gbx_loss]; - var pGbxIn = (Watt)row[(int)ModalResultField.P_gbx_in]; - var pLossAxle = (Watt)row[(int)ModalResultField.P_axle_loss]; - var pLossAngle = row[(int)ModalResultField.P_angle_loss] is DBNull - ? 0.SI<Watt>() - : (Watt)row[(int)ModalResultField.P_angle_loss]; - var pAxleIn = (Watt)row[(int)ModalResultField.P_axle_in]; - var pLossRet = (Watt)row[(int)ModalResultField.P_ret_loss]; - var pRetIn = (Watt)row[(int)ModalResultField.P_retarder_in]; - var pGbxInertia = (Watt)row[(int)ModalResultField.P_gbx_inertia]; - var pShiftLoss = row[(int)ModalResultField.P_gbx_shift_loss] is DBNull - ? 0.SI<Watt>() - : (Watt)row[(int)ModalResultField.P_gbx_shift_loss]; - var pEngInertia = (Watt)row[(int)ModalResultField.P_eng_inertia]; - var pAux = - (Watt)(row[(int)ModalResultField.P_aux] != DBNull.Value ? row[(int)ModalResultField.P_aux] : 0.SI<Watt>()); - var pBrakeLoss = (Watt)row[(int)ModalResultField.P_brake_loss]; - var pBrakeIn = (Watt)row[(int)ModalResultField.P_brake_in]; - var pTcLoss = (Watt)row[(int)ModalResultField.P_TC_loss]; - var pTcOut = (Watt)row[(int)ModalResultField.P_TC_out]; - var pWheelInertia = (Watt)row[(int)ModalResultField.P_wheel_inertia]; - var pPTOconsumer = ptoConsumerColumn == null || row[ptoConsumerColumn] is DBNull - ? 0.SI<Watt>() - : (Watt)row[ptoConsumerColumn]; - var pPTOtransm = ptoTransmissionColumn == null || row[ptoTransmissionColumn] is DBNull - ? 0.SI<Watt>() - : (Watt)row[ptoTransmissionColumn]; - // P_trac = P_veh_inertia + P_roll + P_air + P_slope - Assert.AreEqual(pTrac.Value(), (pAir + pRoll + pGrad + pVehInertia).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - // P_wheel_in = P_trac + P_wheel_inertia - Assert.AreEqual(pWheelIn.Value(), (pTrac + pWheelInertia).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pBrakeIn.Value(), (pWheelIn + pBrakeLoss).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pAxleIn.Value(), (pBrakeIn + pLossAxle).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pRetIn.Value(), (pAxleIn + pLossRet).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pGbxIn.Value(), pTcOut.Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pEngOut.Value(), (pTcOut + pTcLoss).Value(), 1E-3, - "time: {0} distance: {1}", time, distance); - - // P_eng_fcmap = P_eng_out + P_AUX + P_eng_inertia ( + P_PTO_Transm + P_PTO_Consumer ) - Assert.AreEqual(pEngFcmap.Value(), (pEngOut + pAux + pEngInertia + pPTOtransm + pPTOconsumer).Value(), 1E-3, - "time: {0} distance: {1}", time, - distance); - - // P_eng_fcmap = sum(Losses Powertrain) - var pLossTot = pTcLoss + pLossGbx + pLossRet + pGbxInertia + pLossAngle + pLossAxle + pBrakeLoss + - pWheelInertia + pAir + pRoll + pGrad + pVehInertia + pPTOconsumer + pPTOtransm; - - Assert.AreEqual(pEngFcmap.Value(), (pLossTot + pEngInertia + pAux).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.IsTrue(pLossGbx.IsGreaterOrEqual(pShiftLoss + pGbxInertia), "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pGbxIn.Value(), (pRetIn + pLossGbx + pGbxInertia).Value(), gear != 0 ? 1E-3 : 0.5, - "time: {0} distance: {1}", time, - distance); - Assert.AreEqual(pEngFcmap.Value(), - (pTrac + pWheelInertia + pBrakeLoss + pLossAxle + pLossRet + pLossGbx + pGbxInertia + pEngInertia + pAux + - pTcLoss + pPTOtransm + pPTOconsumer).Value(), 0.5, "time: {0} distance: {1}", time, distance); - } - } - } +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using NUnit.Framework; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.InputData.FileIO.JSON; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.OutputData.FileIO; +using TUGraz.VectoCore.Tests.Integration; +using TUGraz.VectoCore.Tests.Utils; +using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert; + +namespace TUGraz.VectoCore.Tests.Reports +{ + [TestFixture] + public class ModDataTest + { + [TestCase()] + public void ModDataIntegritySimpleTest() + { + var cycleData = new[] { + // <s>,<v>,<grad>,<stop> + " 0, 20, 0, 0", + " 100, 60, 0, 0", + "1000, 60, 0, 0", + "1500, 40, 1, 0", + "2000, 50,-1, 0", + "2500, 0, 0, 2" + }; + var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); + var sumData = new SummaryDataContainer(null); + var run = Truck40tPowerTrain.CreateEngineeringRun(cycle, "Truck_ModDataIntegrity.vmod"); + + var engineData = MockSimulationDataFactory.CreateEngineDataFromFile(Truck40tPowerTrain.EngineFile, 0); + + // get a reference to the mod-data because the modaldata container clears it after simulation + var modData = ((ModalDataContainer)run.GetContainer().ModalData).Data; + var auxKeys = ((ModalDataContainer)run.GetContainer().ModalData).Auxiliaries; + + run.Run(); + Assert.IsTrue(run.FinishedWithoutErrors); + + AssertModDataIntegrity(modData, auxKeys, cycle.Entries.Last().Distance, engineData.ConsumptionMap); + } + + [TestCase(@"TestData\Integration\DeclarationMode\Class2_RigidTruck_4x2\Class2_RigidTruck_DECL.vecto")] + public void TestFullCycleModDataIntegrityDeclMT(string jobName) + { + RunSimulation(jobName, ExecutionMode.Declaration); + } + + [TestCase(@"TestData\Integration\EngineeringMode\Class2_RigidTruck_4x2\Class2_RigidTruck_ENG.vecto"), + TestCase(@"TestData\Integration\EngineeringMode\Class5_Tractor_4x2\Class5_Tractor_ENG.vecto"), + TestCase(@"TestData\Integration\EngineeringMode\Class9_RigidTruck_6x2_PTO\Class9_RigidTruck_ENG_PTO.vecto"),] + public void TestFullCycleModDataIntegrityMT(string jobName) + { + RunSimulation(jobName, ExecutionMode.Engineering); + } + + private static void RunSimulation(string jobName, ExecutionMode mode) + { + var fileWriter = new FileOutputWriter(jobName); + var sumData = new SummaryDataContainer(fileWriter); + + var jobContainer = new JobContainer(sumData); + var inputData = JSONInputDataFactory.ReadJsonJob(jobName); + + var runsFactory = new SimulatorFactory(mode, inputData, fileWriter) { WriteModalResults = true }; + + jobContainer.AddRuns(runsFactory); + var modData = new List<Tuple<ModalResults, Meter>>(); + foreach (var run in jobContainer.Runs) { + modData.Add(Tuple.Create(((ModalDataContainer)run.Run.GetContainer().ModalData).Data, + ((DistanceBasedDrivingCycle)((VehicleContainer)run.Run.GetContainer()).DrivingCycle).Data.Entries.Last() + .Distance)); + } + var auxKeys = + new Dictionary<string, DataColumn>( + ((ModalDataContainer)jobContainer.Runs.First().Run.GetContainer().ModalData).Auxiliaries); + jobContainer.Execute(); + jobContainer.WaitFinished(); + + // mod files will be stored in e.g. + // VectoCoreTest\bin\Debug\TestData\Integration\EngineeringMode\Class2_RigidTruck_4x2\Class2_RigidTruck_ENG.vecto_00.vmod + //fileWriter.WriteModData(Path.GetFileName(jobName), "0", "0", modData[0].Item1); + //fileWriter.WriteModData(Path.GetFileName(jobName), "1", "1", modData[1].Item1); + + foreach (var modalResults in modData) { + AssertModDataIntegrity(modalResults.Item1, auxKeys, modalResults.Item2, + FuelConsumptionMapReader.Create(((IEngineeringInputDataProvider)inputData).EngineInputData.FuelConsumptionMap)); + } + + AssertSumDataIntegrity(sumData, mode); + } + + private static void AssertSumDataIntegrity(SummaryDataContainer sumData, ExecutionMode mode) + { + Assert.IsTrue(sumData.Table.Rows.Count > 0); + + var ptoTransmissionColumn = + sumData.Table.Columns.Contains(string.Format(SummaryDataContainer.E_FORMAT, + Constants.Auxiliaries.IDs.PTOTransmission)) + ? string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOTransmission) + : null; + var ptoConsumerColumn = + sumData.Table.Columns.Contains(string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOConsumer)) + ? string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOConsumer) + : null; + + foreach (DataRow row in sumData.Table.Rows) { + var inputFile = row[SummaryDataContainer.INPUTFILE].ToString(); + var cycle = row[SummaryDataContainer.CYCLE].ToString(); + var loading = row[SummaryDataContainer.LOADING].ToString(); + var eFcMapPos = ((SI)row[SummaryDataContainer.E_FCMAP_POS]).Value(); + var eFcMapNeg = ((SI)row[SummaryDataContainer.E_FCMAP_NEG]).Value(); + var ePowertrainInertia = ((SI)row[SummaryDataContainer.E_POWERTRAIN_INERTIA]).Value(); + var eAux = ((SI)row[SummaryDataContainer.E_AUX]).Value(); + var eClutchLoss = ((SI)row[SummaryDataContainer.E_CLUTCH_LOSS]).Value(); + var eTcLoss = ((SI)row[SummaryDataContainer.E_TC_LOSS]).Value(); + //var eShiftLoss = ((SI)row[SummaryDataContainer.E_SHIFT_LOSS]).Value(); + var eGbxLoss = ((SI)row[SummaryDataContainer.E_GBX_LOSS]).Value(); + var eRetLoss = ((SI)row[SummaryDataContainer.E_RET_LOSS]).Value(); + var eAngleLoss = ((SI)row[SummaryDataContainer.E_ANGLE_LOSS]).Value(); + var eAxlLoss = ((SI)row[SummaryDataContainer.E_AXL_LOSS]).Value(); + var eBrakeLoss = ((SI)row[SummaryDataContainer.E_BRAKE]).Value(); + var eVehInertia = ((SI)row[SummaryDataContainer.E_VEHICLE_INERTIA]).Value(); + var eAir = ((SI)row[SummaryDataContainer.E_AIR]).Value(); + var eRoll = ((SI)row[SummaryDataContainer.E_ROLL]).Value(); + var eGrad = ((SI)row[SummaryDataContainer.E_GRAD]).Value(); + var cargoVolume = mode == ExecutionMode.Engineering ? 0 : ((SI)row[SummaryDataContainer.CARGO_VOLUME]).Value(); + + var loadingValue = ((SI)row[SummaryDataContainer.LOADING]).Value() / 1000; + var fcPer100km = ((SI)row[SummaryDataContainer.FCFINAL_LITERPER100KM]).Value(); + var fcPerVolume = mode == ExecutionMode.Engineering + ? 0 + : ((SI)row[SummaryDataContainer.FCFINAL_LiterPer100M3KM]).Value(); + var fcPerLoad = loadingValue > 0 ? ((SI)row[SummaryDataContainer.FCFINAL_LITERPER100TKM]).Value() : 0; + var co2Per100km = ((SI)row[SummaryDataContainer.CO2_KM]).Value(); + var co2PerVolume = mode == ExecutionMode.Engineering ? 0 : ((SI)row[SummaryDataContainer.CO2_M3KM]).Value(); + var co2PerLoad = loadingValue > 0 ? ((SI)row[SummaryDataContainer.CO2_TKM]).Value() : 0; + + var ePTOtransm = ptoTransmissionColumn != null ? ((SI)row[ptoTransmissionColumn]).Value() : 0; + var ePTOconsumer = ptoConsumerColumn != null ? ((SI)row[ptoConsumerColumn]).Value() : 0; + + // E_fcmap_pos = E_fcmap_neg + E_powertrain_inertia + E_aux_xxx + E_aux_sum + E_clutch_loss + E_tc_loss + E_gbx_loss + E_shift_loss + E_ret_loss + E_angle_loss + E_axl_loss + E_brake + E_vehicle_inertia + E_air + E_roll + E_grad + E_PTO_CONSUM + E_PTO_TRANSM + Assert.AreEqual(eFcMapPos, + eFcMapNeg + ePowertrainInertia + eAux + eClutchLoss + eTcLoss + eGbxLoss + eRetLoss + eAngleLoss + + eAxlLoss + eBrakeLoss + eVehInertia + eAir + eRoll + eGrad + ePTOconsumer + ePTOtransm, 1e-5, + "input file: {0} cycle: {1} loading: {2}", + inputFile, cycle, loading); + + var pFcmapPos = ((SI)row[SummaryDataContainer.P_FCMAP_POS]).Value(); + var time = ((SI)row[SummaryDataContainer.TIME]).Value(); + + // E_fcmap_pos = P_fcmap_pos * t + Assert.AreEqual(eFcMapPos, pFcmapPos * (time / 3600), 1e-3, "input file: {0} cycle: {1} loading: {2}", inputFile, + cycle, loading); + + if (cargoVolume > 0) { + Assert.AreEqual(fcPerVolume, fcPer100km / cargoVolume, 1e-3, "input file: {0} cycle: {1} loading: {2}", inputFile, + cycle, loading); + + Assert.AreEqual(co2PerVolume, co2Per100km / cargoVolume, 1e-3, "input file: {0} cycle: {1} loading: {2}", + inputFile, + cycle, loading); + } + + if (loadingValue > 0) { + Assert.AreEqual(co2PerLoad, co2Per100km / loadingValue, 1e-3, "input file: {0} cycle: {1} loading: {2}", + inputFile, cycle, loading); + Assert.AreEqual(fcPerLoad, fcPer100km / loadingValue, 1e-3, "input file: {0} cycle: {1} loading: {2}", + inputFile, cycle, loading); + } + + var stopTimeShare = ((SI)row[SummaryDataContainer.STOP_TIMESHARE]).Value(); + var accTimeShare = ((SI)row[SummaryDataContainer.ACC_TIMESHARE]).Value(); + var decTimeShare = ((SI)row[SummaryDataContainer.DEC_TIMESHARE]).Value(); + var cruiseTimeShare = ((SI)row[SummaryDataContainer.CRUISE_TIMESHARE]).Value(); + + Assert.AreEqual(100, stopTimeShare + accTimeShare + decTimeShare + cruiseTimeShare, 1e-3, + "input file: {0} cycle: {1} loading: {2}", inputFile, cycle, loading); + + Assert.IsTrue(((SI)row[SummaryDataContainer.ACC_POS]).Value() > 0); + Assert.IsTrue(((SI)row[SummaryDataContainer.ACC_NEG]).Value() < 0); + + var gearshifts = ((SI)row[SummaryDataContainer.NUM_GEARSHIFTS]).Value(); + Assert.IsTrue(gearshifts > 0); + + //var acc = ((SI)row[SummaryDataContainer.ACC]).Value(); + } + } + + private static void AssertModDataIntegrity(ModalResults modData, Dictionary<string, DataColumn> auxKeys, + Meter totalDistance, FuelConsumptionMap consumptionMap) + { + Assert.IsTrue(modData.Rows.Count > 0); + + var ptoTransmissionColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOTransmission) + ? auxKeys[Constants.Auxiliaries.IDs.PTOTransmission] + : null; + var ptoConsumerColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOConsumer) + ? auxKeys[Constants.Auxiliaries.IDs.PTOConsumer] + : null; + foreach (DataRow row in modData.Rows) { + if (totalDistance.IsEqual(((Meter)row[(int)ModalResultField.dist]))) { + continue; + } + var gear = (uint)row[(int)ModalResultField.Gear]; + var time = (Second)row[(int)ModalResultField.time]; + + var distance = (Meter)row[(int)ModalResultField.dist]; + var tqEngFcmap = (NewtonMeter)row[(int)ModalResultField.T_eng_fcmap]; + var nEngFcMap = (PerSecond)row[(int)ModalResultField.n_eng_avg]; + + // check fuel consumption interpolation + var fuelConsumption = (SI)row[(int)ModalResultField.FCMap]; + Assert.AreEqual(fuelConsumption.Value(), + consumptionMap.GetFuelConsumption(tqEngFcmap, nEngFcMap).Value.Value(), 1E-3, "time: {0} distance: {1}", + time, distance); + + // check P_eng_FCmap = T_eng_fcmap * n_eng + var pEngFcmap = (SI)row[(int)ModalResultField.P_eng_fcmap]; + Assert.AreEqual(pEngFcmap.Value(), (tqEngFcmap * nEngFcMap).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + var pWheelIn = (Watt)row[(int)ModalResultField.P_wheel_in]; + var pAir = (Watt)row[(int)ModalResultField.P_air]; + var pRoll = (Watt)row[(int)ModalResultField.P_roll]; + var pGrad = (Watt)row[(int)ModalResultField.P_slope]; + var pVehInertia = (Watt)row[(int)ModalResultField.P_veh_inertia]; + var pTrac = (Watt)row[(int)ModalResultField.P_trac]; + + // P_eng_out = P_wheel + P_lossgearbox + P_lossaxle + P_lossretarder + P_agbx + Pa_eng + P_aux - P_brake_loss + var pEngOut = (Watt)row[(int)ModalResultField.P_eng_out]; + var pLossGbx = (Watt)row[(int)ModalResultField.P_gbx_loss]; + var pGbxIn = (Watt)row[(int)ModalResultField.P_gbx_in]; + var pLossAxle = (Watt)row[(int)ModalResultField.P_axle_loss]; + var pLossAngle = row[(int)ModalResultField.P_angle_loss] is DBNull + ? 0.SI<Watt>() + : (Watt)row[(int)ModalResultField.P_angle_loss]; + var pAxleIn = (Watt)row[(int)ModalResultField.P_axle_in]; + var pLossRet = (Watt)row[(int)ModalResultField.P_ret_loss]; + var pRetIn = (Watt)row[(int)ModalResultField.P_retarder_in]; + var pGbxInertia = (Watt)row[(int)ModalResultField.P_gbx_inertia]; + var pShiftLoss = row[(int)ModalResultField.P_gbx_shift_loss] is DBNull + ? 0.SI<Watt>() + : (Watt)row[(int)ModalResultField.P_gbx_shift_loss]; + var pEngInertia = (Watt)row[(int)ModalResultField.P_eng_inertia]; + var pAux = + (Watt)(row[(int)ModalResultField.P_aux] != DBNull.Value ? row[(int)ModalResultField.P_aux] : 0.SI<Watt>()); + var pBrakeLoss = (Watt)row[(int)ModalResultField.P_brake_loss]; + var pBrakeIn = (Watt)row[(int)ModalResultField.P_brake_in]; + + var pWheelInertia = (Watt)row[(int)ModalResultField.P_wheel_inertia]; + var pPTOconsumer = ptoConsumerColumn == null || row[ptoConsumerColumn.ColumnName] is DBNull + ? 0.SI<Watt>() + : (Watt)row[ptoConsumerColumn.ColumnName]; + var pPTOtransm = ptoTransmissionColumn == null || row[ptoTransmissionColumn.ColumnName] is DBNull + ? 0.SI<Watt>() + : (Watt)row[ptoTransmissionColumn.ColumnName]; + // P_trac = P_veh_inertia + P_roll + P_air + P_slope + Assert.AreEqual(pTrac.Value(), (pAir + pRoll + pGrad + pVehInertia).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + // P_wheel_in = P_trac + P_wheel_inertia + Assert.AreEqual(pWheelIn.Value(), (pTrac + pWheelInertia).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pBrakeIn.Value(), (pWheelIn + pBrakeLoss).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pAxleIn.Value(), (pBrakeIn + pLossAxle).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pRetIn.Value(), (pAxleIn + pLossRet).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + var pClutchLoss = (Watt)(row[(int)ModalResultField.P_clutch_loss] != DBNull.Value + ? row[(int)ModalResultField.P_clutch_loss] + : 0.SI<Watt>()); + + var pClutchOut = row[(int)ModalResultField.P_clutch_out]; + if (pClutchOut != DBNull.Value) { + Assert.AreEqual(pGbxIn.Value(), (pClutchOut as Watt).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + Assert.AreEqual(pEngOut.Value(), (pClutchOut as Watt + pClutchLoss).Value(), 1E-3, "time: {0} distance: {1}", + time, distance); + } + + var pTC_Loss = (Watt)(row[(int)ModalResultField.P_TC_loss] != DBNull.Value + ? row[(int)ModalResultField.P_TC_loss] + : 0.SI<Watt>()); + + var pTCOut = row[(int)ModalResultField.P_clutch_out]; + if (pTCOut != DBNull.Value) { + Assert.AreEqual(pGbxIn.Value(), (pTCOut as Watt).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + //Assert.AreEqual(pEngOut.Value(), (pTCOut as Watt + pTC_Loss).Value(), 1E-3, "time: {0} distance: {1}", + // time, distance); + } + + Assert.IsTrue(pLossGbx.IsGreaterOrEqual(pShiftLoss + pGbxInertia), "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pGbxIn.Value(), (pRetIn + pLossGbx + pGbxInertia).Value(), gear != 0 ? 1E-3 : 0.5, + "time: {0} distance: {1}", time, + distance); + + // P_eng_fcmap = P_eng_out + P_AUX + P_eng_inertia ( + P_PTO_Transm + P_PTO_Consumer ) + Assert.AreEqual(pEngFcmap.Value(), (pEngOut + pAux + pEngInertia + pPTOtransm + pPTOconsumer).Value(), 0.5, + "time: {0} distance: {1}", time, distance); + + // P_eng_fcmap = sum(Losses Powertrain) + var pLossTot = pClutchLoss + pTC_Loss + pLossGbx + pLossRet + pGbxInertia + pLossAngle + pLossAxle + pBrakeLoss + + pWheelInertia + pAir + pRoll + pGrad + pVehInertia + pPTOconsumer + pPTOtransm; + var pEngFcmapCalc = (pLossTot + pEngInertia + pAux).Value(); + Assert.AreEqual(pEngFcmap.Value(), pEngFcmapCalc, 0.5, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pEngFcmap.Value(), + (pTrac + pWheelInertia + pBrakeLoss + pLossAxle + pLossRet + pLossGbx + pGbxInertia + pEngInertia + pAux + + pClutchLoss + pTC_Loss + pPTOtransm + pPTOconsumer).Value(), 0.5, "time: {0} distance: {1}", time, distance); + } + } + + [ + TestCase(@"TestData\Integration\EngineeringMode\CityBus_AT\CityBus_AT_Ser.vecto"), + TestCase(@"TestData\Integration\EngineeringMode\CityBus_AT\CityBus_AT_PS.vecto")] + public void TestFullCycleModDataIntegrityAT(string jobName) + { + var fileWriter = new FileOutputWriter(jobName); + var sumData = new SummaryDataContainer(fileWriter); + + var jobContainer = new JobContainer(sumData); + var inputData = JSONInputDataFactory.ReadJsonJob(jobName); + + var runsFactory = + new SimulatorFactory(ExecutionMode.Engineering, inputData, fileWriter) { WriteModalResults = true }; + + jobContainer.AddRuns(runsFactory); + var modData = new List<Tuple<ModalResults, Meter>>(); + foreach (var run in jobContainer.Runs) { + modData.Add(Tuple.Create(((ModalDataContainer)run.Run.GetContainer().ModalData).Data, + ((DistanceBasedDrivingCycle)((VehicleContainer)run.Run.GetContainer()).DrivingCycle).Data.Entries.Last() + .Distance)); + } + var auxKeys = + new Dictionary<string, DataColumn>( + ((ModalDataContainer)jobContainer.Runs.First().Run.GetContainer().ModalData).Auxiliaries); + jobContainer.Execute(); + jobContainer.WaitFinished(); + + foreach (var modalResults in modData) { + AssertModDataIntegrityAT(modalResults.Item1, auxKeys, modalResults.Item2, + FuelConsumptionMapReader.Create(((IEngineeringInputDataProvider)inputData).EngineInputData.FuelConsumptionMap)); + } + + AssertSumDataIntegrity(sumData, ExecutionMode.Engineering); + } + + private static void AssertModDataIntegrityAT(ModalResults modData, Dictionary<string, DataColumn> auxKeys, + Meter totalDistance, FuelConsumptionMap consumptionMap) + { + Assert.IsTrue(modData.Rows.Count > 0); + + var ptoTransmissionColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOTransmission) + ? auxKeys[Constants.Auxiliaries.IDs.PTOTransmission] + : null; + var ptoConsumerColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOConsumer) + ? auxKeys[Constants.Auxiliaries.IDs.PTOConsumer] + : null; + foreach (DataRow row in modData.Rows) { + if (totalDistance.IsEqual(((Meter)row[(int)ModalResultField.dist]))) { + continue; + } + var gear = (uint)row[(int)ModalResultField.Gear]; + var time = (Second)row[(int)ModalResultField.time]; + + var distance = (Meter)row[(int)ModalResultField.dist]; + var tqEngFcmap = (NewtonMeter)row[(int)ModalResultField.T_eng_fcmap]; + var nEngFcMap = (PerSecond)row[(int)ModalResultField.n_eng_avg]; + + // check fuel consumption interpolation + var fuelConsumption = (SI)row[(int)ModalResultField.FCMap]; + Assert.AreEqual(fuelConsumption.Value(), + consumptionMap.GetFuelConsumption(tqEngFcmap, nEngFcMap).Value.Value(), 1E-3, "time: {0} distance: {1}", + time, distance); + + // check P_eng_FCmap = T_eng_fcmap * n_eng + var pEngFcmap = (SI)row[(int)ModalResultField.P_eng_fcmap]; + Assert.AreEqual(pEngFcmap.Value(), (tqEngFcmap * nEngFcMap).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + var pWheelIn = (Watt)row[(int)ModalResultField.P_wheel_in]; + var pAir = (Watt)row[(int)ModalResultField.P_air]; + var pRoll = (Watt)row[(int)ModalResultField.P_roll]; + var pGrad = (Watt)row[(int)ModalResultField.P_slope]; + var pVehInertia = (Watt)row[(int)ModalResultField.P_veh_inertia]; + var pTrac = (Watt)row[(int)ModalResultField.P_trac]; + + // Pe_eng = P_wheel + P_lossgearbox + P_lossaxle + P_lossretarder + P_agbx + Pa_eng + P_aux - P_brake_loss + var pEngOut = (Watt)row[(int)ModalResultField.P_eng_out]; + var pLossGbx = (Watt)row[(int)ModalResultField.P_gbx_loss]; + var pGbxIn = (Watt)row[(int)ModalResultField.P_gbx_in]; + var pLossAxle = (Watt)row[(int)ModalResultField.P_axle_loss]; + var pLossAngle = row[(int)ModalResultField.P_angle_loss] is DBNull + ? 0.SI<Watt>() + : (Watt)row[(int)ModalResultField.P_angle_loss]; + var pAxleIn = (Watt)row[(int)ModalResultField.P_axle_in]; + var pLossRet = (Watt)row[(int)ModalResultField.P_ret_loss]; + var pRetIn = (Watt)row[(int)ModalResultField.P_retarder_in]; + var pGbxInertia = (Watt)row[(int)ModalResultField.P_gbx_inertia]; + var pShiftLoss = row[(int)ModalResultField.P_gbx_shift_loss] is DBNull + ? 0.SI<Watt>() + : (Watt)row[(int)ModalResultField.P_gbx_shift_loss]; + var pEngInertia = (Watt)row[(int)ModalResultField.P_eng_inertia]; + var pAux = + (Watt)(row[(int)ModalResultField.P_aux] != DBNull.Value ? row[(int)ModalResultField.P_aux] : 0.SI<Watt>()); + var pBrakeLoss = (Watt)row[(int)ModalResultField.P_brake_loss]; + var pBrakeIn = (Watt)row[(int)ModalResultField.P_brake_in]; + var pTcLoss = (Watt)row[(int)ModalResultField.P_TC_loss]; + var pTcOut = (Watt)row[(int)ModalResultField.P_TC_out]; + var pWheelInertia = (Watt)row[(int)ModalResultField.P_wheel_inertia]; + var pPTOconsumer = ptoConsumerColumn == null || row[ptoConsumerColumn] is DBNull + ? 0.SI<Watt>() + : (Watt)row[ptoConsumerColumn]; + var pPTOtransm = ptoTransmissionColumn == null || row[ptoTransmissionColumn] is DBNull + ? 0.SI<Watt>() + : (Watt)row[ptoTransmissionColumn]; + // P_trac = P_veh_inertia + P_roll + P_air + P_slope + Assert.AreEqual(pTrac.Value(), (pAir + pRoll + pGrad + pVehInertia).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + // P_wheel_in = P_trac + P_wheel_inertia + Assert.AreEqual(pWheelIn.Value(), (pTrac + pWheelInertia).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pBrakeIn.Value(), (pWheelIn + pBrakeLoss).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pAxleIn.Value(), (pBrakeIn + pLossAxle).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pRetIn.Value(), (pAxleIn + pLossRet).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pGbxIn.Value(), pTcOut.Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pEngOut.Value(), (pTcOut + pTcLoss).Value(), 1E-3, + "time: {0} distance: {1}", time, distance); + + // P_eng_fcmap = P_eng_out + P_AUX + P_eng_inertia ( + P_PTO_Transm + P_PTO_Consumer ) + Assert.AreEqual(pEngFcmap.Value(), (pEngOut + pAux + pEngInertia + pPTOtransm + pPTOconsumer).Value(), 1E-3, + "time: {0} distance: {1}", time, + distance); + + // P_eng_fcmap = sum(Losses Powertrain) + var pLossTot = pTcLoss + pLossGbx + pLossRet + pGbxInertia + pLossAngle + pLossAxle + pBrakeLoss + + pWheelInertia + pAir + pRoll + pGrad + pVehInertia + pPTOconsumer + pPTOtransm; + + Assert.AreEqual(pEngFcmap.Value(), (pLossTot + pEngInertia + pAux).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.IsTrue(pLossGbx.IsGreaterOrEqual(pShiftLoss + pGbxInertia), "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pGbxIn.Value(), (pRetIn + pLossGbx + pGbxInertia).Value(), gear != 0 ? 1E-3 : 0.5, + "time: {0} distance: {1}", time, + distance); + Assert.AreEqual(pEngFcmap.Value(), + (pTrac + pWheelInertia + pBrakeLoss + pLossAxle + pLossRet + pLossGbx + pGbxInertia + pEngInertia + pAux + + pTcLoss + pPTOtransm + pPTOconsumer).Value(), 0.5, "time: {0} distance: {1}", time, distance); + } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/TestData/Components/AT_GBX/GearboxSerialDualTCBus.vgbx b/VectoCore/VectoCoreTest/TestData/Components/AT_GBX/GearboxSerialDualTCBus.vgbx new file mode 100644 index 0000000000000000000000000000000000000000..cf00163cc28aa4f96ce9e8e2f8c5e96c2f41a9d7 --- /dev/null +++ b/VectoCore/VectoCoreTest/TestData/Components/AT_GBX/GearboxSerialDualTCBus.vgbx @@ -0,0 +1,68 @@ +{ + "Header": { + "CreatedBy": " ()", + "Date": "03.08.2016 14:22:48", + "AppVersion": "2.2", + "FileVersion": 6 + }, + "Body": { + "SavedInDeclMode": false, + "ModelName": "AT Serial", + "Inertia": 0.0, + "TracInt": 0.0, + "Gears": [ + { + "Ratio": 2.1, + "Efficiency": "0.98" + }, + { + "Ratio": 4.58, + "Efficiency": "0.98", + "ShiftPolygon": "AT-Shift.vgbs", + "FullLoadCurve": "<NOFILE>" + }, + { + "Ratio": 2.4, + "Efficiency": "0.98", + "ShiftPolygon": "AT-Shift.vgbs", + "FullLoadCurve": "<NOFILE>" + }, + { + "Ratio": 1.8, + "Efficiency": "0.98", + "ShiftPolygon": "AT-Shift.vgbs", + "FullLoadCurve": "<NOFILE>" + }, + { + "Ratio": 1.3, + "Efficiency": "0.98", + "ShiftPolygon": "AT-Shift.vgbs", + "FullLoadCurve": "<NOFILE>" + }, + { + "Ratio": 1.0, + "Efficiency": "0.98", + "ShiftPolygon": "AT-Shift.vgbs", + "FullLoadCurve": "<NOFILE>" + } + ], + "TqReserve": 0.0, + "SkipGears": false, + "ShiftTime": 0, + "EaryShiftUp": false, + "StartTqReserve": 0.0, + "StartSpeed": 0.0, + "StartAcc": 0.0, + "GearboxType": "ATSerial", + "TorqueConverter": { + "Enabled": true, + "File": "TorqueConverter.vtcc", + "ShiftPolygon": "AT-Shift.vgbs", + "RefRPM": 1000.0, + "Inertia": 0.0 + }, + "DownshiftAferUpshiftDelay": 0.0, + "UpshiftAfterDownshiftDelay": 0.0, + "UpshiftMinAcceleration": 0.0 + } +} \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Utils/MockSimulationDataFactory.cs b/VectoCore/VectoCoreTest/Utils/MockSimulationDataFactory.cs index 0531a6625ca38aa9f5da975d5bcec5b9b2a2f68e..675a82b958dfce5b28dde0ecebee4a215dafdce5 100644 --- a/VectoCore/VectoCoreTest/Utils/MockSimulationDataFactory.cs +++ b/VectoCore/VectoCoreTest/Utils/MockSimulationDataFactory.cs @@ -29,85 +29,88 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Collections.Generic; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.InputData.FileIO.JSON; -using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; -using TUGraz.VectoCore.Models.SimulationComponent.Data; - -namespace TUGraz.VectoCore.Tests.Utils -{ - public class MockSimulationDataFactory - { - /// <summary> - /// Create gearboxdata instance directly from a file - /// </summary> - /// <param name="gearBoxFile"></param> - /// <param name="engineFile"></param> - /// <param name="declarationMode"></param> - /// <returns>GearboxData instance</returns> - public static GearboxData CreateGearboxDataFromFile(string gearBoxFile, string engineFile, bool declarationMode = true) - { - var gearboxInput = JSONInputDataFactory.ReadGearbox(gearBoxFile); - var engineInput = JSONInputDataFactory.ReadEngine(engineFile); - if (declarationMode) { - var dao = new DeclarationDataAdapter(); - var engineData = dao.CreateEngineData(engineInput, null, gearboxInput, new List<ITorqueLimitInputData>()); - return dao.CreateGearboxData(gearboxInput, engineData, ((IAxleGearInputData)gearboxInput).Ratio, 0.5.SI<Meter>(), - false); - } else { - var dao = new EngineeringDataAdapter(); - var engineData = dao.CreateEngineData(engineInput, gearboxInput, new List<ITorqueLimitInputData>()); - return dao.CreateGearboxData(gearboxInput, engineData, ((IAxleGearInputData)gearboxInput).Ratio, 0.5.SI<Meter>(), - true); - } - } - - public static AxleGearData CreateAxleGearDataFromFile(string axleGearFile) - { - var dao = new DeclarationDataAdapter(); - var axleGearInput = JSONInputDataFactory.ReadGearbox(axleGearFile); - return dao.CreateAxleGearData((IAxleGearInputData)axleGearInput, false); - } - - public static CombustionEngineData CreateEngineDataFromFile(string engineFile, int numGears) - { - var dao = new EngineeringDataAdapter(); - var engineInput = JSONInputDataFactory.ReadEngine(engineFile); - var engineData = dao.CreateEngineData(engineInput, null, new List<ITorqueLimitInputData>()); - for (uint i = 1; i <= numGears; i++) { - engineData.FullLoadCurves[i] = engineData.FullLoadCurves[0]; - } - return engineData; - } - - public static VehicleData CreateVehicleDataFromFile(string vehicleDataFile) - { - var dao = new EngineeringDataAdapter(); - var vehicleInput = JSONInputDataFactory.ReadJsonVehicle(vehicleDataFile); - var airdragData = vehicleInput as IAirdragEngineeringInputData; - return dao.CreateVehicleData(vehicleInput); - } - - public static AirdragData CreateAirdragDataFromFile(string vehicleDataFile) - { - var dao = new EngineeringDataAdapter(); - var vehicleInput = JSONInputDataFactory.ReadJsonVehicle(vehicleDataFile); - var airdragData = vehicleInput as IAirdragEngineeringInputData; - return dao.CreateAirdragData(airdragData, vehicleInput); - } - - public static DriverData CreateDriverDataFromFile(string driverDataFile) - { - var jobInput = JSONInputDataFactory.ReadJsonJob(driverDataFile); - var engineeringJob = jobInput as IEngineeringInputDataProvider; - if (engineeringJob == null) { - throw new VectoException("Failed to cas to Engineering InputDataProvider"); - } - var dao = new EngineeringDataAdapter(); - return dao.CreateDriverData(engineeringJob.DriverInputData); - } - } +using System.Collections.Generic; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.FileIO.JSON; +using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; +using TUGraz.VectoCore.Models.SimulationComponent.Data; + +namespace TUGraz.VectoCore.Tests.Utils +{ + public class MockSimulationDataFactory + { + /// <summary> + /// Create gearboxdata instance directly from a file + /// </summary> + /// <param name="gearBoxFile"></param> + /// <param name="engineFile"></param> + /// <param name="declarationMode"></param> + /// <returns>GearboxData instance</returns> + public static GearboxData CreateGearboxDataFromFile(string gearBoxFile, string engineFile, bool declarationMode = true) + { + var gearboxInput = JSONInputDataFactory.ReadGearbox(gearBoxFile); + var engineInput = JSONInputDataFactory.ReadEngine(engineFile); + if (declarationMode) { + var dao = new DeclarationDataAdapter(); + var engineData = dao.CreateEngineData(engineInput, null, gearboxInput, new List<ITorqueLimitInputData>()); + return dao.CreateGearboxData(gearboxInput, engineData, ((IAxleGearInputData)gearboxInput).Ratio, 0.5.SI<Meter>(), + VehicleCategory.RigidTruck, + false); + } else { + var dao = new EngineeringDataAdapter(); + var engineData = dao.CreateEngineData(engineInput, gearboxInput, new List<ITorqueLimitInputData>()); + return dao.CreateGearboxData(gearboxInput, engineData, ((IAxleGearInputData)gearboxInput).Ratio, 0.5.SI<Meter>(), + VehicleCategory.RigidTruck, + true); + } + } + + public static AxleGearData CreateAxleGearDataFromFile(string axleGearFile) + { + var dao = new DeclarationDataAdapter(); + var axleGearInput = JSONInputDataFactory.ReadGearbox(axleGearFile); + return dao.CreateAxleGearData((IAxleGearInputData)axleGearInput, false); + } + + public static CombustionEngineData CreateEngineDataFromFile(string engineFile, int numGears) + { + var dao = new EngineeringDataAdapter(); + var engineInput = JSONInputDataFactory.ReadEngine(engineFile); + var engineData = dao.CreateEngineData(engineInput, null, new List<ITorqueLimitInputData>()); + for (uint i = 1; i <= numGears; i++) { + engineData.FullLoadCurves[i] = engineData.FullLoadCurves[0]; + } + return engineData; + } + + public static VehicleData CreateVehicleDataFromFile(string vehicleDataFile) + { + var dao = new EngineeringDataAdapter(); + var vehicleInput = JSONInputDataFactory.ReadJsonVehicle(vehicleDataFile); + var airdragData = vehicleInput as IAirdragEngineeringInputData; + return dao.CreateVehicleData(vehicleInput); + } + + public static AirdragData CreateAirdragDataFromFile(string vehicleDataFile) + { + var dao = new EngineeringDataAdapter(); + var vehicleInput = JSONInputDataFactory.ReadJsonVehicle(vehicleDataFile); + var airdragData = vehicleInput as IAirdragEngineeringInputData; + return dao.CreateAirdragData(airdragData, vehicleInput); + } + + public static DriverData CreateDriverDataFromFile(string driverDataFile) + { + var jobInput = JSONInputDataFactory.ReadJsonJob(driverDataFile); + var engineeringJob = jobInput as IEngineeringInputDataProvider; + if (engineeringJob == null) { + throw new VectoException("Failed to cas to Engineering InputDataProvider"); + } + var dao = new EngineeringDataAdapter(); + return dao.CreateDriverData(engineeringJob.DriverInputData); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/VectoCoreTest.csproj b/VectoCore/VectoCoreTest/VectoCoreTest.csproj index cdd9fae36fee393db5b57eba25b39c30b919bf1e..9d5741aa3cfee88d1b0fa57d535c768f5c0d8c17 100644 --- a/VectoCore/VectoCoreTest/VectoCoreTest.csproj +++ b/VectoCore/VectoCoreTest/VectoCoreTest.csproj @@ -257,6 +257,9 @@ <None Include="TestData\Components\AT_GBX\GearboxSerial.vgbx"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> + <None Include="TestData\Components\AT_GBX\GearboxSerialDualTCBus.vgbx"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> <None Include="TestData\Components\AT_GBX\GearboxSerialDualTC.vgbx"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> diff --git a/VectoCore/VectoCoreTest/XML/XMLEngineeringInputSingleTest.cs b/VectoCore/VectoCoreTest/XML/XMLEngineeringInputSingleTest.cs index b04558a032a19f417e6e7b5efd78f3bd41e4bc67..0d28bcb8b48511ede6cd2a63f058d931479ab878 100644 --- a/VectoCore/VectoCoreTest/XML/XMLEngineeringInputSingleTest.cs +++ b/VectoCore/VectoCoreTest/XML/XMLEngineeringInputSingleTest.cs @@ -436,13 +436,14 @@ namespace TUGraz.VectoCore.Tests.XML Assert.AreEqual(DeclarationData.Gearbox.StartAcceleration.Value(), shiftStrategy.StartAcceleration.Value(), 1e-6); Assert.AreEqual(DeclarationData.Gearbox.TorqueReserveStart, shiftStrategy.StartTorqueReserve, 1e-6); - // TODO: MQ 2017-01-16: introduce constants, use also in input data provider! - Assert.AreEqual(0.8, shiftStrategy.PowershiftShiftTime.Value(), 1e-6); + AssertHelper.AreRelativeEqual(Constants.DefaultPowerShiftTime, shiftStrategy.PowershiftShiftTime); var tcShiftStrategy = inputDataProvider.GearboxInputData.TorqueConverter; - Assert.AreEqual(0.1, tcShiftStrategy.CCUpshiftMinAcceleration.Value(), 1e-6); - Assert.AreEqual(0.1, tcShiftStrategy.CLUpshiftMinAcceleration.Value(), 1e-6); + AssertHelper.AreRelativeEqual(DeclarationData.TorqueConverter.CCUpshiftMinAcceleration, + tcShiftStrategy.CCUpshiftMinAcceleration); + AssertHelper.AreRelativeEqual(DeclarationData.TorqueConverter.CLUpshiftMinAcceleration, + tcShiftStrategy.CLUpshiftMinAcceleration); } [TestMethod] diff --git a/packages/repositories.config b/packages/repositories.config index 96750bd818fd83effc632b7bb600d511c3f3c3a6..4602b99be1aafb216e83dfc07a5271d8caf8017c 100644 --- a/packages/repositories.config +++ b/packages/repositories.config @@ -1,8 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <repositories> - <repository path="..\..\VECTO_API\Excel2XML\packages.config" /> - <repository path="..\..\VECTO_API\VectoDB\packages.config" /> - <repository path="..\..\VECTO-Bugreports\BugReportTests\packages.config" /> <repository path="..\VECTO\packages.config" /> <repository path="..\VECTOAux\VectoAuxiliaries\packages.config" /> <repository path="..\VECTOAux\VectoAuxiliariesTests\packages.config" />