Compare commits

..
Author SHA1 Message Date
Pierre-Antoine Rouby d0acface41 Geometry, doc: Fix pointXYZ foreign key. 2024-04-26 10:04:43 +02:00
Pierre-Antoine Rouby aea7cdb823 doc: dev: Add database scheme images. 2024-04-26 09:40:14 +02:00
Pierre-Antoine Rouby 441a064d84 Solver: CommandLine: Try fix Windows encoding crash. 2024-04-24 09:51:58 +02:00
Pierre-Antoine Rouby ee6b2a94eb Results: Add plot toolsbar iso view and back/forward option. 2024-04-24 09:51:28 +02:00
Pierre-Antoine Rouby 07761716e4 Solver: Mage: Check is node is enable before BC export. 2024-04-24 09:33:33 +02:00
Pierre-Antoine Rouby fd1b2b1041 doc: dev: Minor change. 2024-04-23 09:09:54 +02:00
Pierre-Antoine Rouby e5422c71f5 View: Network: Minor change. 2024-04-22 16:48:17 +02:00
Pierre-Antoine Rouby efd8960e1e Pamhyr2: Fix pep8. 2024-04-22 16:46:50 +02:00
Pierre-Antoine Rouby 8dcb0a298e Pamhyr2: View: Tools: Add comment. 2024-04-22 16:40:58 +02:00
Pierre-Antoine Rouby acbd3537c0 Pamhyr2: Minor change and method documentation. 2024-04-22 16:29:23 +02:00
Pierre-Antoine Rouby 145c301eed doc: dev: Update documentation. 2024-04-22 16:28:41 +02:00
Pierre-Antoine Rouby ec91a8b63f Solver: Fix SIN export and error handler at export. 2024-04-22 11:33:07 +02:00
Pierre-Antoine Rouby ffdeb28bfd Network: Fix potential crash with maptoscene. 2024-04-22 11:07:42 +02:00
Pierre-Antoine Rouby df1ac5586e IC: Fix incline computation in case of zero marging. 2024-04-19 16:31:12 +02:00
Pierre-Antoine Rouby ab1b7a2605 Save/Backup: Add mutual exclusion on save methode and block backup signal. 2024-04-19 10:39:25 +02:00
Pierre-Antoine Rouby 53456cf7fa IC: Fix generator spinbox max size. 2024-04-17 14:47:49 +02:00
Pierre-Antoine Rouby 1cbdda1ec5 Solver: Log: Fix new line spliting (depend of OS). 2024-04-17 14:46:17 +02:00
Pierre-Antoine Rouby ba2fa25636 Pamhyr2: Fix some fonts size and family. 2024-04-17 14:45:32 +02:00
Pierre-Antoine Rouby 5189cbaa6f Windows: Fix logging file encoding. 2024-04-17 14:27:01 +02:00
Pierre-Antoine Rouby f1ce2e4b10 Windows: Enable console but hide it. 2024-04-17 12:18:28 +02:00
Pierre-Antoine Rouby 50ae49c0ec Windows: Fix UTF-8 en/decode. 2024-04-17 12:17:25 +02:00
Pierre-Antoine Rouby 502c2240f7 Solver: Parameters: Fix Y/N french translate. 2024-04-17 09:42:17 +02:00
Pierre-Antoine Rouby b784f00b92 Solver: Mage: Fix pep8. 2024-04-16 15:39:51 +02:00
Pierre-Antoine Rouby 457dac477a Solver: Mage: Minor change. 2024-04-16 14:01:59 +02:00
Pierre-Antoine Rouby dc114f759d Solver: Mage: Enable LC export. 2024-04-16 12:04:19 +02:00
Pierre-Antoine Rouby 672f81f216 MeshingTools: Fix mailleurTT path. 2024-04-16 10:47:07 +02:00
Pierre-Antoine Rouby 3516986ff2 Geometry: Meshing: Fix space step maximum value to 9999.99 (m). 2024-04-16 10:12:15 +02:00
Pierre-Antoine Rouby 7ecd98a5fb Solver: Mage: Add error file by default. 2024-04-16 08:32:19 +02:00
Pierre-Antoine Rouby 1fdeab9685 Geometry: Meshing: Minor change. 2024-04-15 15:42:37 +02:00
Pierre-Antoine Rouby ebd4e64cc3 Pamhyr2: Update Mage version to v8.3.5 2024-04-15 11:39:06 +02:00
Pierre-Antoine Rouby 1452f4129f Config: Fix configuration save whene click cancel. 2024-04-15 11:16:41 +02:00
Pierre-Antoine Rouby 04d43f3f28 Backup: Fix backup. 2024-04-15 11:16:20 +02:00
Pierre-Antoine Rouby b7ebf961ac Geometry: Fix geometry loading. 2024-04-15 10:29:56 +02:00
Pierre-Antoine Rouby 28c7a0177a HS: Basic: Fix plot AC init. 2024-04-15 09:35:10 +02:00
Pierre-Antoine Rouby 62860750f2 Config: Fix useless print. 2024-04-09 09:37:29 +02:00
Pierre-Antoine Rouby 4d8277c5c2 Pamhyr2: Fix pep8. 2024-04-08 16:25:25 +02:00
Pierre-Antoine Rouby b9fddcf78c LC: Add DMY datetime support. 2024-04-08 16:13:23 +02:00
Pierre-Antoine Rouby a834e1905d BC: Add DMY datetime support. 2024-04-08 16:10:39 +02:00
Pierre-Antoine Rouby de1f5c1944 RunSolver: Fix copy methode. 2024-04-08 15:37:00 +02:00
Pierre-Antoine Rouby ae21315593 Network: Fix crash when edge addition click on the void. 2024-04-05 11:15:09 +02:00
Pierre-Antoine Rouby b209547a5b Solver: Disable mage fake 7. 2024-04-03 17:48:09 +02:00
Pierre-Antoine Rouby faab0d78cf tests_cases: Fix and update Saar study. 2024-04-03 14:49:19 +02:00
Pierre-Antoine Rouby a487cd8e64 AddFile, REPLine: Fix modified status. 2024-04-02 17:07:04 +02:00
Pierre-Antoine Rouby 92eac86c68 AddFiles, REPLine: Add undo commands. 2024-04-02 16:18:21 +02:00
Pierre-Antoine Rouby e350b7d8f5 Solver: Mage8: Do not add additional files into REP file. 2024-03-27 10:50:23 +01:00
Pierre-Antoine Rouby e7e1582836 MainWindow: Checker: Minor change and fixes. 2024-03-27 09:57:53 +01:00
Pierre-Antoine Rouby 9d9a8a7ced MainWindow: Info: Simplify study section. 2024-03-27 09:40:14 +01:00
Pierre-Antoine Rouby aef81d088c Meshing: Add trivial MashingWithMAgeMailleurTT unit tests. 2024-03-27 09:36:34 +01:00
Pierre-Antoine Rouby 35b421b4df Pamhyr2: Fix Pep8. 2024-03-27 09:33:43 +01:00
Pierre-Antoine Rouby dbbae7a53f Translate: Rebuild Pamhyr2 french translate. 2024-03-27 09:27:37 +01:00
Pierre-Antoine Rouby b9ace9f58f MainWindow: Remove obsolete actions. 2024-03-26 17:54:32 +01:00
Pierre-Antoine Rouby 48aa5cb1aa Config: Update config with new mage_fake7 solver and new mage path. 2024-03-26 15:29:45 +01:00
Pierre-Antoine Rouby b517c38cb9 Solver: Mage: Add mage fake 7. 2024-03-26 15:18:05 +01:00
Pierre-Antoine Rouby d158c8ad7a Windows: Fix 'pwd' import. 2024-03-26 13:49:56 +01:00
Pierre-Antoine Rouby 8c9eeb6160 Windows: Fix NSI file. 2024-03-26 11:02:02 +01:00
Pierre-Antoine Rouby aedb8c46fc REPLines: Add REP lines into model, view and minor change. 2024-03-26 10:40:57 +01:00
Pierre-Antoine Rouby 1ff895368e pamhyr: Fix save after backup and minor change. 2024-03-26 08:36:45 +01:00
Pierre-Antoine Rouby 48e30125bb AdditionalFiles: Add model, view and solver export. 2024-03-25 17:21:31 +01:00
Pierre-Antoine Rouby db416d25de pamhyr: Fix Pep8. 2024-03-25 14:04:55 +01:00
Pierre-Antoine Rouby da18a8b712 Study: Add default description example. 2024-03-25 13:57:27 +01:00
Pierre-Antoine Rouby 48c98cddba Study: Switch rich text to markdown. 2024-03-22 17:07:13 +01:00
Pierre-Antoine Rouby 16a0e03d1d Study: Add riche text option for study description editing. 2024-03-22 16:12:57 +01:00
Pierre-Antoine Rouby e0f580daf6 windows: Fix widgets path. 2024-03-22 15:13:35 +01:00
Pierre-Antoine Rouby c1c16964eb windows: Disable console. 2024-03-22 15:03:47 +01:00
Pierre-Antoine Rouby d0134d6415 ci: Fix hash path. 2024-03-22 14:54:15 +01:00
Pierre-Antoine Rouby 9f4c759ea3 package: Fix exe and _internal position. 2024-03-22 14:51:10 +01:00
Pierre-Antoine Rouby 661e2071d1 Package: Rename mage to mage8 and reorganise package installation dir. 2024-03-22 14:43:51 +01:00
Pierre-Antoine Rouby 0f25334032 pamhyr: Close study DB if already init. 2024-03-22 14:03:46 +01:00
Pierre-Antoine Rouby 334ada3dcc pamhyr: Add missing dependencies. 2024-03-22 11:32:49 +01:00
Pierre-Antoine Rouby df0b5bb014 MainWindow: Minor change. 2024-03-22 11:24:58 +01:00
Pierre-Antoine Rouby 20686086d8 pamhyr: Add CONFIG modules. 2024-03-22 11:23:25 +01:00
Pierre-Antoine Rouby 1be8f6c434 MainWindow: Add status at save/backup. 2024-03-22 11:17:18 +01:00
Pierre-Antoine Rouby f8c16d8c7c pamhyr: Reopen backup if newer than last save in case of crash. 2024-03-22 10:55:48 +01:00
Pierre-Antoine Rouby 7f3cf46ee1 pamhyr: Add periodic backup. 2024-03-22 09:51:53 +01:00
Pierre-Antoine Rouby 632cd2cd4c Checker: Fix checker table update at study close. 2024-03-22 08:45:37 +01:00
Pierre-Antoine Rouby 0f5243f36a Geometry, checker: Minor change. 2024-03-22 08:29:04 +01:00
Pierre-Antoine Rouby 137368cc27 pamhyr: Fix pep8. 2024-03-20 17:08:11 +01:00
Pierre-Antoine Rouby e343d284d9 MainWindow: Checker: Add lists. 2024-03-20 17:03:37 +01:00
Pierre-Antoine Rouby a23692a29c MainWindow: Checker: Add worker. 2024-03-20 16:08:53 +01:00
Pierre-Antoine Rouby 30170df1b1 Mainwindow: Checker: Add table. 2024-03-20 12:24:13 +01:00
Pierre-Antoine Rouby 3be4e6c112 MainWindow: Fix missing file. 2024-03-20 09:25:59 +01:00
Pierre-Antoine Rouby e5650b5378 MainWindow: Checkers: Add checker tab template. 2024-03-19 17:21:27 +01:00
Pierre-Antoine Rouby 67f534a6f6 Checker: Add related module(s). 2024-03-19 12:00:44 +01:00
Pierre-Antoine Rouby 51031e7359 Pamhyr: Add pamhyr modules flags enum and checker status OR operator. 2024-03-19 09:18:28 +01:00
Pierre-Antoine Rouby e215e0f14a MainWindow: Info: Minor change. 2024-02-28 16:49:10 +01:00
Pierre-Antoine Rouby 1099d5f282 Pamhyr2: Fix Pep8. 2024-02-28 16:28:54 +01:00
Pierre-Antoine Rouby 330761a372 MainWindow: Info: Add some informations. 2024-02-28 16:27:09 +01:00
Pierre-Antoine Rouby 81f38b942c Reservoir: Edit: Fix undo/redo update. 2024-02-28 15:44:58 +01:00
Pierre-Antoine Rouby 07cefceed8 Network: Add reservoir shortcut at network edit. 2024-02-28 15:40:57 +01:00
Pierre-Antoine Rouby ed5e520b35 Network: Refacto graph context menu. 2024-02-28 10:49:38 +01:00
Pierre-Antoine Rouby 36b62260b1 Results: Fix results export. 2024-02-27 15:40:21 +01:00
Pierre-Antoine Rouby 3e085dd7c6 MainWindow: Add minimal info tab. 2024-02-27 15:40:08 +01:00
Pierre-Antoine Rouby a18fd29795 pamhyr: Fix Pep8. 2024-02-26 16:37:09 +01:00
Pierre-Antoine Rouby 76e4f4b80e Results: Add waiting window at results reading. 2024-02-26 16:33:45 +01:00
Pierre-Antoine Rouby 8466531916 MainWindow: Add BC short cut for sediment. 2024-02-26 14:21:49 +01:00
Pierre-Antoine Rouby a4c5d34720 Pamhyr: Centralize ND and NA translate. 2024-02-21 17:19:50 +01:00
Pierre-Antoine Rouby 2e158f4c1b Pamhyr: Factorize some translate. 2024-02-21 15:52:16 +01:00
Pierre-Antoine Rouby b3a7e7f465 HS: Remove useless print. 2024-02-21 10:53:46 +01:00
Pierre-Antoine Rouby 1a66188411 HS: Minor fixes. 2024-02-21 10:49:47 +01:00
Pierre-Antoine Rouby 485b2cad1e ci: Update mage version. 2024-02-20 17:07:12 +01:00
Pierre-Antoine Rouby 3bcd90f7ae Pamhyr: Update translate. 2024-02-20 16:58:54 +01:00
Pierre-Antoine Rouby 586f17dc2a Results, tools: Fix negative timestamp on Windows and some others fixes. 2024-02-20 15:12:51 +01:00
Pierre-Antoine Rouby 9863b05c30 tools: Fix timestamp to pamhyr notation function for Windows. 2024-02-20 14:25:23 +01:00
Pierre-Antoine Rouby a9f92637ca Solver: Mage: Fix ST file name. 2024-02-20 12:07:30 +01:00
Pierre-Antoine Rouby 6b8b1b8e1e Geometry: Fix update. 2024-02-20 11:29:51 +01:00
Pierre-Antoine Rouby c3c5802be2 Solver: Mage: Fix ST file name export. 2024-02-20 11:14:39 +01:00
Pierre-Antoine Rouby ab776f15f4 Friction: Connect to geometry update. 2024-02-20 10:53:22 +01:00
Pierre-Antoine Rouby ebc3e938bf Results: Fix KPC update where no sediment. 2024-02-20 10:36:18 +01:00
Pierre-Antoine Rouby 9cc3bb23c0 IC: Propagate update, update at gemometry change and minor change. 2024-02-20 10:25:04 +01:00
Pierre-Antoine Rouby d2f275c49f Results: Add export function. 2024-02-19 16:44:37 +01:00
Pierre-Antoine Rouby aec31df520 Results: Change default tab. 2024-02-19 15:47:59 +01:00
Pierre-Antoine Rouby 76745dc9d0 Pamhyr: Fix Pep8 and minor change. 2024-02-19 15:44:04 +01:00
Pierre-Antoine Rouby 25dce4d386 Results: Add bedload sediment results to KPC plot. 2024-02-19 15:38:06 +01:00
Pierre-Antoine Rouby 1c736df647 Results: Add overflow to KPC plot. 2024-02-19 14:41:12 +01:00
Pierre-Antoine Rouby aeae8fb710 Results: Update plot XY and add overflow on this plot. 2024-02-19 14:32:10 +01:00
Pierre-Antoine Rouby 6055065e27 Results: Update plot KPC. 2024-02-19 10:57:58 +01:00
Pierre-Antoine Rouby a08b2c77d6 Results: Update AC plot with max water level. 2024-02-19 10:19:46 +01:00
Pierre-Antoine Rouby f9a099a284 Results: Hydrograph: Add legend. 2024-02-19 09:46:43 +01:00
Pierre-Antoine Rouby 62fcafa982 Results: Renew hydrograph. 2024-02-16 16:56:46 +01:00
Pierre-Antoine Rouby 065d94eb4a Results: Add 'raw_data' tab and delete sediment tab. 2024-02-16 15:44:50 +01:00
Pierre-Antoine Rouby 7760181baa Friction: Apply new PamhyrPlot features. 2024-02-16 14:35:37 +01:00
Pierre-Antoine Rouby 9302d1fabc SL: Apply new PamhyrPlot features. 2024-02-16 14:16:58 +01:00
Pierre-Antoine Rouby d1d63c8c29 Reservoir: Apply new PamhyrPlot features. 2024-02-16 11:22:29 +01:00
Pierre-Antoine Rouby bfd166b717 IC: Apply new PamhyrPlot features. 2024-02-16 11:16:18 +01:00
Pierre-Antoine Rouby 4f747f8fa7 HS: Apply new PamhyrPlot features. 2024-02-16 10:58:10 +01:00
Pierre-Antoine Rouby 2111307965 LC: Update plot with PmahyrPlot new features. 2024-02-16 10:18:29 +01:00
Pierre-Antoine Rouby 065e1f063f Pamhyr: Change time edition and plot display (exp BC). 2024-02-16 10:04:22 +01:00
Pierre-Antoine Rouby 5226836211 Pamhyr: Fix Pep8. 2024-02-14 17:03:05 +01:00
Pierre-Antoine Rouby c58dc5785a Plot: Add a default colors set and delete geo:plot_xy dependence on geo:plot_ac. 2024-02-14 16:44:41 +01:00
Pierre-Antoine Rouby 30d76da32f Geometry: Renew Plot AC. 2024-02-14 16:23:48 +01:00
Pierre-Antoine Rouby 876521fdea Geometry: Renew PlotKPC. 2024-02-14 15:49:20 +01:00
Pierre-Antoine Rouby e1e5279366 Plot: Start refactoring with Geometry.PlotXY at exemple. 2024-02-14 15:15:08 +01:00
Pierre-Antoine Rouby 32886c5034 Configure: Remove unused configuration. 2024-02-14 09:37:35 +01:00
Pierre-Antoine Rouby 41e14208e4 SQL: Move SQL class to separate file. 2024-02-14 09:29:34 +01:00
Pierre-Antoine Rouby b79fc28a5f ListedSubWindow: Logging minor change. 2024-02-13 13:33:31 +01:00
Pierre-Antoine Rouby ef72ff6903 doc: Fix Pep8. 2024-02-13 11:51:45 +01:00
Pierre-Antoine Rouby 82e8b510ca Pamhyr: Close sub windows at model close. 2024-02-13 11:46:06 +01:00
Pierre-Antoine Rouby 8109ddf78f Pamhyr: Chose to close all subwindow at window close. 2024-02-13 11:43:24 +01:00
Pierre-Antoine Rouby f0f6ad17e2 Pamhyr: Add recursive window activation. 2024-02-13 11:32:16 +01:00
Pierre-Antoine Rouby 83d53a46fb Pamhyr: Add windows list recursively. 2024-02-13 11:25:53 +01:00
Pierre-Antoine Rouby a8c8e14d6a MainWindow: Add windows menu with list of windows (depth 1). 2024-02-13 11:12:25 +01:00
Pierre-Antoine Rouby e96e291ec4 Pamhyr: Add update propagation mechanism. 2024-02-13 09:23:36 +01:00
Pierre-Antoine Rouby e03ebedfdf tools: licence.el: Minor change. 2024-02-12 17:08:09 +01:00
Pierre-Antoine Rouby deaf114fa3 Pamhyr: Update licence. 2024-02-12 17:06:13 +01:00
Pierre-Antoine Rouby 0071ef22d7 Study: Add window title translate. 2024-02-12 15:43:34 +01:00
Pierre-Antoine Rouby 58924aaf3a Stricklers: Add window title translate. 2024-02-12 15:41:34 +01:00
Pierre-Antoine Rouby d6af6ce486 SP: Add window title translate. 2024-02-12 15:36:30 +01:00
Pierre-Antoine Rouby b1d0e6dc55 SL: Add windows title translate. 2024-02-12 15:34:30 +01:00
Pierre-Antoine Rouby a200adb51a RunSolver: Add windows title translate. 2024-02-12 15:18:01 +01:00
Pierre-Antoine Rouby 6ea00200b0 Results: Add window title translate. 2024-02-12 15:12:34 +01:00
Pierre-Antoine Rouby 5cf03d7ae0 Results: Minor change. 2024-02-12 15:10:47 +01:00
Pierre-Antoine Rouby 3b5fbdabd4 About: Update copyright date. 2024-02-12 15:09:53 +01:00
Pierre-Antoine Rouby 18c5d9b480 Results: Add window title translate. 2024-02-12 15:08:40 +01:00
Pierre-Antoine Rouby fe5c050c61 Reservoir: Add windows title translate. 2024-02-12 14:58:10 +01:00
Pierre-Antoine Rouby a7c56e3920 Network: Add window title translate. 2024-02-12 14:50:12 +01:00
Pierre-Antoine Rouby a519228856 LC: Add windows title translate. 2024-02-12 14:46:09 +01:00
Pierre-Antoine Rouby e1f5628a4f IC: Add windows title translate and minor change. 2024-02-12 14:41:05 +01:00
Pierre-Antoine Rouby e4eee1c29e (B)HS: Add windows title translate. 2024-02-12 14:34:33 +01:00
Pierre-Antoine Rouby 0fc5bd3c10 Geometry: Add windows title translate. 2024-02-12 14:26:40 +01:00
Pierre-Antoine Rouby 77de17d7e3 Friction: Add window title translate. 2024-02-12 14:19:31 +01:00
Pierre-Antoine Rouby 87fcf1c610 Debug, Doc: Add windows title translate. 2024-02-12 14:16:12 +01:00
Pierre-Antoine Rouby 8895d0d565 Config: Add windows title translate. 2024-02-12 14:11:02 +01:00
Pierre-Antoine Rouby 6340d9ea0b CheckList: Add window title translate. 2024-02-12 14:02:55 +01:00
Pierre-Antoine Rouby 62aaa276a7 BC: Translate window title. 2024-02-12 13:58:39 +01:00
Pierre-Antoine Rouby 0391775fed Geometry: Meshing: Add lm parameter translate. 2024-02-12 10:53:00 +01:00
Pierre-Antoine Rouby 400b743feb Geometry: Meshing: Fix pep8. 2024-02-09 17:28:29 +01:00
Pierre-Antoine Rouby 754910f514 Geometry: Meshing: Add lm options (no traduction). 2024-02-09 17:27:09 +01:00
Pierre-Antoine Rouby 614285804d Geometry: Meshing: Add "directrices". 2024-02-09 17:19:13 +01:00
Pierre-Antoine Rouby 1b22ba436b Geometry: Meshing: Add cross sections limites. 2024-02-09 17:08:29 +01:00
Pierre-Antoine Rouby 387d462c2c Geometry: Meshing: Update windows with radiobutton instead of checkbox. 2024-02-09 16:47:51 +01:00
Pierre-Antoine Rouby e6178525d7 Geometry: Add missing file. 2024-02-07 17:19:22 +01:00
Pierre-Antoine Rouby a663dc482c Meshing: Add lplan and linear to meching options. 2024-02-07 17:09:50 +01:00
Pierre-Antoine Rouby b913d76972 Meshing: Mage: Change API of mailleurTT for the next mage version. 2024-02-07 16:56:18 +01:00
Pierre-Antoine Rouby ab276db78c Meshing: Add minimal meshing option dialog. 2024-02-07 16:04:59 +01:00
Pierre-Antoine Rouby 34038d2844 README: Replace installation instruction to link to wiki documentation. 2024-02-07 14:28:04 +01:00
Pierre-Antoine Rouby c27ea5c447 Doc: wiki: Add defender message screenshot. 2024-02-07 12:00:14 +01:00
Pierre-Antoine Rouby a8c71e475e Pep8: Fix. 2024-02-07 11:26:29 +01:00
Pierre-Antoine Rouby 41673145ee Translate: Minor change. 2024-02-07 11:23:15 +01:00
Pierre-Antoine Rouby 4757c7d051 Translate: Update. 2024-02-07 11:22:22 +01:00
Pierre-Antoine Rouby 5619b98468 Solver: Run: Close checklist at solver run, resize solver window and fix empty message. 2024-02-07 10:23:02 +01:00
Pierre-Antoine Rouby 630eb98343 SL: Fix default name. 2024-02-07 10:09:18 +01:00
Pierre-Antoine Rouby 5412cb4d2d HS: Add default name. 2024-02-07 10:06:18 +01:00
Pierre-Antoine Rouby 8f46f128ff SL: Add default name. 2024-02-07 10:00:30 +01:00
Pierre-Antoine Rouby 8807d4d98b Reservoir: Add default name. 2024-02-07 09:59:22 +01:00
Pierre-Antoine Rouby 7719f5270d BC, LC: Add default name. 2024-02-07 09:57:23 +01:00
Pierre-Antoine Rouby afb4c1b61e Friction: Add id to friction and default name to stricklers. 2024-02-07 09:52:43 +01:00
Pierre-Antoine Rouby 28bea42b15 River: Add default reach at study creation. 2024-02-07 09:43:13 +01:00
Pierre-Antoine Rouby 955af412ea MainWindow: Make toolbar run launch the lasest solver used and add sc on F6. 2024-02-06 15:21:51 +01:00
Pierre-Antoine Rouby 49dd3c65e1 ci: Set tag message to release message and minor change. 2024-02-05 13:38:54 +01:00
Pierre-Antoine Rouby b2f41f88c9 ci: Minor change to fix sha256 path. 2024-02-05 13:25:19 +01:00
Pierre-Antoine Rouby f3500c7f24 ci: Add sha256 to release artefact. 2024-02-05 11:52:56 +01:00
Pierre-Antoine Rouby 1cbdc9deff ci: Disable PDF of user documentations. 2024-02-05 11:42:43 +01:00
Pierre-Antoine Rouby 89652cc080 ci: Add packages checksum. 2024-02-05 11:39:56 +01:00
Pierre-Antoine Rouby fe3f151e0b ci: Minor change. 2024-02-05 11:18:33 +01:00
Pierre-Antoine Rouby 16caae9d40 ci: Add build check. 2024-02-05 11:14:14 +01:00
Pierre-Antoine Rouby d541becb1a ci: Add antivirus check with clamav scan. 2024-02-02 11:23:39 +01:00
Pierre-Antoine Rouby 21e97d4e30 Solvers: Disable generic solver. 2024-02-02 10:25:41 +01:00
Pierre-Antoine Rouby 9fd9bd95f4 SolverParameters: Minor change. 2024-02-02 10:17:54 +01:00
Pierre-Antoine Rouby fe9c348ee0 Friction: SQL: Fix type name. 2024-01-31 09:57:58 +01:00
Pierre-Antoine Rouby 0d36ba188e Geometry: Export/Import file extention add lower case. 2024-01-31 09:37:17 +01:00
Pierre-Antoine Rouby 5a6d55c2ca MainWindow: Minor change. 2024-01-31 09:27:21 +01:00
Pierre-Antoine Rouby 36ad9562eb MainWindow: Fix save as function. 2024-01-31 09:23:50 +01:00
Pierre-Antoine Rouby bf06a9fe43 Network: Set unselected edges to black. 2024-01-31 09:12:23 +01:00
Pierre-Antoine Rouby 34c9fbd77a pamhyr: Some hot fixes... 2024-01-30 16:23:00 +01:00
265 changed files with 10650 additions and 5147 deletions

No files matched your search

+195 -77
View File
@@ -1,5 +1,5 @@
# .gitlab-ci.yml -- Pamhyr gitlab-ci
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -20,6 +20,8 @@ stages:
- test
- build
- package
- hash
- antivirus
- release
#############
@@ -27,9 +29,9 @@ stages:
#############
variables:
MAGE_VERSION: "v8.3.3"
MAGE_8_VERSION: "v8.3.5"
dl-mage-doc:
dl-mage8-doc:
stage: downloads
tags:
- linux
@@ -38,46 +40,48 @@ dl-mage-doc:
script:
- mkdir -p doc
- cd doc
- curl -L -o mage8.pdf https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_VERSION/downloads/documents/Mage-8_Documentation.pdf
- curl -L -o mage8.pdf https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_8_VERSION/downloads/documents/Mage-8_Documentation.pdf
artifacts:
paths:
- doc/mage8.pdf
dl-mage-linux:
dl-mage8-linux:
stage: downloads
tags:
- linux
rules:
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
script:
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_VERSION/downloads/packages/mage_linux.tgz
- mkdir -p mage-linux
- cd mage-linux
- tar xvf ../mage.tgz
- curl -L -o mage8.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_8_VERSION/downloads/packages/mage_linux.tgz
- mkdir -p mage8-linux
- cd mage8-linux
- tar xvf ../mage8.tgz
artifacts:
paths:
- mage-linux/mage
- mage-linux/mage_extraire
- mage-linux/mailleurTT
- mage-linux/libbief.so
- mage8-linux/mage
- mage8-linux/mage_as7
- mage8-linux/mage_extraire
- mage8-linux/mailleurTT
- mage8-linux/libbief.so
dl-mage-windows:
dl-mage8-windows:
stage: downloads
tags:
- linux
rules:
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
script:
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_VERSION/downloads/packages/mage_windows.tgz
- mkdir -p mage-windows
- cd mage-windows
- tar xvf ../mage.tgz
- curl -L -o mage8.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_8_VERSION/downloads/packages/mage_windows.tgz
- mkdir -p mage8-windows
- cd mage8-windows
- tar xvf ../mage8.tgz
artifacts:
paths:
- mage-windows/mage.exe
- mage-windows/mage_extraire.exe
- mage-windows/mailleurTT.exe
- mage-windows/libbief.dll
- mage8-windows/mage.exe
- mage8-windows/mage_as7.exe
- mage8-windows/mage_extraire.exe
- mage8-windows/mailleurTT.exe
- mage8-windows/libbief.dll
#############
# CONFIGURE #
@@ -148,23 +152,22 @@ test-pep8:
# BUILD #
#########
build-users-doc:
stage: build
tags:
- linux
needs:
- job: set-version
artifacts: true
script:
- cd ./doc/users/
- ./build.sh
artifacts:
paths:
- doc/users/documentation.pdf
- doc/users/documentation.html
- doc/users/images/
allow_failure: true
# build-users-doc:
# stage: build
# tags:
# - linux
# needs:
# - job: set-version
# artifacts: true
# script:
# - cd ./doc/users/
# - ./build.sh
# artifacts:
# paths:
# - doc/users/documentation.pdf
# - doc/users/documentation.html
# - doc/users/images/
# allow_failure: true
build-td:
stage: build
@@ -221,9 +224,9 @@ build-linux:
rules:
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
needs:
- job: dl-mage-linux
- job: dl-mage8-linux
artifacts: true
- job: dl-mage-doc
- job: dl-mage8-doc
artifacts: true
- job: set-version
artifacts: true
@@ -231,8 +234,8 @@ build-linux:
artifacts: true
- job: build-developers-doc
artifacts: true
- job: build-users-doc
artifacts: true
# - job: build-users-doc
# artifacts: true
- job: build-td
artifacts: true
script:
@@ -248,28 +251,27 @@ build-linux:
- pyinstaller -y --paths linux-venv/lib/python3.8/site-packages ../src/pamhyr.py
# Create directory
- mkdir -p pamhyr
- mkdir -p pamhyr/pamhyr
- mkdir -p pamhyr/pamhyr/_internal
- mkdir -p pamhyr/_internal
# Copy Pamhyr info
- cp -v ../VERSION pamhyr/pamhyr/_internal/
- cp -v ../AUTHORS pamhyr/pamhyr/_internal/
- cp -v ../LICENSE pamhyr/pamhyr/_internal/
- cp -v ../src/motd.txt pamhyr/pamhyr/_internal/
- cp -v ../VERSION pamhyr/_internal/
- cp -v ../AUTHORS pamhyr/_internal/
- cp -v ../LICENSE pamhyr/_internal/
- cp -v ../src/motd.txt pamhyr/_internal/
# Copy mage
- mkdir -p pamhyr/mage
- cp -v ../mage-linux/* pamhyr/mage/
- mkdir -p pamhyr/mage8
- cp -v ../mage8-linux/* pamhyr/mage8/
# Copy Pamhyr
- cp -r dist/pamhyr pamhyr/
- cp -r dist/pamhyr/* pamhyr/
# Copy Pamhyr resources
- mkdir -p pamhyr/pamhyr/_internal/View
- mkdir -p pamhyr/pamhyr/_internal/View/ui
- mkdir -p pamhyr/pamhyr/_internal/View/ui/Widgets
- cp -r ../src/View/ui/*.ui pamhyr/pamhyr/_internal/View/ui/
- cp -r ../src/View/ui/ressources/ pamhyr/pamhyr/_internal/View/ui
- cp -r ../src/View/ui/Widgets/*.ui pamhyr/pamhyr/_internal/View/ui/Widgets
- mkdir -p pamhyr/_internal/View
- mkdir -p pamhyr/_internal/View/ui
- mkdir -p pamhyr/_internal/View/ui/Widgets
- cp -r ../src/View/ui/*.ui pamhyr/_internal/View/ui/
- cp -r ../src/View/ui/ressources/ pamhyr/_internal/View/ui
- cp -r ../src/View/ui/Widgets/*.ui pamhyr/_internal/View/ui/Widgets
# Copy lang
- mkdir -p pamhyr/pamhyr/_internal/lang
- cp -r ../src/lang/*.qm pamhyr/pamhyr/_internal/lang
- mkdir -p pamhyr/_internal/lang
- cp -r ../src/lang/*.qm pamhyr/_internal/lang
# Copy tests cases
- mkdir -p pamhyr/tests_cases/
- mkdir -p pamhyr/tests_cases/Saar
@@ -297,10 +299,6 @@ build-linux:
# Copy TP charriage
- mkdir -p pamhyr/doc/TP_charriage/
- cp ../doc/users/TP_charriage/* pamhyr/doc/TP_charriage
# Create running script
- echo "#!/bin/sh" > pamhyr/Pamhyr2
- echo "./pamhyr/pamhyr $@" >> pamhyr/Pamhyr2
- chmod u+x pamhyr/Pamhyr2
artifacts:
paths:
- linux/pamhyr
@@ -312,9 +310,9 @@ build-windows:
rules:
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
needs:
- job: dl-mage-windows
- job: dl-mage8-windows
artifacts: true
- job: dl-mage-doc
- job: dl-mage8-doc
artifacts: true
- job: set-version
artifacts: true
@@ -322,18 +320,20 @@ build-windows:
artifacts: true
- job: build-developers-doc
artifacts: true
- job: build-users-doc
artifacts: true
# - job: build-users-doc
# artifacts: true
- job: build-td
artifacts: true
script:
- mkdir windows
- cd windows
# Setup env
- python -m pip install -U pip
- python -m pip install -r ..\requirements.txt
- python -m pip install -U -r ..\requirements.txt
# Run Pyinstaller
- pyinstaller -y ..\src\pamhyr.py
# - pyinstaller --noconsole -y ..\src\pamhyr.py
- pyinstaller --hide-console hide-early -y ..\src\pamhyr.py
# Create directory
- mkdir pamhyr
- dir
@@ -403,6 +403,111 @@ windows-package-exe:
- copy ..\packages\pamhyr.nsi pamhyr.nsi
- .\make-windows-exe.bat
########
# HASH #
########
linux-build-hash:
stage: hash
tags:
- release
- linux
needs:
- job: build-linux
artifacts: true
rules:
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
script:
- cd linux
- sha256sum -b pamhyr/pamhyr > pamhyr/pamhyr.sha256
artifacts:
paths:
- linux/pamhyr/pamhyr.sha256
windows-build-hash:
stage: hash
tags:
- release
- linux
needs:
- job: build-windows
artifacts: true
rules:
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
script:
- cd windows
- sha256sum -b pamhyr/pamhyr.exe > pamhyr/pamhyr.exe.sha256
artifacts:
paths:
- windows/pamhyr/pamhyr.exe.sha256
pkg-hash:
stage: hash
tags:
- release
- linux
needs:
- job: linux-package-tar
artifacts: true
- job: windows-package-zip
artifacts: true
- job: windows-package-exe
artifacts: true
rules:
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_TAG
script:
- cd windows
- sha256sum -b pamhyr-windows.exe > pamhyr-windows.exe.sha256
- sha256sum -b pamhyr-windows.zip > pamhyr-windows.zip.sha256
- cd ..
- cd linux
- sha256sum -b pamhyr-gnulinux.tar.xz > pamhyr-gnulinux.tar.xz.sha256
artifacts:
paths:
- windows/pamhyr-windows.exe.sha256
- windows/pamhyr-windows.zip.sha256
- linux/pamhyr-gnulinux.tar.xz.sha256
#############
# ANTIVIRUS #
#############
build-check-clamav:
stage: antivirus
tags:
- release
- linux
needs:
- job: build-linux
artifacts: true
- job: build-windows
artifacts: true
rules:
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
script:
- cd packages
- ./clamav-scan.sh builds
allow_failure: true
pkg-check-clamav:
stage: antivirus
tags:
- release
- linux
needs:
- job: linux-package-tar
artifacts: true
- job: windows-package-zip
artifacts: true
- job: windows-package-exe
artifacts: true
rules:
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_TAG
script:
- cd packages
- ./clamav-scan.sh packages
allow_failure: true
###########
# RELEASE #
###########
@@ -419,10 +524,12 @@ tag-release:
artifacts: true
- job: windows-package-exe
artifacts: true
- job: build-users-doc
artifacts: true
# - job: build-users-doc
# artifacts: true
- job: build-developers-doc
artifacts: true
- job: pkg-hash
artifacts: true
rules:
- if: $CI_COMMIT_TAG
artifacts:
@@ -430,33 +537,44 @@ tag-release:
- linux/pamhyr-gnulinux.tar.xz
- windows/pamhyr-windows.zip
- windows/pamhyr-windows.exe
- linux/pamhyr-gnulinux.tar.xz.sha256
- windows/pamhyr-windows.zip.sha256
- windows/pamhyr-windows.exe.sha256
- doc/dev/documentation.pdf
- doc/users/documentation.pdf
# - doc/users/documentation.pdf
script:
- cd packages
release:
name: '$CI_COMMIT_TAG'
description: 'Automatic release from tag $CI_COMMIT_TAG'
description: '$CI_COMMIT_TAG_MESSAGE'
tag_name: '$CI_COMMIT_TAG'
ref: '$CI_COMMIT_SHA'
assets:
links:
- name: 'GNU/Linux CHECKSUM SHA256 (tar.xz)'
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/linux/pamhyr-gnulinux.tar.xz.sha256'
filepath: '/linux/pamhyr-gnulinux.tar.xz.sha256'
link_type: 'package'
- name: 'GNU/Linux (tar.xz)'
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/linux/pamhyr-gnulinux.tar.xz'
filepath: '/linux/pamhyr-gnulinux.tar.xz'
link_type: 'package'
- name: 'Windows CHECKSUM SHA256 (exe)'
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/windows/pamhyr-windows.exe.sha256'
filepath: '/windows/pamhyr-windows.exe.sha256'
link_type: 'package'
- name: 'Windows (exe)'
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/windows/pamhyr-windows.exe'
filepath: '/windows/pamhyr-windows.exe'
link_type: 'package'
- name: 'Windows CHECKSUM SHA256 (zip)'
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/windows/pamhyr-windows.zip.sha256'
filepath: '/windows/pamhyr-windows.zip.sha256'
link_type: 'package'
- name: 'Windows (zip)'
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/windows/pamhyr-windows.zip'
filepath: '/windows/pamhyr-windows.zip'
link_type: 'package'
- name: 'User documentations (pdf)'
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/doc/users/documentation.pdf'
filepath: '/doc/users/documentation.pdf'
link_type: 'other'
- name: 'Dev documentations (pdf)'
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/doc/dev/documentation.pdf'
filepath: '/doc/dev/documentation.pdf'
+2 -2
View File
@@ -1,3 +1,3 @@
Sylvain COULIBALY, INRAE, 2020 - 2022
Théophile TERRAZ, INRAE, 2022 - 2023
Pierre-Antoine ROUBY, INRAE, 2023
Théophile TERRAZ, INRAE, 2022 - 2024
Pierre-Antoine ROUBY, INRAE, 2023 - 2024
+2 -12
View File
@@ -25,21 +25,11 @@ for more details.
### GNU/Linux
Downloads the [last
realease](https://gitlab.irstea.fr/theophile.terraz/pamhyr/-/releases/permalink/latest)
GNU/Linux binary archive.
```shell
tar xf pamhyr-gnulinux.tar.xz
cd pamhyr
./Pamhyr2
```
[See documentation](https://gitlab.irstea.fr/theophile.terraz/pamhyr/-/wikis/home/en/Install%20on%20GNULinux)
### Windows
Downloads the [last
realease](https://gitlab.irstea.fr/theophile.terraz/pamhyr/-/releases/permalink/latest)
Windows installer or ZIP archive.
[See documentation](https://gitlab.irstea.fr/theophile.terraz/pamhyr/-/wikis/home/en/Install%20on%20Windows)
### From source code
+82 -45
View File
@@ -1,5 +1,5 @@
# documentation.org -- Pamhyr developers documentation
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -369,6 +369,7 @@ of Bar (Listing [[sql-bar]] and [[sql-foo]]).
CREATE TABLE bar (
id INTEGER NOT NULL PRIMARY KEY,
x INTEGER NOT NULL,
y INTEGER NOT NULL,
foo_id INTEGER NOT NULL,
FOREIGN KEY(foo_id) REFERENCES foo(id),
)""")
@@ -455,6 +456,15 @@ of Bar (Listing [[sql-bar]] and [[sql-foo]]).
bar._sql_save(execute, data=data)
#+end_src
Let see the results database scheme for Pamhyr2 at version v0.0.7 in
Figure [[sql_schema]].
#+NAME: sql_schema
#+ATTR_LATEX: :width 16cm
#+CAPTION: SQLite database scheme at Pamhyr2 version v0.0.7 (generate with [[https://gitlab.com/Screwtapello/sqlite-schema-diagram]])
[[./images/schema_v0.0.7.png]]
[fn:sqlite] The SQLite web site: https://www.sqlite.org/index.html
(last access 2023-09-20)
@@ -538,44 +548,44 @@ generic value from optional parameters, for examples:
#+NAME: window
#+CAPTION: Example of Pamhyr2 window
#+begin_src python :python python3 :results output :noweb yes
from View.Tools.PamhyrWindow import PamhyrWindow
from View.My.Translate import MyTranslate
from View.My.Table import MyTableModel
from View.Tools.PamhyrWindow import PamhyrWindow
from View.My.Translate import MyTranslate
from View.My.Table import MyTableModel
class MyWindow(PamhyrWindow):
_pamhyr_ui = "MyUI"
_pamhyr_name = "My window"
class MyWindow(PamhyrWindow):
_pamhyr_ui = "MyUI"
_pamhyr_name = "My window"
def __init__(self, my_data=None,
study=None, config=None,
parent=None):
self._my_data = my_data
def __init__(self, study=None, config=None,
my_data=None,
parent=None):
self._my_data = my_data
super(MyWindow, self).__init__(
# Window title
title = self._pamhyr_name + " - " + study.name,
# Window standard data
study = study, config = config,
trad = MyTranslate(),
parent = parent,
# Activate undo/redo and copy/paste shortcut
options = ["undo", "copy"]
)
super(MyWindow, self).__init__(
# Window title
title = self._pamhyr_name + " - " + study.name,
# Window standard data
study = study, config = config,
trad = MyTranslate(),
parent = parent,
# Activate undo/redo and copy/paste shortcut
options = ["undo", "copy"]
)
# Add custom data to hash window computation
self._hash_data.append(self._my_data)
# Add custom data to hash window computation
self._hash_data.append(self._my_data)
# Setup custom window components
self.setup_table()
self.setup_connections()
# Setup custom window components
self.setup_table()
self.setup_connections()
def setup_table(self):
# Init table(s)...
def setup_table(self):
# Init table(s)...
def setup_connections(self):
# Init action connection(s)...
def setup_connections(self):
# Init action connection(s)...
# ...
# ...
#+end_src
Typically we called method =setup_*=, the method to initialize some
@@ -661,11 +671,13 @@ creation, this stack is accessible at =self._undo_stack=.
*** Plot
To define a new plot you can create a class who inherit to APlot. The
creator need threee argument:
To define a new plot you can create a class who inherit to
PamhyrPlot. The creator need at leaste five argument:
- A =canvas= of type =MplCanvas=
- A (optional) =trad= of type =PamhyrTranslate=
- A =data= used in =draw= and =update= to create and update the plot
- A optional =toolbar= of type =PamhyrToolbar=
- A =parent= window
This class must implement two method =draw= and =update=, the first
method to draw the plot from scratch, the second to update the plot if
data has changed.
@@ -673,19 +685,36 @@ data has changed.
#+begin_src python :python python3 :results output :noweb yes
from View.Tools.PamhyrPlot import PamhyrPlot
class MyPlot(APlot):
def __init__(self, canvas=None, data=None, toolbar=None):
class MyPlot(PamhyrPlot):
def __init__(self, canvas=None, trad=None, toolbar=None
data=None, parent=None):
super(MyPlot, self).__init__(
canvas=canvas,
trad=trad,
data=data,
toolbar=toolbar
toolbar=toolbar,
parent=parent
)
self.label_x = self._trad["x"]
self.label_y = self._trad["y"]
# Optional configuration
self._isometric_axis = False
self._auto_relim_update = True
self._autoscale_update = True
def draw(self):
# Draw function code...
def update(self, ind = None):
def update(self):
# Update function code...
def clear(self):
# Clear plot values...
# ...
#+end_src
** Solver
@@ -745,7 +774,7 @@ execute a code on distant computer, for example, over ssh.
style=dashed;
subgraph cluster021 {
label="Solver Classes";
classSolverM7[label="Mage7", fillcolor=6];
//classSolverM7[label="Mage7", fillcolor=6];
classSolverM8[label="Mage8", fillcolor=6];
classSolverR[label="RubarBE", fillcolor=6];
}
@@ -828,7 +857,7 @@ solver and get results:
- (2.1) The solver read the input file(s)
- (2.2) The solver compute results and write it to solver output
file(s)
- (3) Pamhyr2 create a Reuslts
- (3) Pamhyr2 create a =Results= object
- (3.1) The Pamhyr2 solver class read solver output file(s) and
complete Results with readed data
@@ -958,8 +987,16 @@ different methods:
** Unit tests
The unit tests is actually not implemented in Pamhyr2, it is a *work
in progress*.
A very small part of Pamhyr2 has unit test. This part is limited to the Model.
#+begin_src shell
python3 -m venv test
. test test/bin/activate
pip3 install -U -r ./full-requirements.txt
cd src/
python3 -Walways -m unittest discovert -v -t .
#+end_src
** The debug mode
@@ -970,14 +1007,14 @@ line:
./Pamhyr2 debug
#+end_src
This mode add some log and add two action in main window menu:
"About/Debug" open a window with Python Repl in current Python
environement, and "About/Debug SQLite" who open the application
This mode add some log and add two action in main window menu: "About
> Debug" open a window with Python Repl in current Python
environement, and "About > Debug SQLite" who open the application
SQLiteBrowser (if installed) on current Study to explore the study
data base file.
#+NAME: debug-repl
#+ATTR_LATEX: :width 12cm
#+ATTR_LATEX: :width 14cm
#+CAPTION: Pamhyr2 debug Python REPL
[[./images/python-debug-repl.png]]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

+2 -1
View File
@@ -4,9 +4,10 @@ PyQt5-sip==12.12.2
PyQtWebEngine==5.15.6
QScintilla>=2.14.1
pyqtgraph>=0.12.1
matplotlib>=3.4.1
matplotlib>=3.7.1
numpy>=1.24.2
colorama>=0.4.3
pyinstaller>=5.11.0
shapely>=2.0.1
lxml>=4.9.3
platformdirs>=4.2.0
+21
View File
@@ -0,0 +1,21 @@
#! /bin/bash
set +x
OPTS="-r -a -i"
if [ "$1" == "builds" ]; then
FILES="../windows/ ../linux/"
else
FILES="../windows/pamhyr-windows.exe ../windows/pamhyr-windows.zip ../linux/pamhyr-gnulinux.tar.xz"
fi
clamscan $OPTS $FILES | tee clamav.log
RES=$(cat clamav.log | grep "Infected files: 0")
if [ -z "$RES" ]; then
echo "Infected files"
exit -1
else
echo "OK"
exit 0
fi
+3
View File
@@ -0,0 +1,3 @@
@echo off
start cmd /c pamhyr.exe debug
+3
View File
@@ -0,0 +1,3 @@
#! /bin/sh
./pamhyr debug
+19 -18
View File
@@ -16,34 +16,35 @@ rem along with this program. If not, see <https://www.gnu.org/licenses/>.
@ECHO ON
mkdir pamhyr\pamhyr\_internal
xcopy /s /e /y dist\pamhyr pamhyr\pamhyr
mkdir pamhyr\_internal
xcopy /s /e /y dist\pamhyr pamhyr
rem Copy data
mkdir pamhyr\pamhyr\_internal\lang
mkdir pamhyr\pamhyr\_internal\View\ui\ressources
mkdir pamhyr\pamhyr\_internal\View\ui\Widgets
mkdir pamhyr\_internal\lang
mkdir pamhyr\_internal\View\ui\ressources
mkdir pamhyr\_internal\View\ui\Widgets
rem UI
copy /y ..\src\View\ui\ressources\ pamhyr\pamhyr\_internal\View\ui\ressources
copy /y ..\src\View\ui\Widgets\*.ui pamhyr\pamhyr\_internal\View\ui\Widgets
copy /y ..\src\View\ui\*.ui pamhyr\pamhyr\_internal\View\ui\
copy /y ..\src\View\ui\ressources\ pamhyr\_internal\View\ui\ressources
copy /y ..\src\View\ui\Widgets\*.ui pamhyr\_internal\View\ui\Widgets
copy /y ..\src\View\ui\*.ui pamhyr\_internal\View\ui\
rem Lang
copy /y ..\src\lang\*.qm pamhyr\pamhyr\_internal\lang\
copy /y ..\src\lang\*.qm pamhyr\_internal\lang\
rem Information
copy /y ..\VERSION pamhyr\pamhyr\_internal
copy /y ..\AUTHORS pamhyr\pamhyr\_internal
copy /y ..\LICENSE pamhyr\pamhyr\_internal
copy /y ..\src\motd.txt pamhyr\pamhyr\_internal
copy /y ..\VERSION pamhyr\_internal
copy /y ..\AUTHORS pamhyr\_internal
copy /y ..\LICENSE pamhyr\_internal
copy /y ..\src\motd.txt pamhyr\_internal
rem MAGE
mkdir pamhyr\mage
copy /y ..\mage-windows\mage.exe pamhyr\mage\
copy /y ..\mage-windows\mage_extraire.exe pamhyr\mage\
copy /y ..\mage-windows\mailleurTT.exe pamhyr\mage\
copy /y ..\mage-windows\libbief.dll pamhyr\mage\
mkdir pamhyr\mage8
copy /y ..\mage8-windows\mage.exe pamhyr\mage8\
copy /y ..\mage8-windows\mage_as7.exe pamhyr\mage8\
copy /y ..\mage8-windows\mage_extraire.exe pamhyr\mage8\
copy /y ..\mage8-windows\mailleurTT.exe pamhyr\mage8\
copy /y ..\mage8-windows\libbief.dll pamhyr\mage8\
rem Copy tests_cases
mkdir pamhyr\tests_cases
+3 -3
View File
@@ -5,7 +5,7 @@
Name "Pamhyr2"
OutFile "pamhyr-windows.exe"
LicenseData "pamhyr\pamhyr\_internal\LICENSE"
LicenseData "pamhyr\_internal\LICENSE"
LicenseText "I Agree"
RequestExecutionLevel admin
@@ -41,12 +41,12 @@ SectionEnd
Section "Start Menu Shortcuts"
CreateDirectory "$SMPROGRAMS\Pamhyr2"
CreateShortcut "$SMPROGRAMS\Pamhyr2\Uninstall.lnk" "$INSTDIR\uninstall.exe"
CreateShortcut "$SMPROGRAMS\Pamhyr2\Pamhyr2.lnk" "$INSTDIR\pamhyr\pamhyr.exe"
CreateShortcut "$SMPROGRAMS\Pamhyr2\Pamhyr2.lnk" "$INSTDIR\pamhyr.exe"
SectionEnd
Section "Desktop Shortcuts"
SetShellVarContext all
CreateShortcut "$desktop\Pamhyr2.lnk" "$instdir\pamhyr\pamhyr.exe"
CreateShortcut "$desktop\Pamhyr2.lnk" "$instdir\pamhyr.exe"
SectionEnd
Section "Uninstall"
+2 -1
View File
@@ -4,9 +4,10 @@ PyQt5-sip==12.12.2
#PyQtWebEngine==5.15.6
QScintilla>=2.14.1
pyqtgraph>=0.12.1
matplotlib>=3.4.1
matplotlib>=3.7.1
numpy>=1.24.2
colorama>=0.4.3
pyinstaller>=5.11.0
shapely>=2.0.1
lxml>=4.9.3
platformdirs>=4.2.0
+32 -2
View File
@@ -1,5 +1,5 @@
# Checker.py -- Pamhyr abstract checker class
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,23 +16,53 @@
# -*- coding: utf-8 -*-
import logging
from enum import Enum
from Modules import Modules
from Model.Except import NotImplementedMethodeError
logger = logging.getLogger()
class STATUS(Enum):
UNKNOWN = -1
OK = 0
WARNING = 1
ERROR = 2
UNKNOWN = 999
def __eq__(self, y):
return self.value == y.value
def __gt__(self, y):
return self.value > y.value
def __or__(self, y):
v = [self, y]
r = self.OK
if self.UNKNOWN in v:
r = self.UNKNOWN
if self.ERROR in v:
r = self.ERROR
if self.WARNING in v:
r = self.WARNING
logger.debug(f"CHECKER: STATUS: {self} | {y} = {r}")
return r
class AbstractModelChecker(object):
def __init__(self):
self._name = ""
self._description = ""
self._solver = "study"
self._modules = Modules.NONE
self.reset()
def reset(self):
self._status = STATUS.UNKNOWN
self._summary = "Unknown"
+10 -3
View File
@@ -1,5 +1,5 @@
# Mage.py -- Pamhyr MAGE checkers
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,6 +23,8 @@ from tools import flatten, timer
from PyQt5.QtCore import QCoreApplication
from Modules import Modules
from Checker.Checker import AbstractModelChecker, STATUS
from Checker.Study import StudyGeometryChecker
@@ -30,7 +32,7 @@ _translate = QCoreApplication.translate
class MageNetworkGraphChecker(AbstractModelChecker):
def __init__(self, connectivity=True):
def __init__(self, connectivity=True, version="mage8"):
super(MageNetworkGraphChecker, self).__init__()
self._mode_conn = connectivity
@@ -44,6 +46,8 @@ class MageNetworkGraphChecker(AbstractModelChecker):
"Checker", f"Mage network graph {mode} checker")
self._description = _translate(
"Checker", "Check if the network graph is valid")
self._solver = version
self._modules = Modules.NETWORK
@timer
def _connectivity(self, summary, status, graph):
@@ -199,7 +203,7 @@ class MageNetworkGraphChecker(AbstractModelChecker):
class MageGeometryGuideLineChecker(StudyGeometryChecker):
def __init__(self):
def __init__(self, version="mage8"):
super(MageGeometryGuideLineChecker, self).__init__()
self._name = _translate("Checker", "Mage geometry guide line checker")
@@ -208,6 +212,9 @@ class MageGeometryGuideLineChecker(StudyGeometryChecker):
"Check if exists geometry guide line is correctly defined \
for each reaches of the study"
)
self._solver = version
self._modules = Modules.GEOMETRY
self._reachs = []
def run(self, study):
+9 -3
View File
@@ -1,5 +1,5 @@
# Study.py -- Pamhyr study checkers
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@ import time
from PyQt5.QtCore import QCoreApplication
from Modules import Modules
from Checker.Checker import AbstractModelChecker, STATUS
_translate = QCoreApplication.translate
@@ -31,7 +32,9 @@ class StudyNetworkReachChecker(AbstractModelChecker):
self._name = _translate("Checker", "Study network reach checker")
self._description = _translate(
"Checker", "Check if exists at least one reach for study")
"Checker", "Check if exists at least one reach for study"
)
self._modules = Modules.NETWORK
def run(self, study):
if study is None:
@@ -62,7 +65,10 @@ class StudyGeometryChecker(AbstractModelChecker):
self._name = _translate("Checker", "Study geometry checker")
self._description = _translate(
"Checker", "Check if exists geometry for each reach of study")
"Checker", "Check if exists geometry for each reach of study"
)
self._modules = Modules.GEOMETRY
self._reachs = []
def run(self, study):
+1 -1
View File
@@ -1,5 +1,5 @@
# AMeshingTool.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+57 -12
View File
@@ -1,5 +1,5 @@
# Mage.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ from ctypes import (
)
from PyQt5.QtCore import QProcess
from tools import logger_color_red, logger_color_reset
from tools import logger_color_red, logger_color_reset, logger_exception
from Meshing.AMeshingTool import AMeshingTool
logger = logging.getLogger()
@@ -65,6 +65,10 @@ class MeshingWithMage(AMeshingTool):
)
)
@classmethod
def _path(cls):
return cls._exe_path()
def _init_c_init_bief_from_geo_file(self):
self._c_init_bief_from_geo_file = getattr(
self._bief_lib, 'c_init_bief_from_geo_file'
@@ -274,15 +278,25 @@ class MeshingWithMageMailleurTT(AMeshingTool):
return os.path.abspath(
os.path.join(
os.path.dirname(__file__),
"..", "..", "..", "mage", f"mailleurTT{ext}"
"..", "..", "mage8", f"mailleurTT{ext}"
)
)
@classmethod
def _path(cls):
return cls._exe_path()
###########
# Meshing #
###########
def meshing(self, reach, step: float = 50):
def meshing(self, reach,
step: float = 50,
limites=[-1, -1],
directrices=['un', 'np'],
lplan: bool = False,
lm: int = 3,
linear: bool = False):
if reach is None or len(reach.profiles) == 0:
return reach
@@ -291,22 +305,51 @@ class MeshingWithMageMailleurTT(AMeshingTool):
st_file = self.export_reach_to_st(reach, tmp)
m_file = st_file.rsplit(".ST", 1)[0] + ".M"
os.sync()
proc = QProcess()
proc.setWorkingDirectory(tmp)
logger.debug(f"mailleurTT '{st_file}, {m_file}, {str(step)}'")
lplan = 1 if lplan else 0
linear = 1 if linear else 0
logger.info(
f"! {self._exe_path()} {st_file} {m_file} " +
f"{str(step)} " +
f"{limites[0]} {limites[1]} " +
f"{directrices[0]} {directrices[1]} " +
f"{lplan} {lm} {linear}"
)
proc.start(
self._exe_path(), [st_file, m_file, str(step)]
self._exe_path(),
list(map(
str,
[
st_file, m_file, step,
limites[0], limites[1],
directrices[0], directrices[1],
lplan, lm, linear
]
))
)
proc.waitForFinished()
errors = proc.readAllStandardError()
if len(errors) != 0:
if proc.exitCode() != 0:
logger.error(
f"{logger_color_red()}" +
f"MailleurTT error: {proc.exitCode()}" +
f"{logger_color_reset()}"
)
outputs = proc.readAllStandardOutput()
logger.debug(outputs)
errors = proc.readAllStandardError()
logger.error(
f"{logger_color_red()}{errors}{logger_color_reset()}"
)
else:
self.import_m_file(reach, m_file)
return reach
def export_reach_to_st(self, reach, tmp):
@@ -318,7 +361,9 @@ class MeshingWithMageMailleurTT(AMeshingTool):
return tmp_st
def import_m_file(self, reach, m):
reach.purge()
logger.debug(f"meshing: Import geometry from {m}")
reach.import_geometry(m)
if os.path.exists(m):
reach.purge()
logger.debug(f"meshing: Import geometry from {m}")
reach.import_geometry(m)
else:
logger.error(f"meshing: Meshed geometry file {m} do not exists")
+1 -1
View File
@@ -1,5 +1,5 @@
# __init__.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+8 -2
View File
@@ -1,5 +1,5 @@
# test_Model.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -25,9 +25,10 @@ from Model.Saved import SavedStatus
from Model.Study import Study
from Model.River import River
from Meshing.Mage import MeshingWithMage
from Meshing.Mage import MeshingWithMage, MeshingWithMageMailleurTT
mage_mesher = os.path.exists(MeshingWithMage._lib_path())
mage_mesher_TT = os.path.exists(MeshingWithMageMailleurTT._exe_path())
class MeshingTestCase(unittest.TestCase):
@@ -35,3 +36,8 @@ class MeshingTestCase(unittest.TestCase):
def test_create_meshingtool_mage(self):
mesher = MeshingWithMage()
self.assertNotEqual(mesher, None)
@unittest.skipIf(not mage_mesher_TT, "mailleurTT is not available")
def test_create_meshingtool_mageTT(self):
mesher = MeshingWithMageMailleurTT()
self.assertNotEqual(mesher, None)
+178
View File
@@ -0,0 +1,178 @@
# AddFile.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from functools import reduce
from tools import trace, timer
from Model.Tools.PamhyrDB import SQLSubModel
from Model.Except import NotImplementedMethodeError
class AddFile(SQLSubModel):
_sub_classes = []
_id_cnt = 0
def __init__(self, id: int = -1, enabled=True,
name="", path="", text="",
status=None):
super(AddFile, self).__init__()
if id == -1:
self.id = AddFile._id_cnt
else:
self.id = id
self._status = status
self._enabled = enabled
self._name = f"File {self.id}" if name == "" else name
self._path = path
self._text = text
AddFile._id_cnt = max(id, AddFile._id_cnt+1)
def __getitem__(self, key):
value = None
if key == "enabled":
value = self._enabled
elif key == "name":
value = self._name
elif key == "path":
value = self._path
elif key == "text":
value = self._text
return value
def __setitem__(self, key, value):
if key == "enabled":
self._enabled = value
elif key == "name":
self._name = value
elif key == "path":
self._path = value
elif key == "text":
self._text = value
self._status.modified()
@property
def enabled(self):
return self._enabled
@enabled.setter
def enabled(self, enabled):
self._enabled = enabled
self._status.modified()
def is_enabled(self):
return self._enabled
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
self._status.modified()
@property
def path(self):
return self._path
@path.setter
def path(self, path):
self._path = path
self._status.modified()
@property
def text(self):
return self._text
@text.setter
def text(self, text):
self._text = text
self._status.modified()
@classmethod
def _db_create(cls, execute):
execute("""
CREATE TABLE additional_files(
id INTEGER NOT NULL PRIMARY KEY,
enabled BOOLEAN NOT NULL,
name TEXT NOT NULL,
path TEXT NOT NULL,
text TEXT NOT NULL
)
""")
return cls._create_submodel(execute)
@classmethod
def _db_update(cls, execute, version):
major, minor, release = version.strip().split(".")
if major == minor == "0":
if int(release) < 8:
cls._db_create(execute)
return True
@classmethod
def _db_load(cls, execute, data=None):
new = []
table = execute(
"SELECT id, enabled, name, path, text " +
"FROM additional_files"
)
for row in table:
it = iter(row)
id = next(it)
enabled = (next(it) == 1)
name = next(it)
path = next(it)
text = next(it)
f = cls(
id=id, enabled=enabled, name=name, path=path, text=text,
status=data['status']
)
new.append(f)
return new
def _db_save(self, execute, data=None):
sql = (
"INSERT INTO " +
"additional_files(id, enabled, name, path, text) " +
"VALUES (" +
f"{self.id}, {self._enabled}, " +
f"'{self._db_format(self._name)}', " +
f"'{self._db_format(self._path)}', " +
f"'{self._db_format(self._text)}'" +
")"
)
execute(sql)
return True
+56
View File
@@ -0,0 +1,56 @@
# AddFileList.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import trace, timer
from Model.Except import NotImplementedMethodeError
from Model.Tools.PamhyrList import PamhyrModelList
from Model.AdditionalFile.AddFile import AddFile
class AddFileList(PamhyrModelList):
_sub_classes = [AddFile]
@classmethod
def _db_load(cls, execute, data=None):
new = cls(status=data["status"])
new._lst = AddFile._db_load(execute, data)
return new
def _db_save(self, execute, data=None):
ok = True
# Delete previous data
execute("DELETE FROM additional_files")
for af in self._lst:
ok &= af._db_save(execute, data)
return ok
@property
def files(self):
return self.lst
def new(self, index):
n = AddFile(status=self._status)
self.insert(index, n)
self._status.modified()
return n
@@ -1,5 +1,5 @@
# BoundaryCondition.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,7 +18,12 @@
import logging
from tools import trace, timer, old_pamhyr_date_to_timestamp
from tools import (
trace, timer,
old_pamhyr_date_to_timestamp,
date_iso_to_timestamp,
date_dmy_to_timestamp,
)
from Model.Tools.PamhyrDB import SQLSubModel
from Model.Except import NotImplementedMethodeError
@@ -189,6 +194,10 @@ class BoundaryCondition(SQLSubModel):
@classmethod
def time_convert(cls, data):
if type(data) is str:
if data.count("-") == 2:
return date_iso_to_timestamp(data)
if data.count("/") == 2:
return date_dmy_to_timestamp(data)
if data.count(":") == 3:
return old_pamhyr_date_to_timestamp(data)
if data.count(":") == 2:
@@ -200,6 +209,9 @@ class BoundaryCondition(SQLSubModel):
@property
def name(self):
if self._name == "":
return f"B{self.id + 1}"
return self._name
@name.setter
@@ -1,5 +1,5 @@
# BoundaryConditionList.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -1,5 +1,5 @@
# BoundaryConditionTypes.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# Except.py -- Pamhyr model exceptions
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+29 -16
View File
@@ -1,5 +1,5 @@
# Friction.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -26,11 +26,21 @@ logger = logging.getLogger()
class Friction(SQLSubModel):
def __init__(self, name: str = "", status=None):
_id_cnt = 0
def __init__(self, id: int = -1, name: str = "",
status=None):
super(Friction, self).__init__()
self._status = status
if id == -1:
self.id = Friction._id_cnt
else:
self.id = id
Friction._id_cnt = max(self.id, Friction._id_cnt+1)
self._name = name
self._edge = None
self._begin_kp = 0.0
@@ -42,13 +52,13 @@ class Friction(SQLSubModel):
def _db_create(cls, execute):
execute("""
CREATE TABLE friction(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
ind INTERGER NOT NULL,
id INTEGER NOT NULL PRIMARY KEY,
ind INTEGER NOT NULL,
begin_kp REAL NOT NULL,
end_kp REAL NOT NULL,
reach INTEGER NOT NULL,
begin_strickler INTERGER,
end_strickler INTERGER,
begin_strickler INTEGER NOT NULL,
end_strickler INTEGER NOT NULL,
FOREIGN KEY(reach) REFERENCES river_reach(id),
FOREIGN KEY(begin_strickler) REFERENCES stricklers(id),
FOREIGN KEY(end_strickler) REFERENCES stricklers(id)
@@ -70,28 +80,30 @@ class Friction(SQLSubModel):
stricklers = data["stricklers"].stricklers
table = execute(
"SELECT ind, begin_kp, end_kp, begin_strickler, end_strickler " +
"SELECT id, ind, begin_kp, end_kp, " +
"begin_strickler, end_strickler " +
f"FROM friction WHERE reach = {reach.id}"
)
for row in table:
ind = row[0]
id = row[0]
ind = row[1]
# Get stricklers
if int(row[3]) == -1:
if int(row[4]) == -1:
bs = None
else:
bs = next(filter(lambda s: s.id == row[3], stricklers))
bs = next(filter(lambda s: s.id == row[4], stricklers))
if int(row[4]) == -1:
if int(row[5]) == -1:
es = None
else:
es = next(filter(lambda s: s.id == row[4], stricklers))
es = next(filter(lambda s: s.id == row[5], stricklers))
# Create friction
sec = cls(status=status)
sec.edge = reach
sec.begin_kp = row[1]
sec.end_kp = row[2]
sec.begin_kp = row[2]
sec.end_kp = row[3]
sec.begin_strickler = bs
sec.end_strickler = es
@@ -112,10 +124,11 @@ class Friction(SQLSubModel):
execute(
"INSERT INTO " +
"friction(ind, begin_kp, end_kp, " +
"friction(id, ind, begin_kp, end_kp, " +
"reach, begin_strickler, end_strickler) " +
"VALUES (" +
f"{ind}, {self._begin_kp}, {self._end_kp}, " +
f"{self.id}, {ind}, " +
f"{self._begin_kp}, {self._end_kp}, " +
f"{self._edge.id}, " +
f"{b_s_id}, {e_s_id}" +
")"
+1 -1
View File
@@ -1,5 +1,5 @@
# FrictionList.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# Point.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# PointXY.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+2 -2
View File
@@ -1,5 +1,5 @@
# PointXYZ.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -47,7 +47,7 @@ class PointXYZ(Point, SQLSubModel):
z INTEGER NOT NULL,
profile INTEGER NOT NULL,
sl INTEGER,
FOREIGN KEY(profile) REFERENCES profileXYZ(id),
FOREIGN KEY(profile) REFERENCES geometry_profileXYZ(id),
FOREIGN KEY(sl) REFERENCES sedimentary_layer(id)
)
""")
+1 -1
View File
@@ -1,5 +1,5 @@
# Profile.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+30 -32
View File
@@ -1,5 +1,5 @@
# ProfileXYZ.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -478,57 +478,55 @@ class ProfileXYZ(Profile, SQLSubModel):
return abs(rg.dist(rd))
def get_water_limits(self, z):
# ====================================================================
# détermination des points limites RG et RD pour un niveau
# d'eau donné
#
# irg et ird sont les premiers indices en partant des rives
# gauche et droite qui correspondent à des points sous la
# surface de l'eau ptX et ptY sont les points interpolés où
# le plan d'eau intersecte le profil known_level est le
# niveau d'eau pour lequel on a obtenu irg, ird, ptX et ptY
# ====================================================================
"""
Determine left and right limits of water elevation.
"""
# initialisation
irg = -1
ird = -1
# Get the index of first point with elevation lesser than water
# elevation (for the right and left river side)
i_left = -1
i_right = -1
for i in range(self.number_points):
if self.point(i).z <= z:
irg = i
i_left = i
break
for i in reversed(range(self.number_points)):
if self.point(i).z <= z:
ird = i
i_right = i
break
# interpolation des points ptX et ptY
if (irg < self.number_points - 1):
# Interpolate points at river left side
if (i_left > 0):
x = np.interp(
z,
[self.point(irg).z, self.point(irg + 1).z],
[self.point(irg).x, self.point(irg + 1).x]
[self.point(i_left).z, self.point(i_left - 1).z],
[self.point(i_left).x, self.point(i_left - 1).x]
)
y = np.interp(
z,
[self.point(irg).z, self.point(irg + 1).z],
[self.point(irg).y, self.point(irg + 1).y]
[self.point(i_left).z, self.point(i_left - 1).z],
[self.point(i_left).y, self.point(i_left - 1).y]
)
ptX = PointXYZ(x, y, z)
pt_left = PointXYZ(x, y, z)
else:
ptX = self.point(0)
if (ird > 0):
pt_left = self.point(0)
# Interpolate points at river right side
if (i_right < self.number_points - 1):
x = np.interp(
z,
[self.point(ird-1).z, self.point(ird).z],
[self.point(ird-1).x, self.point(ird).x]
[self.point(i_right).z, self.point(i_right + 1).z],
[self.point(i_right).x, self.point(i_right + 1).x]
)
y = np.interp(
z,
[self.point(ird).z, self.point(ird - 1).z],
[self.point(ird).y, self.point(ird - 1).y]
[self.point(i_right).z, self.point(i_right + 1).z],
[self.point(i_right).y, self.point(i_right + 1).y]
)
ptY = PointXYZ(x, y, z)
pt_right = PointXYZ(x, y, z)
else:
ptY = self.point(self.number_points - 1)
pt_right = self.point(self.number_points - 1)
return ptX, ptY
return pt_left, pt_right
+7 -4
View File
@@ -1,5 +1,5 @@
# Reach.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -65,7 +65,7 @@ class Reach(SQLSubModel):
new._profiles = ProfileXYZ._db_load(
execute,
data=data
data=data.copy()
)
return new
@@ -111,7 +111,7 @@ class Reach(SQLSubModel):
def _get_profiles_list(self):
# Profiles list generator is type (int, Point) with the first
# element the index of the Point in list
logger.info(f"Load profiles from reach {self.name}")
logger.debug(f"Load profiles from reach {self.name}")
return list(
map(
lambda p: p[1],
@@ -743,7 +743,10 @@ class Reach(SQLSubModel):
incline_acc.sort()
marge = round(len(incline_acc) * 0.1)
incline_set = incline_acc[marge:-marge]
if marge > 0:
incline_set = incline_acc[marge:-marge]
else:
incline_set = incline_acc
logger.debug(f"+{incline_acc}")
logger.debug(f"-{incline_set}")
+1 -1
View File
@@ -1,5 +1,5 @@
# Vector_1d.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -1,5 +1,5 @@
# HydraulicStructures.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -158,6 +158,9 @@ class BasicHS(SQLSubModel):
@property
def name(self):
if self._name == "":
return f"{self._type}{self.id + 1}"
return self._name
@name.setter
+1 -1
View File
@@ -1,5 +1,5 @@
# Types.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# Value.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -1,5 +1,5 @@
# HydraulicStructures.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -187,6 +187,9 @@ class HydraulicStructure(SQLSubModel):
@property
def name(self):
if self._name == "":
return f"HS{self.id + 1}"
return self._name
@name.setter
@@ -1,5 +1,5 @@
# HydraulicStructuresList.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -1,5 +1,5 @@
# InitialConditions.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -430,7 +430,7 @@ class InitialConditions(SQLSubModel):
logger.debug(f"({profile.kp}):")
logger.debug(f" width = {width}")
logger.debug(f" strickler = {strickler}")
logger.debug(f" hieght = {height}")
logger.debug(f" height = {height}")
new = Data(reach=self._reach, status=self._status)
new["kp"] = profile.kp
@@ -1,5 +1,5 @@
# InitialConditionsDict.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -1,5 +1,5 @@
# LateralContribution.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,7 +18,12 @@
import logging
from tools import trace, timer, old_pamhyr_date_to_timestamp
from tools import (
trace, timer,
old_pamhyr_date_to_timestamp,
date_iso_to_timestamp,
date_dmy_to_timestamp,
)
from Model.Tools.PamhyrDB import SQLSubModel
from Model.Except import NotImplementedMethodeError
@@ -189,6 +194,10 @@ class LateralContribution(SQLSubModel):
@classmethod
def time_convert(cls, data):
if type(data) is str:
if data.count("-") == 2:
return date_iso_to_timestamp(data)
if data.count("/") == 2:
return date_dmy_to_timestamp(data)
if data.count(":") == 3:
return old_pamhyr_date_to_timestamp(data)
if data.count(":") == 2:
@@ -200,6 +209,9 @@ class LateralContribution(SQLSubModel):
@property
def name(self):
if self._name == "":
return f"L{self.id + 1}"
return self._name
@name.setter
@@ -1,5 +1,5 @@
# LateralContributionList.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -1,5 +1,5 @@
# LateralContributionTypes.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# Edge.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+14 -1
View File
@@ -1,5 +1,5 @@
# Graph.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -67,6 +67,13 @@ class Graph(object):
def edges_counts(self):
return len(self._edges)
def enable_nodes_counts(self):
return reduce(
lambda acc, n: acc + 1 if self.is_enable_node(n) else acc,
self._nodes,
0
)
def enable_edges_counts(self):
return reduce(
lambda acc, e: acc + 1 if e.is_enable() else acc,
@@ -213,6 +220,12 @@ class Graph(object):
True
)
def is_internal_node(self, node):
return not (
self.is_upstream_node(node) or
self.is_downstream_node(node)
)
def is_enable_node(self, node):
return reduce(
lambda acc, e: (
+1 -1
View File
@@ -1,5 +1,5 @@
# Node.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# Point.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# __init__.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# test_Network.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+180
View File
@@ -0,0 +1,180 @@
# REPLine.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from functools import reduce
from tools import trace, timer
from Model.Tools.PamhyrDB import SQLSubModel
from Model.Except import NotImplementedMethodeError
class REPLine(SQLSubModel):
_sub_classes = []
_id_cnt = 0
def __init__(self, id: int = -1, enabled=True,
name="", line="", solvers=set(),
status=None):
super(REPLine, self).__init__()
if id == -1:
self.id = REPLine._id_cnt
else:
self.id = id
self._status = status
self._enabled = enabled
self._name = f"Line{self.id}" if name == "" else name
self._line = line
self._solvers = solvers
REPLine._id_cnt = max(id, REPLine._id_cnt+1)
def __getitem__(self, key):
value = None
if key == "enabled":
value = self._enabled
elif key == "name":
value = self._name
elif key == "line":
value = self._line
elif key == "solvers":
value = self._solvers
return value
def __setitem__(self, key, value):
if key == "enabled":
self._enabled = value
elif key == "name":
self._name = value
elif key == "line":
self._line = value
elif key == "solvers":
self._solvers = value
self._status.modified()
@property
def enabled(self):
return self._enabled
@enabled.setter
def enabled(self, enabled):
self._enabled = enabled
self._status.modified()
def is_enabled(self):
return self._enabled
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
self._status.modified()
@property
def line(self):
return self._line
@line.setter
def line(self, line):
self._line = line
self._status.modified()
@property
def solvers(self):
return self._solvers
@solvers.setter
def solvers(self, solvers):
self._solvers = solvers
self._status.modified()
@classmethod
def _db_create(cls, execute):
execute("""
CREATE TABLE rep_lines(
id INTEGER NOT NULL PRIMARY KEY,
enabled BOOLEAN NOT NULL,
name TEXT NOT NULL,
line TEXT NOT NULL,
solvers TEXT NOT NULL
)
""")
return cls._create_submodel(execute)
@classmethod
def _db_update(cls, execute, version):
major, minor, release = version.strip().split(".")
if major == minor == "0":
if int(release) < 9:
cls._db_create(execute)
return True
@classmethod
def _db_load(cls, execute, data=None):
new = []
table = execute(
"SELECT id, enabled, name, line, solvers " +
"FROM rep_lines"
)
for row in table:
it = iter(row)
id = next(it)
enabled = (next(it) == 1)
name = next(it)
line = next(it)
solvers = set(next(it).split(";;"))
f = cls(
id=id, enabled=enabled, name=name, line=line,
solvers=solvers, status=data['status']
)
new.append(f)
return new
def _db_save(self, execute, data=None):
solvers = ";;".join(self._solvers)
sql = (
"INSERT INTO " +
"rep_lines(id, enabled, name, line, solvers) " +
"VALUES (" +
f"{self.id}, {self._enabled}, " +
f"'{self._db_format(self._name)}', " +
f"'{self._db_format(self._line)}', " +
f"'{self._db_format(solvers)}'" +
")"
)
execute(sql)
return True
+56
View File
@@ -0,0 +1,56 @@
# REPLineList.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import trace, timer
from Model.Except import NotImplementedMethodeError
from Model.Tools.PamhyrList import PamhyrModelList
from Model.REPLine.REPLine import REPLine
class REPLineList(PamhyrModelList):
_sub_classes = [REPLine]
@classmethod
def _db_load(cls, execute, data=None):
new = cls(status=data["status"])
new._lst = REPLine._db_load(execute, data)
return new
def _db_save(self, execute, data=None):
ok = True
# Delete previous data
execute("DELETE FROM rep_lines")
for af in self._lst:
ok &= af._db_save(execute, data)
return ok
@property
def lines(self):
return self.lst
def new(self, index):
n = REPLine(status=self._status)
self.insert(index, n)
self._status.modified()
return n
+4 -1
View File
@@ -1,5 +1,5 @@
# Reservoir.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -152,6 +152,9 @@ class Reservoir(SQLSubModel):
@property
def name(self):
if self._name == "":
return f"R{self.id + 1}"
return self._name
@name.setter
+1 -1
View File
@@ -1,5 +1,5 @@
# ReservoirList.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# Results.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+7 -1
View File
@@ -1,5 +1,5 @@
# River.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -59,6 +59,9 @@ class Profile(object):
def get_ts_key(self, timestamp, key):
return self._data[timestamp][key]
def has_sediment(self):
return any(map(lambda ts: "sl" in self._data[ts], self._data))
class Reach(object):
def __init__(self, reach, study):
@@ -92,6 +95,9 @@ class Reach(object):
def set(self, profile_id, timestamp, key, data):
self._profiles[profile_id].set(timestamp, key, data)
def has_sediment(self):
return any(map(lambda profile: profile.has_sediment(), self._profiles))
class River(object):
def __init__(self, study):
+55 -21
View File
@@ -1,5 +1,5 @@
# River.py -- Pamhyr river model
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -40,6 +40,8 @@ from Model.Reservoir.ReservoirList import ReservoirList
from Model.HydraulicStructures.HydraulicStructuresList import (
HydraulicStructureList,
)
from Model.AdditionalFile.AddFileList import AddFileList
from Model.REPLine.REPLineList import REPLineList
from Solver.Solvers import solver_type_list
@@ -224,6 +226,8 @@ class River(Graph, SQLSubModel):
SedimentLayerList,
ReservoirList,
HydraulicStructureList,
AddFileList,
REPLineList,
]
def __init__(self, status=None):
@@ -245,6 +249,8 @@ class River(Graph, SQLSubModel):
self._hydraulic_structures = HydraulicStructureList(
status=self._status
)
self._additional_files = AddFileList(status=self._status)
self._rep_lines = REPLineList(status=self._status)
@classmethod
def _db_create(cls, execute):
@@ -263,66 +269,62 @@ class River(Graph, SQLSubModel):
# Stricklers (Stricklers is load in first because it's needed
# for reachs)
new._stricklers = StricklersList._db_load(
execute,
data
execute, data
)
data["stricklers"] = new._stricklers
# Initial conditions
new._sediment_layers = SedimentLayerList._db_load(
execute,
data
execute, data
)
data["sediment_layers_list"] = new._sediment_layers
# Network
new._nodes = RiverNode._db_load(
execute,
data
execute, data
)
data["nodes"] = new.nodes()
new._edges = RiverReach._db_load(
execute,
data
execute, data
)
data["edges"] = new.edges()
# Boundary Condition
new._boundary_condition = BoundaryConditionList._db_load(
execute,
data
execute, data
)
# Lateral Contribution
new._lateral_contribution = LateralContributionList._db_load(
execute,
data
execute, data
)
# Initial conditions
new._initial_conditions = InitialConditionsDict._db_load(
execute,
data
execute, data
)
# Reservoir
new._reservoir = ReservoirList._db_load(
execute,
data
execute, data
)
# Hydraulic Structures
new._hydraulic_structures = HydraulicStructureList._db_load(
execute,
data
execute, data
)
# Parameters
new._parameters = SolverParametersList._db_load(
execute,
data
execute, data
)
# Additional Files
new._additional_files = AddFileList._db_load(
execute, data
)
new._rep_lines = REPLineList._db_load(execute, data)
return new
def _db_save(self, execute, data=None):
@@ -336,6 +338,8 @@ class River(Graph, SQLSubModel):
objs.append(self._stricklers)
objs.append(self._reservoir)
objs.append(self._hydraulic_structures)
objs.append(self._additional_files)
objs.append(self._rep_lines)
for solver in self._parameters:
objs.append(self._parameters[solver])
@@ -372,6 +376,28 @@ class River(Graph, SQLSubModel):
except Exception as e:
logger_exception(e)
def init_default(self):
self.init_default_network()
self.init_default_additional_files()
def init_default_network(self):
n1 = self.add_node(880.0, 950.0)
n2 = self.add_node(1120.0, 1020.0)
e = self.add_edge(n1, n2)
def init_default_additional_files(self):
add_file = self._additional_files.new(0)
add_file.name = "Pamhyr2 stamp file"
add_file.path = "Pamhyr2.txt"
add_file.text = """This repository has been generated by Pamhyr2 \
version "@version" !
All hand made file modification could be erased by the next solver
execution...
Last export at: @date."""
@property
def boundary_condition(self):
return self._boundary_condition
@@ -413,6 +439,14 @@ class River(Graph, SQLSubModel):
def hydraulic_structures(self):
return self._hydraulic_structures
@property
def additional_files(self):
return self._additional_files
@property
def rep_lines(self):
return self._rep_lines
@property
def parameters(self):
return self._parameters
+1 -1
View File
@@ -1,5 +1,5 @@
# Saved.py -- Pamhyr model status class
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+50
View File
@@ -1,5 +1,23 @@
# SedimentLayer.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from functools import reduce
from tools import trace, timer
from Model.Tools.PamhyrDB import SQLSubModel
@@ -37,6 +55,9 @@ class Layer(SQLSubModel):
@property
def name(self):
if self._name == "":
return f"Layer{self.id + 1}"
return self._name
@name.setter
@@ -204,6 +225,9 @@ class SedimentLayer(SQLSubModel):
@property
def name(self):
if self._name == "":
return f"SL{self.id + 1}"
return self._name
@name.setter
@@ -340,3 +364,29 @@ class SedimentLayer(SQLSubModel):
lst[index], lst[prev] = lst[prev], lst[index]
self._status.modified()
def compute_height_from_bottom(self, bottom_elevation: list):
sl_height = self.height()
sl_height_by_profile = []
for i in range(len(sl_height)):
cur_profile = []
for _ in bottom_elevation:
cur_profile.append(sl_height[i])
sl_height_by_profile.append(cur_profile)
z_sl = reduce(
lambda acc, current_sl: acc + [
list(
map(
lambda cur_sl_h, prev_sl_h: prev_sl_h - cur_sl_h,
current_sl, acc[-1]
)
)
],
sl_height_by_profile,
[bottom_elevation]
)
return z_sl
@@ -1,3 +1,19 @@
# SedimentLayerList.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import trace, timer
+1 -1
View File
@@ -1,5 +1,5 @@
# Serializable.py -- Pamhyr pickle abstract class
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -1,5 +1,5 @@
# SolverParametersList.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+3 -1
View File
@@ -1,5 +1,5 @@
# Stricklers.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -120,6 +120,8 @@ class Stricklers(SQLSubModel):
@property
def name(self):
if self._name == "":
return f"K{self.id + 1}"
return self._name
@name.setter
+1 -1
View File
@@ -1,5 +1,5 @@
# StricklersList.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+26 -6
View File
@@ -1,5 +1,5 @@
# Study.py -- Pamhyr Study class
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@ class Study(SQLModel):
def __init__(self, filename=None, init_new=True):
# Metadata
self._version = "0.0.7"
self._version = "0.0.9"
self.creation_date = datetime.now()
self.last_modification_date = datetime.now()
self.last_save_date = datetime.now()
@@ -103,10 +103,20 @@ class Study(SQLModel):
except Exception as e:
logger.error(e)
is_new = False
fname = fname + "." + str(self._old_save_id)
filename = os.path.join(fdir, "_PAMHYR_", "__old__", fname)
shutil.copy(self.filename, filename)
self._old_save_id += 1
if os.path.exists(self.filename) and ".backup" not in self.filename:
filename = os.path.join(fdir, "_PAMHYR_", "__old__", fname)
logger.debug(f"Backup previous version copy: {filename}")
shutil.copy(self.filename, filename)
self._old_save_id += 1
is_new = True
if ".backup" in self.filename:
is_new = True
self._init_db_file(self.filename, is_new=is_new)
self.commit()
# Save
self.last_save_date = datetime.now()
@@ -128,6 +138,16 @@ class Study(SQLModel):
@filename.setter
def filename(self, filename):
if filename is None:
self._filename = None
self.status.modified()
return
if self._filename is not None and self._filename != "":
self._filename = str(filename)
self.status.modified()
return
self._filename = str(filename)
self._init_db_file(filename, is_new=True)
self.status.modified()
@@ -221,7 +241,7 @@ class Study(SQLModel):
if version[0] == self._version:
return True
logger.info("Update database")
logger.debug("Update database")
if self._update_submodel(version[0]):
self.execute(
+6 -3
View File
@@ -1,5 +1,5 @@
# PamhyrDB.py -- Pamhyr abstract model database classes
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@ import logging
from pathlib import Path
from functools import reduce
from tools import SQL
from SQL import SQL
from Model.Except import NotImplementedMethodeError
logger = logging.getLogger()
@@ -35,8 +35,10 @@ class SQLModel(SQL):
_sub_classes = []
def _init_db_file(self, db, is_new=True):
exists = Path(db).exists()
if self._db is not None:
self._db.close()
exists = Path(db).exists()
if exists and is_new:
os.remove(db)
@@ -68,6 +70,7 @@ class SQLModel(SQL):
return True
def _create(self):
raise NotImplementedMethodeError(self, self._create)
def _update_submodel(self, version):
+2 -2
View File
@@ -1,5 +1,5 @@
# PamhyrDict.py -- Pamhyr abstract dict for model classes
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@ class PamhyrModelDict(SQLSubModel):
def __len__(self):
return len(self._dict)
def is_defined(self, key):
def __contains__(self, key):
return key in self._dict
def set(self, key, new):
+80 -9
View File
@@ -1,5 +1,5 @@
# PamhyrList.py -- Pamhyr Abstract List object for the Model
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -62,16 +62,27 @@ class PamhyrModelList(SQLSubModel):
@property
def lst(self):
"""Return the PamhyrList as a Python list
Return the PamhyrList as a Python list. This list is the
current list used in the PamhyrList object. **If you need to
modify it, please make a copy.**
Returns: The Python list
"""
return self._lst
def __len__(self):
return len(self.lst)
def get(self, row):
return self._lst[row]
def index(self, el):
return self._lst.index(el)
def set(self, row, new):
self._lst[row] = new
def get(self, index):
return self._lst[index]
def set(self, index, new):
self._lst[index] = new
if self._status is not None:
self._status.modified()
@@ -93,6 +104,14 @@ class PamhyrModelList(SQLSubModel):
self._status.modified()
def delete(self, lst):
"""Delete a list of elements
Args:
lst: The list of elements
Returns:
Nothing
"""
for el in lst:
self._lst.remove(el)
@@ -100,6 +119,14 @@ class PamhyrModelList(SQLSubModel):
self._status.modified()
def delete_i(self, indexes):
"""Delete elements from list of indexes
Args:
indexes: The elements indexes
Returns:
Nothing
"""
lst = list(
map(
lambda x: x[1],
@@ -175,16 +202,32 @@ class PamhyrModelListWithTab(SQLSubModel):
################
def len(self, lst):
"""Size of tab list
Args:
lst: The tab name
Returns:
The size of the tab list
"""
return len(self._tabs[lst])
def get_tab(self, lst):
"""Get tab list (copy) from name
Args:
lst: The tab name
Returns:
Nothing
"""
return self._tabs[lst].copy()
def get(self, lst, row):
return self._tabs[lst][row]
def get(self, lst, index):
return self._tabs[lst][index]
def set(self, lst, row, new):
self._tabs[lst][row] = new
def set(self, lst, index, new):
self._tabs[lst][index] = new
self._status.modified()
def new(self, lst, index):
@@ -200,15 +243,43 @@ class PamhyrModelListWithTab(SQLSubModel):
raise NotImplementedMethodeError(self, self.new)
def insert(self, lst, index, new):
"""Insert element in tab
Args:
lst: The tab name
index: The index of new element
new: The new elements
Returns:
Nothing
"""
self._tabs[lst].insert(index, new)
self._status.modified()
def delete(self, lst, els):
"""Delete elements from specific tab
Args:
lst: The tab name
els: The elements list
Returns:
Nothing
"""
for el in els:
self._tabs[lst].remove(el)
self._status.modified()
def delete_i(self, lst, indexes):
"""Delete elements from specific tab
Args:
lst: The tab name
indexes: The elements indexes
Returns:
Nothing
"""
els = list(
map(
lambda x: x[1],
+1 -1
View File
@@ -1,5 +1,5 @@
# __init__.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# test_Model.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+95
View File
@@ -0,0 +1,95 @@
# Modules.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import logging
from enum import Flag, auto
logger = logging.getLogger()
class Modules(Flag):
NONE = 0
# General
STUDY = auto()
CONFIG = auto()
# Modelling
NETWORK = auto()
GEOMETRY = auto()
BOUNDARY_CONDITION = auto()
LATERAL_CONTRIBUTION = auto()
FRICTION = auto()
INITIAL_CONDITION = auto()
HYDRAULIC_STRUCTURES = auto()
RESERVOIR = auto()
SEDIMENT_LAYER = auto()
ADDITIONAL_FILES = auto()
# Results
RESULTS = auto()
# Display
WINDOW_LIST = auto()
@classmethod
def all(cls):
return ~cls.NONE
@classmethod
def modelling(cls):
return (
cls.NETWORK
| cls.GEOMETRY
| cls.BOUNDARY_CONDITION
| cls.LATERAL_CONTRIBUTION
| cls.FRICTION
| cls.INITIAL_CONDITION
| cls.HYDRAULIC_STRUCTURES
| cls.RESERVOIR
| cls.SEDIMENT_LAYER
)
@classmethod
def modelling_list(cls):
return [
cls.NETWORK,
cls.GEOMETRY,
cls.BOUNDARY_CONDITION,
cls.LATERAL_CONTRIBUTION,
cls.FRICTION,
cls.INITIAL_CONDITION,
cls.HYDRAULIC_STRUCTURES,
cls.RESERVOIR,
cls.SEDIMENT_LAYER,
]
@classmethod
def modelling_display_name(cls):
return {
cls.NETWORK: "Network",
cls.GEOMETRY: "Geometry",
cls.BOUNDARY_CONDITION: "Boundary condition",
cls.LATERAL_CONTRIBUTION: "Lateral contribution",
cls.FRICTION: "Friction",
cls.INITIAL_CONDITION: "Initial condition",
cls.HYDRAULIC_STRUCTURES: "Hydraulic structures",
cls.RESERVOIR: "Reservoir",
cls.SEDIMENT_LAYER: "Sediment layer",
}
+133
View File
@@ -0,0 +1,133 @@
# SQL.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import os
import logging
import sqlite3
from pathlib import Path
from tools import timer
logger = logging.getLogger()
class SQL(object):
def _init_db_file(self, db):
exists = Path(db).exists()
os.makedirs(
os.path.dirname(db),
exist_ok=True
)
self._db = sqlite3.connect(db)
self._cur = self._db.cursor()
if not exists:
self._create() # Create db
self._save() # Save
else:
self._update() # Update db scheme if necessary
self._load() # Load data
def __init__(self, filename=None):
self._db = None
if filename is not None:
self._init_db_file(filename)
def commit(self):
logger.debug("SQL - commit")
self._db.commit()
def _close(self):
self.commit()
self._db.close()
def _fetch_string(self, s):
return s.replace("&#39;", "'")
def _fetch_tuple(self, tup):
res = []
for v in tup:
if type(v) is str:
v = self._fetch_string(v)
res.append(v)
return res
def _fetch_list(self, lst):
res = []
for v in lst:
if type(v) is str:
v = self._fetch_string(v)
elif type(v) is tuple:
v = self._fetch_tuple(v)
res.append(v)
return res
def _fetch(self, res, one):
if one:
value = res.fetchone()
else:
value = res.fetchall()
res = value
if type(value) is list:
res = self._fetch_list(value)
elif type(value) is tuple:
res = self._fetch_tuple(value)
return res
def _db_format(self, value):
# Replace ''' by '&#39;' to preserve SQL injection
if type(value) is str:
value = value.replace("'", "&#39;")
return value
@timer
def execute(self, cmd, fetch_one=True, commit=False):
logger.debug(f"SQL - {cmd}")
value = None
try:
res = self._cur.execute(cmd)
if commit:
self._db.commit()
value = self._fetch(res, fetch_one)
except Exception as e:
logger_exception(e)
finally:
return value
def _create(self):
logger.warning("TODO: Create")
def _update(self):
logger.warning("TODO: Update")
def _save(self):
logger.warning("TODO: Save")
def _load(self):
logger.warning("TODO: LOAD")
+1 -1
View File
@@ -1,5 +1,5 @@
# AScript.py -- Pamhyr abstract script class
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# Hello.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# ListSolver.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# MageMesh.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# P3DST.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# Run.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
# ASolver.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+60 -8
View File
@@ -1,5 +1,5 @@
# CommandLine.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,7 +19,8 @@
import os
import logging
from tools import timer, parse_command_line
from datetime import datetime
from tools import timer, parse_command_line, get_version, logger_exception
try:
# Installation allow Unix-like signal
@@ -124,6 +125,54 @@ class CommandLineSolver(AbstractSolver):
"""
raise NotImplementedMethodeError(self, self.log_file)
def export_additional_files(self, study, repertory, qlog, name="0"):
files = []
if qlog is not None:
qlog.put("Export additional files")
add_files = study.river.additional_files.files
for add_file in add_files:
self.export_additional_file(
study, add_file, repertory, files
)
return files
def export_additional_file(self, study, add_file, repertory, files):
if add_file.path == "" or not add_file.is_enabled():
return files
path = os.path.join(repertory, add_file.path)
os.makedirs(
os.path.dirname(path),
exist_ok=True
)
with open(path, "w+") as f:
files.append(add_file.path)
txt = add_file.text
txt = txt.replace("@version", get_version())
txt = txt.replace("@date", datetime.now().isoformat(sep=" "))
f.write(txt)
return files
def export_study_description(self, study, repertory, qlog, name="0"):
files = []
path = os.path.join(
repertory, "pamhyr-study-description.txt"
)
with open(path, "w+", encoding='utf-8') as f:
txt = study.description\
.encode()\
.decode('utf-8', 'replace')
f.write(txt)
#######
# Run #
#######
@@ -132,7 +181,7 @@ class CommandLineSolver(AbstractSolver):
return os.path.abspath(
os.path.join(
os.path.dirname(__file__),
"..", "..", ".."
"..", ".."
)
)
@@ -224,12 +273,15 @@ class CommandLineSolver(AbstractSolver):
return True
def _data_ready(self):
# Read process output and put lines in queue
s = self._process.readAll().data().decode()
try:
# Read process output and put lines in queue
s = self._process.readAll().data().decode('utf-8', "replace")
if self._output is not None:
for x in s.split('\n'):
self._output.put(x)
if self._output is not None:
for x in s.split(os.linesep):
self._output.put(x)
except Exception as e:
logger_exception(e)
def _finished(self, study, exit_code, exit_status):
if self._output is not None:
+1 -1
View File
@@ -1,5 +1,5 @@
# GenericSolver.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+153 -115
View File
@@ -1,5 +1,5 @@
# Mage.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@ import os
import logging
import numpy as np
from tools import timer, trace
from tools import timer, trace, logger_exception
from Solver.CommandLine import CommandLineSolver
from Checker.Mage import (
@@ -90,7 +90,7 @@ class Mage(CommandLineSolver):
("mage_compute_reach_volume_balance", "y"),
("mage_max_reach_volume_balance", "0.001"),
("mage_min_reach_volume_to_check", "1000.0"),
("mage_init_internal", " "),
("mage_init_internal", "n"),
]
return lst
@@ -98,10 +98,9 @@ class Mage(CommandLineSolver):
@classmethod
def checkers(cls):
lst = [
MageNetworkGraphChecker(connectivity=True),
MageNetworkGraphChecker(connectivity=False),
MageGeometryGuideLineChecker(),
MageNetworkGraphChecker(connectivity=True, version=cls._type),
MageNetworkGraphChecker(connectivity=False, version=cls._type),
MageGeometryGuideLineChecker(version=cls._type),
]
return lst
@@ -129,7 +128,15 @@ class Mage(CommandLineSolver):
name = self._study.name
return f"{name}.TRA"
@timer
def _export_REP_additional_lines(self, study, rep_file):
lines = filter(
lambda line: line.is_enabled(),
study.river.rep_lines.lines
)
for line in lines:
rep_file.write(line.line)
def _export_ST(self, study, repertory, qlog, name="0"):
files = []
@@ -139,18 +146,9 @@ class Mage(CommandLineSolver):
os.makedirs(os.path.join(repertory, "net"), exist_ok=True)
# Write header
edges = study.river.edges()
edges = list(
filter(
lambda e: e.is_enable(),
edges
)
)
edges = study.river.enable_edges()
for edge in edges:
name = edge.name.replace(" ", "_")
if edge._name == "":
name = f"Reach_{edge.id}"
name = f"Reach_{edge.id + 1:>3}".replace(" ", "0")
with mage_file_open(
os.path.join(repertory, "net", f"{name}.ST"),
@@ -237,7 +235,6 @@ class Mage(CommandLineSolver):
# Point line
wfile.write(f"{x} {y} {z} {n} {sediment}\n")
@timer
def _export_BC(self, t, bounds, repertory, qlog, name="0"):
files = []
@@ -271,7 +268,6 @@ class Mage(CommandLineSolver):
return files
@timer
def _export_bound_cond(self, study, repertory, qlog, name="0"):
files = []
lst = study.river.boundary_condition
@@ -286,6 +282,9 @@ class Mage(CommandLineSolver):
if bound.node is None:
continue
if not study.river.is_enable_node(bound.node):
continue
if bound.bctype == "ZD":
AVA.append(bound)
elif bound.bctype == "TD" or bound.bctype == "PC":
@@ -302,42 +301,55 @@ class Mage(CommandLineSolver):
return files
# @timer
# def _export_LC(self, lateral, repertory, qlog, name="0"):
# files = []
def _export_lateral_contrib(self, study, repertory, qlog, name="0"):
files = []
lst = study.river.lateral_contribution
# if qlog is not None:
# qlog.put(f"Export LAT file")
with mage_file_open(
os.path.join(repertory, f"{name}.LAT"),
"w+"
) as f:
if qlog is not None:
qlog.put(f"Export LAT file")
files.append(f"{name}.LAT")
# with mage_file_open(
# os.path.join(repertory, f"{name}.LAT"),
# "w+"
# ) as f:
# files.append(f"{name}.LAT")
for tab in ["liquid", "solid", "suspenssion"]:
for lateral in lst.get_tab(tab):
self._export_LC(study, lateral, f, qlog)
# name = f"{lateral.node.id:3}".replace(" ", "x")
# f.write(f"* {lateral.node.name} ({name}) {lateral.bctype}\n")
# f.write(f"${name}\n")
# header = lateral.header
# f.write(f"*{header[0]:>9}|{header[1]:>10}\n")
return files
# for d in lateral.data:
# f.write(f"{d[0]:1{name}.3f}{d[1]:10.3f}\n")
def _export_LC(self, study, lateral, f, qlog, name="0"):
if lateral.edge is None:
return
# return files
edges = study.river.enable_edges()
if lateral.edge not in edges:
return
# @timer
# def _export_lateral_contrib(self, study, repertory, qlog, name="0"):
# files = []
# lst = study.river.lateral_contribution
eid, _ = next(
filter(
lambda e: e[1] == lateral.edge,
enumerate(edges)
)
)
# for tab in ["liquid", "solid", "suspenssion"]:
# for lateral in lst.get_tab(tab):
# files = files + self._export_LC(lateral, repertory, qlog)
name = f"{eid+1:>3}"
# name = f"Reach_{lateral.edge.id + 1:>3}".replace(" ", "0")
f.write(f"* {lateral.edge.name} ({name}) {lateral.lctype}\n")
f.write(
f"${name} " +
f"{lateral.begin_kp:>10.4f} {lateral.end_kp:>10.4f}\n"
)
header = lateral.header
f.write(f"*{header[0]:>9}|{header[1]:>10}\n")
# return files
for d in lateral.data:
if lateral.lctype in ["EV"]:
f.write(f"{d[0]:10.3f}{-d[1]:10.3f}\n")
else:
f.write(f"{d[0]:10.3f}{d[1]:10.3f}\n")
@timer
def _export_RUG(self, study, repertory, qlog, name="0"):
files = []
@@ -348,13 +360,7 @@ class Mage(CommandLineSolver):
with mage_file_open(os.path.join(repertory, f"{name}.RUG"), "w+") as f:
files.append(f"{name}.RUG")
edges = study.river.edges()
edges = list(
filter(
lambda e: e.is_enable(),
edges
)
)
edges = study.river.enable_edges()
id = 1
for edge in edges:
@@ -381,7 +387,6 @@ class Mage(CommandLineSolver):
return files
@timer
def _export_INI(self, study, repertory, qlog, name="0"):
files = []
@@ -424,7 +429,6 @@ class Mage(CommandLineSolver):
files.append(f"{name}.INI")
return files
@timer
def _export_CAS(self, study, repertory, qlog, name="0"):
files = []
@@ -457,7 +461,6 @@ class Mage(CommandLineSolver):
return files
@timer
def _export_SIN(self, study, repertory, qlog, name="0"):
files = []
@@ -489,35 +492,41 @@ class Mage(CommandLineSolver):
if not hs.input_reach.is_enable():
continue
if hs.input_kp is None:
continue
f.write(
'* ouvrage au pk ' +
f"{float(hs.input_kp):>12.1f}" + ' ' +
hs.name + '\n'
)
for bhs in hs.basic_structures:
reach_id = study.river.get_edge_id(hs.input_reach) + 1
param_str = ' '.join(
[
f'{p:>10.3f}'
for p in self._export_SIN_parameters(bhs)
]
)
name = bhs.name
if name == "":
name = f"HS_{bhs.id:>3}".replace(" ", "0")
else:
name = name.replace(" ", "_")
f.write(
f"{sin_dict[bhs._type]} " +
f"{reach_id} {float(hs.input_kp):>12.3f} " +
f"{param_str} {name}\n"
)
self._export_SIN_bhs(study, sin_dict, hs, f)
return files
def _export_SIN_bhs(self, study, sin_dict, hs, f):
for bhs in hs.basic_structures:
reach_id = study.river.get_edge_id(hs.input_reach) + 1
param_str = ' '.join(
[
f'{p:>10.3f}'
for p in self._export_SIN_parameters(bhs)
]
)
name = bhs.name
if name == "":
name = f"HS_{bhs.id:>3}".replace(" ", "0")
else:
name = name.replace(" ", "_")
f.write(
f"{sin_dict[bhs._type]} " +
f"{reach_id} {float(hs.input_kp):>12.3f} " +
f"{param_str} {name}\n"
)
def _export_SIN_parameters(self, bhs):
res = [9999.999] * 5
@@ -576,7 +585,6 @@ class Mage(CommandLineSolver):
return res
@timer
def _export_VAR(self, study, repertory, qlog, name="0"):
files = []
@@ -612,7 +620,6 @@ class Mage(CommandLineSolver):
return files
@timer
def _export_DEV(self, study, repertory, qlog, name="0"):
files = []
@@ -635,7 +642,6 @@ class Mage(CommandLineSolver):
return files
@timer
def _export_REP(self, study, repertory, files, qlog, name="0"):
if qlog is not None:
qlog.put("Export REP file")
@@ -657,6 +663,7 @@ class Mage(CommandLineSolver):
f.write("* OUTPUT\n")
f.write(f"TRA {name}.TRA\n")
f.write(f"BIN {name}.BIN\n")
f.write(f"ERR {name}.ERR\n")
for file in files:
EXT = file.split('.')[1]
@@ -664,6 +671,8 @@ class Mage(CommandLineSolver):
if EXT in ["GRA"]:
f.write(f"{EXT} {file}\n")
self._export_REP_additional_lines(study, f)
@timer
def export(self, study, repertory, qlog=None):
self._study = study
@@ -674,6 +683,8 @@ class Mage(CommandLineSolver):
self._bin_file = f"{name}.BIN"
self._export_ST(study, repertory, qlog, name=name)
self.export_additional_files(study, repertory, qlog, name=name)
self.export_study_description(study, repertory, qlog, name=name)
return True
@@ -765,7 +776,6 @@ class Mage8(Mage):
return lst
@timer
def _export_PAR(self, study, repertory, qlog=None, name="0"):
files = []
@@ -792,11 +802,14 @@ class Mage8(Mage):
value = ("p" if value.lower() in ["y", "yes", "true"]
else "")
logger.debug(
f"export: PAR: {name}: {value} ({p.value})"
)
f.write(f"{name} {value}\n")
return files
@timer
def _export_NET(self, study, repertory, qlog=None, name="0"):
files = []
@@ -806,20 +819,11 @@ class Mage8(Mage):
with mage_file_open(os.path.join(repertory, f"{name}.NET"), "w+") as f:
files.append(f"{name}.NET")
edges = study.river.edges()
edges = list(
filter(
lambda e: e.is_enable(),
edges
)
)
edges = study.river.enable_edges()
for e in edges:
name = e.name.replace(" ", "_")
if e._name == "":
name = f"Reach_{e.id}"
id = f"Bief_{e.id+1}"
name = f"Reach_{e.id + 1:>3}".replace(" ", "0")
id = name
n1 = f"{e.node1.id:3}".replace(" ", "x")
n2 = f"{e.node2.id:3}".replace(" ", "x")
@@ -829,7 +833,6 @@ class Mage8(Mage):
return files
@timer
def _export_QSO(self, bounds, repertory, qlog, name="0"):
files = []
@@ -865,6 +868,16 @@ class Mage8(Mage):
return files
def export_func_dict(self):
return [
self._export_ST, self._export_PAR,
self._export_NET, self._export_bound_cond,
self._export_RUG, self._export_INI,
self._export_SIN, self._export_VAR,
self._export_CAS, self._export_DEV,
self._export_lateral_contrib,
]
@timer
def export(self, study, repertory, qlog=None, name="0"):
self._study = study
@@ -877,20 +890,19 @@ class Mage8(Mage):
# Generate files
files = []
files = self._export_ST(study, repertory, qlog, name=name)
files = files + self._export_PAR(study, repertory, qlog, name=name)
files = files + self._export_NET(study, repertory, qlog, name=name)
files = files + \
self._export_bound_cond(study, repertory, qlog, name=name)
files = files + self._export_RUG(study, repertory, qlog, name=name)
files = files + self._export_INI(study, repertory, qlog, name=name)
files = files + self._export_SIN(study, repertory, qlog, name=name)
files = files + self._export_VAR(study, repertory, qlog, name=name)
files = files + self._export_CAS(study, repertory, qlog, name=name)
files = files + self._export_DEV(study, repertory, qlog, name=name)
self._export_REP(study, repertory, files, qlog, name=name)
try:
for func in self.export_func_dict():
files = files + func(study, repertory, qlog, name=name)
return True
self.export_additional_files(study, repertory, qlog, name=name)
self.export_study_description(study, repertory, qlog, name=name)
self._export_REP(study, repertory, files, qlog, name=name)
return True
except Exception as e:
logger.error(f"Failed to export study to {self._type}")
logger_exception(e)
return False
###########
# RESULTS #
@@ -1019,9 +1031,12 @@ class Mage8(Mage):
reach.set(ri, timestamp, key, d)
if key == "Z":
profile = reach.profile(ri)
ptX, ptY = profile.geometry.get_water_limits(d)
reach.set(ri, timestamp, "ptX", ptX)
reach.set(ri, timestamp, "ptY", ptY)
limits = profile.geometry.get_water_limits(d)
reach.set(
ri, timestamp,
"water_limits",
limits
)
endline()
end = newline().size <= 0
@@ -1200,11 +1215,34 @@ class Mage8(Mage):
logger.info(f"read_gra: ... end with {len(ts)} timestamp read")
@timer
def results(self, study, repertory, qlog=None):
def results(self, study, repertory,
qlog=None, name=None,
with_gra=True):
self._study = study
name = study.name.replace(" ", "_")
if name is None:
name = study.name.replace(" ", "_")
results = super(Mage8, self).results(study, repertory, qlog, name=name)
self.read_gra(study, repertory, results, qlog, name=name)
if with_gra:
self.read_gra(study, repertory, results, qlog, name=name)
return results
class MageFake7(Mage8):
_type = "mage_fake7"
def __init__(self, name):
super(MageFake7, self).__init__(name)
self._type = "mage_fake7"
@timer
def results(self, study, repertory,
qlog=None, name=None,
with_gra=False):
results = super(MageFake7, self).results(
study, repertory,
qlog, name=name, with_gra=with_gra
)
return results
+8 -4
View File
@@ -1,5 +1,5 @@
# Solvers.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,18 +19,22 @@
from PyQt5.QtCore import QCoreApplication
from Solver.GenericSolver import GenericSolver
from Solver.Mage import Mage7, Mage8
from Solver.Mage import (
Mage7, Mage8, MageFake7,
)
_translate = QCoreApplication.translate
solver_long_name = {
"generic": "Generic",
# "generic": "Generic",
# "mage7": "Mage v7",
"mage8": "Mage v8",
# "mage_fake7": "Mage fake v7",
}
solver_type_list = {
"generic": GenericSolver,
# "generic": GenericSolver,
# "mage7": Mage7,
"mage8": Mage8,
# "mage_fake7": MageFake7,
}
+2 -2
View File
@@ -1,5 +1,5 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -67,5 +67,5 @@ class AboutWindow(PamhyrDialog):
label = f"\n - {author}" + label
except StopIteration:
label = _translate("About", "Contributors: ") + label
label = "Copyright © 2023 INRAE\n" + label
label = "Copyright © 2023-2024 INRAE\n" + label
self.set_label_text("label_copyright", label)
+90
View File
@@ -0,0 +1,90 @@
# Window.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import logging
from Modules import Modules
from View.Tools.PamhyrWindow import PamhyrWindow
from PyQt5.QtWidgets import (
QLabel, QPlainTextEdit, QPushButton,
QCheckBox,
)
from View.AdditionalFiles.Translate import AddFileTranslate
from View.AdditionalFiles.UndoCommand import (
SetCommand
)
logger = logging.getLogger()
class EditAddFileWindow(PamhyrWindow):
_pamhyr_ui = "AdditionalFile"
_pamhyr_name = "Edit additional file"
def __init__(self, study=None, config=None, add_file=None,
trad=None, undo=None, parent=None):
name = trad[self._pamhyr_name] + " - " + study.name
super(EditAddFileWindow, self).__init__(
title=name,
study=study,
config=config,
options=[],
parent=parent
)
self._add_file = add_file
self._hash_data.append(self._add_file)
self._undo = undo
self.setup_values()
self.setup_connection()
def setup_values(self):
self.set_check_box("checkBox", self._add_file.enabled)
self.set_line_edit_text("lineEdit_name", self._add_file.name)
self.set_line_edit_text("lineEdit_path", self._add_file.path)
self.set_plaintext_edit_text("plainTextEdit", self._add_file.text)
def setup_connection(self):
self.find(QPushButton, "pushButton_cancel")\
.clicked.connect(self.close)
self.find(QPushButton, "pushButton_ok")\
.clicked.connect(self.accept)
def accept(self):
is_enabled = self.get_check_box("checkBox")
name = self.get_line_edit_text("lineEdit_name")
path = self.get_line_edit_text("lineEdit_path")
text = self.get_plaintext_edit_text("plainTextEdit")
self._undo.push(
SetCommand(
self._add_file,
enabled=is_enabled,
name=name,
path=path,
text=text,
)
)
self._propagate_update(key=Modules.ADDITIONAL_FILES)
self.close()
+81
View File
@@ -0,0 +1,81 @@
# List.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import logging
from functools import reduce
from tools import trace, timer
from PyQt5.QtCore import (
Qt, QVariant,
)
from PyQt5.QtGui import (
QColor, QBrush,
)
from View.Tools.PamhyrList import PamhyrListModel
from View.AdditionalFiles.UndoCommand import (
AddCommand, DelCommand
)
logger = logging.getLogger()
class ListModel(PamhyrListModel):
def data(self, index, role):
row = index.row()
column = index.column()
file = self._data.files[row]
if role == Qt.ForegroundRole:
color = Qt.gray
if file.is_enabled():
color = QColor("black")
else:
color = QColor("grey")
return QBrush(color)
if role == Qt.ItemDataRole.DisplayRole:
text = f"{file.name}: '{file.path}'"
if not file.is_enabled():
text += " (disabled)"
return text
return QVariant()
def add(self, row):
self._undo.push(
AddCommand(
self._data, row
)
)
self.update()
def delete(self, row):
self._undo.push(
DelCommand(
self._data, row
)
)
self.update()
+35
View File
@@ -0,0 +1,35 @@
# Translate.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
from View.Translate import MainTranslate
_translate = QCoreApplication.translate
class AddFileTranslate(MainTranslate):
def __init__(self):
super(AddFileTranslate, self).__init__()
self._dict["Additional files"] = _translate(
"AdditionalFiles", "Additional files"
)
self._dict["Edit additional file"] = _translate(
"AdditionalFiles", "Edit additional file"
)
+82
View File
@@ -0,0 +1,82 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import trace, timer
from PyQt5.QtWidgets import (
QMessageBox, QUndoCommand, QUndoStack,
)
class SetCommand(QUndoCommand):
def __init__(self, add_file, **kwargs):
QUndoCommand.__init__(self)
self._add_file = add_file
self._new = kwargs
self._old = None
def undo(self):
f = self._add_file
for key in self._old:
f[key] = self._old[key]
def redo(self):
f = self._add_file
if self._old is None:
self._old = {}
for key in self._new:
self._old[key] = f[key]
for key in self._new:
f[key] = self._new[key]
class AddCommand(QUndoCommand):
def __init__(self, files, row):
QUndoCommand.__init__(self)
self._files = files
self._row = row
self._new = None
def undo(self):
self._files.delete([self._new])
def redo(self):
if self._new is None:
self._new = self._files.new(self._row)
else:
self._files.insert(self._row, self._new)
class DelCommand(QUndoCommand):
def __init__(self, files, row):
QUndoCommand.__init__(self)
self._files = files
self._row = row
self._old = self._files.get(row)
def undo(self):
self._files.insert(self._row, self._old)
def redo(self):
self._files.delete_i([self._row])
+118
View File
@@ -0,0 +1,118 @@
# Window.py -- Pamhyr
# Copyright (C) 2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import trace, timer
from PyQt5.QtWidgets import (
QAction, QListView,
)
from View.Tools.PamhyrWindow import PamhyrWindow
from View.AdditionalFiles.List import ListModel
from View.AdditionalFiles.Translate import AddFileTranslate
from View.AdditionalFiles.Edit.Window import EditAddFileWindow
class AddFileListWindow(PamhyrWindow):
_pamhyr_ui = "AdditionalFileList"
_pamhyr_name = "Additional files"
def __init__(self, study=None, config=None,
parent=None):
trad = AddFileTranslate()
name = trad[self._pamhyr_name] + " - " + study.name
super(AddFileListWindow, self).__init__(
title=name,
study=study,
config=config,
trad=trad,
options=[],
parent=parent
)
self.setup_list()
self.setup_connections()
def setup_list(self):
lst = self.find(QListView, f"listView")
self._list = ListModel(
list_view=lst,
data=self._study.river.additional_files,
undo=self._undo_stack,
trad=self._trad,
)
def setup_connections(self):
self.find(QAction, "action_add").triggered.connect(self.add)
self.find(QAction, "action_delete").triggered.connect(self.delete)
self.find(QAction, "action_edit").triggered.connect(self.edit)
def update(self):
self._list.update()
def selected_rows(self):
lst = self.find(QListView, f"listView")
return list(map(lambda i: i.row(), lst.selectedIndexes()))
def add(self):
rows = self.selected_rows()
if len(rows) > 0:
row = rows[0]
else:
row = 0
self._list.add(row)
def delete(self):
rows = self.selected_rows()
if len(rows) == 0:
return
self._list.delete(rows[0])
def edit(self):
rows = self.selected_rows()
for row in rows:
add_file = self._study.river.additional_files.files[row]
if self.sub_window_exists(
EditAddFileWindow,
data=[self._study, self._config, add_file]
):
continue
win = EditAddFileWindow(
study=self._study,
config=self._config,
add_file=add_file,
trad=self._trad,
undo=self._undo_stack,
parent=self,
)
win.show()
def _undo(self):
self._undo_stack.undo()
self.update()
def _redo(self):
self._undo_stack.redo()
self.update()
+27 -68
View File
@@ -1,5 +1,5 @@
# Plot.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -27,8 +27,6 @@ from PyQt5.QtCore import (
QCoreApplication
)
from View.BoundaryCondition.Edit.translate import BCETranslate
_translate = QCoreApplication.translate
logger = logging.getLogger()
@@ -47,99 +45,60 @@ class Plot(PamhyrPlot):
)
self._table_headers = self._trad.get_dict("table_headers")
header = self.data.header
self.label_x = self._table_headers[header[0]]
self.label_y = self._table_headers[header[1]]
self._mode = mode
self._isometric_axis = False
self._auto_relim_update = True
self._autoscale_update = True
def custom_ticks(self):
if self.data.header[0] != "time":
return
t0 = datetime.fromtimestamp(0)
nb = len(self.data.data)
mod = int(nb / 5)
mod = mod if mod > 0 else nb
fx = list(
map(
lambda x: x[1],
filter(
lambda x: x[0] % mod == 0,
enumerate(self.data.data)
)
)
)
xx = list(map(lambda v: v[0], fx))
if self._mode == "time":
xt = list(
map(
lambda v: str(
datetime.fromtimestamp(v[0]) - t0
).split(",")[0]
.replace("days", _translate("BoundaryCondition", "days"))
.replace("day", _translate("BoundaryCondition", "day")),
fx
)
)
else:
xt = list(
map(
lambda v: str(datetime.fromtimestamp(v[0]).date()),
fx
)
)
self.canvas.axes.set_xticks(ticks=xx, labels=xt, rotation=45)
self.set_ticks_time_formater()
@timer
def draw(self):
self.canvas.axes.cla()
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
self.init_axes()
if len(self.data) == 0:
self._init = False
return
self.draw_data()
self.custom_ticks()
self.idle()
self._init = True
def draw_data(self):
# Plot data
x = list(map(lambda v: v[0], self.data.data))
y = list(map(lambda v: v[1], self.data.data))
self._line, = self.canvas.axes.plot(
x, y,
color='r', lw=1.,
markersize=5, marker='+',
picker=30,
color=self.color_plot,
**self.plot_default_kargs
)
self.custom_ticks()
# Plot label
header = self.data.header
self.canvas.axes.set_xlabel(
self._table_headers[header[0]], color='black', fontsize=10
)
self.canvas.axes.set_ylabel(
self._table_headers[header[1]], color='black', fontsize=10
)
self.canvas.axes.autoscale_view(True, True, True)
self.canvas.figure.tight_layout()
self.canvas.figure.canvas.draw_idle()
# self.toolbar.update()
self._init = True
@timer
def update(self, ind=None):
if not self._init:
self.draw()
return
self.update_data()
self.update_idle()
def update_data(self):
x = list(map(lambda v: v[0], self.data.data))
y = list(map(lambda v: v[1], self.data.data))
self._line.set_data(x, y)
self.custom_ticks()
self.canvas.axes.relim()
self.canvas.axes.autoscale()
self.canvas.figure.tight_layout()
self.canvas.figure.canvas.draw_idle()
+7 -5
View File
@@ -1,5 +1,5 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -21,7 +21,11 @@ import traceback
from datetime import date, time, datetime, timedelta
from tools import trace, timer
from tools import (
trace, timer,
timestamp_to_old_pamhyr_date,
old_pamhyr_date_to_timestamp
)
from View.Tools.PamhyrTable import PamhyrTableModel
@@ -70,9 +74,7 @@ class TableModel(PamhyrTableModel):
value = f"{v:.4f}"
elif self._data.header[column] == "time":
if self._opt_data == "time":
t0 = datetime.fromtimestamp(0)
t = datetime.fromtimestamp(v)
value = str(t - t0)
value = timestamp_to_old_pamhyr_date(int(v))
else:
value = str(datetime.fromtimestamp(v))
else:
@@ -1,5 +1,5 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+4 -5
View File
@@ -1,5 +1,5 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -105,12 +105,11 @@ class EditBoundaryConditionWindow(PamhyrWindow):
trad = BCETranslate()
self._long_types = trad.get_dict("long_types")
name = self._pamhyr_name
name = trad[self._pamhyr_name]
if self._data is not None:
node_name = (self._data.node.name if self._data.node is not None
else _translate("BoundaryCondition", "Not associate"))
name = (
_translate("Edit boundary condition", self._pamhyr_name) +
else trad['not_associated'])
name += (
f" - {study.name} " +
f" - {self._data.name} ({self._data.id}) " +
f"({self._long_types[self._data.bctype]} - {node_name})"
+10 -6
View File
@@ -1,5 +1,5 @@
# translate.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
from PyQt5.QtCore import QCoreApplication
from View.Tools.PamhyrTranslate import PamhyrTranslate
from View.Translate import MainTranslate
from View.BoundaryCondition.translate import BCTranslate
@@ -29,12 +29,16 @@ class BCETranslate(BCTranslate):
def __init__(self):
super(BCETranslate, self).__init__()
self._dict["Edit Boundary Conditions"] = _translate(
"BoundaryCondition", "Edit boundary conditions"
)
self._sub_dict["table_headers"] = {
"x": _translate("BoundaryCondition", "X"),
"y": _translate("BoundaryCondition", "Y"),
"time": _translate("BoundaryCondition", "Time"),
"date": _translate("BoundaryCondition", "Date"),
"discharge": _translate("BoundaryCondition", "Discharge (m³/s)"),
"z": _translate("BoundaryCondition", "Z (m)"),
"time": self._dict["time"],
"date": self._dict["date"],
"discharge": self._dict["unit_discharge"],
"z": self._dict["unit_elevation"],
"solid": _translate("BoundaryCondition", "Solid (kg/s)"),
}
+3 -3
View File
@@ -1,5 +1,5 @@
# Table.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -85,7 +85,7 @@ class ComboBoxDelegate(QItemDelegate):
)
else:
self.editor.addItems(
[_translate("BoundaryCondition", "Not associate")] +
[self._trad["not_associated"]] +
self._data.nodes_names()
)
@@ -145,7 +145,7 @@ class TableModel(PamhyrTableModel):
elif self._headers[column] == "node":
n = self._lst.get(self._tab, row).node
if n is None:
return _translate("BoundaryCondition", "Not associate")
return self._trad["not_associated"]
return n.name
return QVariant()
+1 -1
View File
@@ -1,5 +1,5 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+16 -4
View File
@@ -1,5 +1,5 @@
# Window.py -- Pamhyr
# Copyright (C) 2023 INRAE
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
import logging
from tools import trace, timer
from tools import trace, timer, logger_exception
from View.Tools.PamhyrWindow import PamhyrWindow
@@ -37,6 +37,7 @@ from PyQt5.QtWidgets import (
QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
QWidget,
)
from Model.BoundaryCondition.BoundaryConditionTypes import (
@@ -68,13 +69,17 @@ class BoundaryConditionWindow(PamhyrWindow):
_pamhyr_name = "Boundary conditions"
def __init__(self, study=None, config=None, parent=None):
name = self._pamhyr_name + " - " + study.name
trad = BCTranslate()
name = (
trad[self._pamhyr_name] +
" - " + study.name
)
super(BoundaryConditionWindow, self).__init__(
title=name,
study=study,
config=config,
trad=BCTranslate(),
trad=trad,
parent=parent
)
@@ -166,6 +171,13 @@ class BoundaryConditionWindow(PamhyrWindow):
)
)
def set_active_tab(self, tab_id=0):
try:
tab_widget = self.find(QTabWidget, "tabWidget")
tab_widget.setCurrentIndex(tab_id)
except Exception as e:
logger_exception(e)
def add(self):
tab = self.current_tab()
rows = self.index_selected_rows()
Loaded 100 of 265 files, more files were not shown because too many files have changed in this diff. Show more