diff --git a/.vscode/launch.json b/.vscode/launch.json index 90250c7..c50c5ba 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,17 @@ { "version": "0.2.0", "configurations": [ + { + "name": "Compute gistim server", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/gistim/__main__.py", + "console": "integratedTerminal", + "args": [ + "compute", + "${input:computeGistimJsonPath}" + ] + }, { "name": "Attach to QGIS", "type": "debugpy", @@ -11,5 +22,13 @@ }, "justMyCode": true } + ], + "inputs": [ + { + "id": "computeGistimJsonPath", + "type": "promptString", + "description": "Path to the JSON input file for the compute command", + "default": "${workspaceFolder}/testdata/test.json" + } ] } diff --git a/README.md b/README.md index a45158d..818b103 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,14 @@ QGIS-Tim is an open source project for multi-layer groundwater flow simulations. QGIS-Tim provides a link between QGIS and the open source analytic -element method software: [TimML (steady-state)](https://github.com/mbakker7/timml) -and [TTim (transient)](https://github.com/mbakker7/ttim). +element method software: [timflow](https://github.com/timflow-org/timflow). The benefit of the analytic element method (AEM) is that no grid or time-stepping is required. Geohydrological features are represented by points, lines, and polygons. QGIS-Tim stores these features in a [GeoPackage](https://www.geopackage.org/). -QGIS-Tim consists of a "front-end" (the QGIS plugin) and a "back-end" (the TimML and TTim server). +QGIS-Tim consists of a "front-end" (the QGIS plugin) and a "back-end" (the timflow server). The front-end is a QGIS plugin that provides a limited graphical interface to setup model input, visualize, and analyze model input. The back-end is a Python package. The plugin converts the GeoPackage content to a JSON file or a Python script. The back-end reads the JSON file, does the @@ -48,19 +47,19 @@ Download and install a recent version of QGIS (>=3.28): This will add an icon to the toolbar(s). By clicking the icon, the plugin is started. -### Install the TimML and TTim server +### Install the timflow server With the plugin installed, we can already define model input and convert it to Python scripts or JSON files. -To run TimML and TTim computations directly from QGIS, we need to install a server program which contains TimML and TTim. +To run timflow computations directly from QGIS, we need to install a server program which contains timflow. 1. Start the QGIS-Tim plugin by clicking the QGIS-Tim icon in the toolbar. -2. Find and click the "Install TimML and TTim server" button at the bottom of the plugin window. +2. Find and click the "Install timflow server" button at the bottom of the plugin window. 3. Click the "Install latest release from GitHub" button to download and install the server program. Specific releases can also be manually downloaded from the [GitHub Releases page](https://github.com/Deltares/QGIS-Tim/releases): 1. Download the gistim ZIP file for your platform: Windows, macOS, or Linux. -2. Find and click the "Install TimML and TTim server" button at the bottom of the plugin window. +2. Find and click the "Install timflow server" button at the bottom of the plugin window. 3. Set the path to the downloaded ZIP file in the "Install from ZIP file" section. 4. Click the "Install" button. @@ -73,7 +72,7 @@ This repository uses [pixi](https://pixi.sh) to install required dependencies. 3. Call `pixi shell -e dev` to activate the development environment. 4. Call `pixi run install-qgis-plugins` to install this plugin and some debug tools inside of the included QGIS installation. 5. Call `pixi run install-backend` to install the backend as a symlink between the pyinstaller dist folder and %APPDATA%/qgis-tim. -6. Call `pixi run qgis` to start QGIS. The plugin should be installed and enabled and you should be able to see the versions of timml and ttim. +6. Call `pixi run qgis` to start QGIS. The plugin should be installed and enabled and you should be able to see the versions of timflow. After making a change to the plugin, you can reload the plugin with the [plugin reloader](https://plugins.qgis.org/plugins/plugin_reloader/). diff --git a/docs/developer.qmd b/docs/developer.qmd index 19662c8..74ff658 100644 --- a/docs/developer.qmd +++ b/docs/developer.qmd @@ -8,14 +8,11 @@ QGIS-Tim uses pixi to manage installing dependencies and run common tasks. Follow the instructions on the [Getting Started page](https://pixi.sh/). ### PyInstaller -To build the TimML and TTim server application with PyInstaller, run `pixi run build-backend` +To build the timflow server application with PyInstaller, run `pixi run build-backend` This creates a built PyInstaller application in `./dist/gistim`. -Run `pixi run zip-backend` to create a ZIP file of the PyInstaller application. -Run `pixi run zip-plugin` to create a ZIP file of the QGIS plugin that can be installed in QGIS. - -To test the created ZIP files: Install the QGIS from the ZIP file, start the QGIS plugin and try to install the ZIP file via the "Install TimML and TTim server" button. +Run `pixi run -e dev install-backend` to create a symlink between %APPDATA%/qgis-tim and ./dist/gistim. ## Creating new release diff --git a/docs/index.qmd b/docs/index.qmd index ad3805f..7dce898 100644 --- a/docs/index.qmd +++ b/docs/index.qmd @@ -10,8 +10,7 @@ listing: QGIS-Tim is an open source project for multi-layer groundwater flow simulations. QGIS-Tim provides a link between QGIS and the open source analytic -element method software: [TimML (steady-state)](https://github.com/mbakker7/timml) -and [TTim (transient)](https://github.com/mbakker7/ttim). +element method software: [timflow](https://github.com/timflow-org/timflow). The benefit of the analytic element method (AEM) is that no grid or time-stepping is required. Geohydrological features are represented by points, @@ -21,5 +20,5 @@ lines, and polygons. QGIS-Tim stores these features in a QGIS-Tim consists of a "front-end" and a "back-end". The front-end is a QGIS plugin that provides a limited graphical interface to setup model input, visualize, and analyze model input. The back-end is a Python package. It reads -the contents of the GeoPackage and transforms it into a TimML or TTim model, +the contents of the GeoPackage and transforms it into a timflow model, computes a result, and writes it to a file that the QGIS plugin loads. diff --git a/docs/install.qmd b/docs/install.qmd index dc97fda..3547bdd 100644 --- a/docs/install.qmd +++ b/docs/install.qmd @@ -35,14 +35,14 @@ This will add an icon to the toolbar(s). ![](figures/tutorial/button-Qgis-tim.pn By clicking the icon, the plugin is started. -## 3. Install the TimML and TTim server +## 3. Install the timflow server With the plugin installed, we can already define model input and convert it to Python scripts or JSON files. -To run TimML and TTim computations directly from QGIS, we need to install a server program which contains TimML and TTim. +To run timflow computations directly from QGIS, we need to install a server program which contains timflow. ### Method A: Install from GitHub (requires internet connection) 1. Start the QGIS-Tim plugin by clicking the QGIS-Tim icon in the toolbar. -1. Find and click the "Install TimML and TTim server" button at the bottom of the plugin window. +1. Find and click the "Install timflow server" button at the bottom of the plugin window. 1. Click the "Install latest release from GitHub" button to download and install the server program. ### Method B: Install from ZIP file @@ -51,6 +51,6 @@ Specific releases can also be manually downloaded from the [GitHub Releases page 1. Download the gistim ZIP file for your platform: Windows, macOS, or Linux. 1. Start the QGIS-Tim plugin by clicking the QGIS-Tim icon in the toolbar. -1. Find and click the "Install TimML and TTim server" button at the bottom of the plugin window. +1. Find and click the "Install timflow server" button at the bottom of the plugin window. 1. Set the path to the downloaded ZIP file in the "Install from ZIP file" section. 1. Click the "Install" button. diff --git a/docs/tutorial_Rijsenhout.qmd b/docs/tutorial_Rijsenhout.qmd index 8d83551..4b3b338 100644 --- a/docs/tutorial_Rijsenhout.qmd +++ b/docs/tutorial_Rijsenhout.qmd @@ -13,7 +13,7 @@ In this tutorial, you will learn how to: - install and use the QGIS-Tim plugin; - use the basic of QGIS for pre- and postprocessing of TIM; -- create several steady state models (TimML) and a transient model (TTim); +- create several steady state models and a transient model; - analyse the results; - export your model to a Python script. @@ -152,13 +152,13 @@ Your window looks like in @fig-Panel-QGIS-Tim. ![QGIS-Tim panel](figures/tutorial/Panel-QGIS-Tim.png){width=50% #fig-Panel-QGIS-Tim} -(@) Check in the *Layers* panel on the left that your new geopackage is added as a group.
A sub group **timml** for the steady state model input and the sub group **ttim** for the transient model input. +(@) Check in the *Layers* panel on the left that your new geopackage is added as a group.
A sub group **steady-state** for the steady state model input and the sub group **transient** for the transient model input. If you had no introduction to the Tim plugin, read the Intermezzo below for a general explanation of the components. > **Intermezzo:** *introduction Tabs on the Tim panel* > -> - Model Manager: an overview of the elements in your geopackage. In case you switch to transient modelling, an extra column with *ttim* elements is added. +> - Model Manager: an overview of the elements in your geopackage. In case you switch to transient modelling, an extra column with *transient* elements is added. > - Elements: a list of at least 16 Tim elements from which you can build your model. > - Results: here you can define your domain and cell size, decide if your model is transient or not and manage the output files. @@ -168,7 +168,7 @@ Now we are ready to define our first steady state model by parameterizing our Aq We start with a very simple 'model', only the parameters of a single aquifer.
Important message: all editing of model parameters and model elements you do in the *Layers* panel on the left! -(@) So select the layer "timml Aquifer:Aquifer" on the left. +(@) So select the layer "steady-state Aquifer:Aquifer" on the left. (@) Click your right mouse button and from the menu select *Attribute Table* to open the table in a new window.
**NB** Alternative is to press F6 or use the button *Open Attribute Table* (![](figures/tutorial/button-Qgis-OpenAttributeTable.png){width=3%}). (@) Start the editing mode with a click on the *Toggle Editing Mode* button (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}). (@) Hover with your mouse over the buttons and find the *Add Feature* button (![](figures/tutorial/button-AttributeTable-AddFeature.png){width=20%}). Perhaps button 5 from left. @@ -223,9 +223,9 @@ The calculation result is now visible and we see a mesh with just the value 0, n (@) Click on the element "Well" and a window opens to create a new (vector) layer in QGIS. (@) Give the layer a name, e.g. "DewateringWell" and click *OK*. -See that layer "timml Well:DewateringWell" is added to the timml sub group in your geopackage with 'point' as geometry. Also in the ttim sub group an element with the same name is added. This is a table that can store transient well data while referring to the x/y locations in the timml layer. Next step is to add the actual well, both the location and its parameters. +See that layer "steady-state Well:DewateringWell" is added to the steady-state sub group in your geopackage with 'point' as geometry. Also in the transient sub group an element with the same name is added. This is a table that can store transient well data while referring to the x/y locations in the steady-state layer. Next step is to add the actual well, both the location and its parameters. -(@) Select the layer "timml Well:DewateringWell". +(@) Select the layer "steady-state Well:DewateringWell". (@) Click your right mouse button and select the *Toggle Editing Mode* (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}). (@) To add a new well (feature) to the layer click the *Add Point Feature* button (![](figures/tutorial/button_AddPointFeature.png){width=4%}). (@) With your mouse, click on a location in the centre of the group of bombs. @@ -275,7 +275,7 @@ A single aquifer is of course not enough to describe the geology of our project ![Project area cross section (left) lifting the World War II bomb (right)](figures/tutorial/photo-fieldwork-liftbomb-crosssection.jpg){width=100% #fig-photo-fieldwork-liftbomb-crosssection} -(@) In your geopackage select the layer "timml Aquifer:Aquifer" and click your right mouse button. +(@) In your geopackage select the layer "steady-state Aquifer:Aquifer" and click your right mouse button. (@) From the menu select *Open Attribute Table* and the table opens in a new window. Once again, press F6 for a quick open of the Attribute Table. (@) Start the editing mode with a click on the *Toggle Editing Mode* button (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}). (@) Add three extra aquifers / features; click three times on the *Add Feature* button (![](figures/tutorial/button-AttributeTable-AddFeature.png){width=15%}). @@ -308,9 +308,9 @@ Let's now check the calculated heads for the 4 layers, first with the *Value Too Now we introduce a new but frequently used element: the sheet pile. (@) Return to the QGIS-Tim panel and go to the tab *Elements*. -(@) Click on the element "Leaky Line Doublet". +(@) Click on the element "Leaky Wall". (@) Give the layer a name, e.g. "sheetpile". -(@) In your geopackage select the layer "timml Leaky Line Doublet:sheetpile" and start editing using the *Toggle Editing Mode* button (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}). +(@) In your geopackage select the layer "steady-state Leaky Wall:sheetpile" and start editing using the *Toggle Editing Mode* button (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}). (@) In the editing mode, the *Add Line Feature* button (![](figures/tutorial/button_AddLineFeature.png){width=4%}) is available. Click the button and draw a box around the 5 bombs (click left to start, click right to close). (@) In the *Feature Attributes* window make resistance = 1500 and layer = 0. (@) Click *OK*. @@ -360,16 +360,16 @@ It is not possible for the plugin to automaticcaly read your geopackage as it is In the backgorund the plugin first removes all layers and than opens the geopackage again. You did not see it, did you? It happend in a blink of an eye. ## Model 5: add infiltration of drainwater -To prevent damage on the private properties caused by the dewatering, the authorities demand 50% of the drained flux to be infiltrated. For the infiltration a horizontal well of 400 m is used. In Tim this element is called "Line Sink Ditch". Let's add this element just along the road (Aalsmeerderweg) southeast of the project area. +To prevent damage on the private properties caused by the dewatering, the authorities demand 50% of the drained flux to be infiltrated. For the infiltration a horizontal well of 400 m is used. In Tim this element is called "Ditch". Let's add this element just along the road (Aalsmeerderweg) southeast of the project area. -(@) On the tab *Elements* in QGIS-Tim click on the element "Line Sink Ditch". +(@) On the tab *Elements* in QGIS-Tim click on the element "Ditch". (@) Give the layer a name, e.g. "InfiltrationWell". -See that layer "timml Line Sink Ditch:InfiltrationWell" is added to the timml sub group in your geopackage with 'line' as geometry. For the transient version of the model a table with the same name is added to the ttim sub group. Next step is to add the location of the horizontal well and its capacity. +See that layer "steady-state Ditch:InfiltrationWell" is added to the steady-state sub group in your geopackage with 'line' as geometry. For the transient version of the model a table with the same name is added to the transient sub group. Next step is to add the location of the horizontal well and its capacity. (@) Click the *Measure Line" button (![](figures/tutorial/button_MeasureLine.png){width=4%}) from the "Attributes Toolbar". (@) With your left mouse button try to get an idea what a distance of 400 m along the road looks like. Close the window. -(@) Select the layer "timml Line Sink Ditch:InfiltrationWell". +(@) Select the layer "steady-state Ditch:InfiltrationWell". (@) Start editing with the *Toggle Editing Mode*. (@) Use the *Add Line Feature* button (![](figures/tutorial/button_AddLineFeature.png){width=4%}) to draw a 400 m line (click left to start, click right to close). (@) Fill these feature within the table: discharge = -1000 (negative abstraction is flux into the model), resistance = 1, width = 1, layer = 0! not *NULL* ;-). By default order = 4. @@ -385,11 +385,11 @@ We have the Value Tool and the Cross section tool to check for calculated values (@) On the tab *Elements* in QGIS-Tim click on the element "Head Observation". (@) Give the layer a name, e.g. "Piezometers". -(@) Select the new layer "timml Head Observation:Piezometers". +(@) Select the new layer "steady-state Head Observation:Piezometers". (@) Start editing with the *Toggle Editing Mode* and use *Add Point Feature* button (![](figures/tutorial/button_AddPointFeature.png){width=4%}). (@) Click with your left mouse button to place a point near point A. (@) In the poped up window fill in Label = A and click *OK*. -(@) Go to the layer "timml Head Observation:Piezometers", click your right mouse button and activate "![](figures/tutorial/icon-showlabels.png){width=4%} show labels" +(@) Go to the layer "steady-state Head Observation:Piezometers", click your right mouse button and activate "![](figures/tutorial/icon-showlabels.png){width=4%} show labels" (@) Add point B close to the dwatering well (@fig-figure_ObservationsLocations). ![Observation locations (*A*-*E*) together with other Tim elements](figures/tutorial/figure_ObservationsLocations.png){width=80% #fig-figure_ObservationsLocations} @@ -398,13 +398,13 @@ Are you tired of the pop-up window every time you add a point? There is an optio (@) On the tab *Model Manager*, in the lowest section, check the option "Suppress attribute form pop-up after feature creation". (@) Place points C to E. -(@) Open the Attribute Table from layer "timml Head Observation:Piezometers" and fill in the Labels C to E. +(@) Open the Attribute Table from layer "steady-state Head Observation:Piezometers" and fill in the Labels C to E. (@) Save your changes and stop the editing mode. (@) Compute the model again. The observed values are saved in a new layer under the existing group "case-Rijsenhout output" and sub group "vector". -(@) In this sub group select the layer "case-Rijsenhout-timml Head Observation:Piezometers" and check the calculated values within this layer by opening the Attribute Table (F6). +(@) In this sub group select the layer "case-Rijsenhout-steady-state Head Observation:Piezometers" and check the calculated values within this layer by opening the Attribute Table (F6). (@) Close the Attribute Table. ### Draw Contour Lines @@ -420,10 +420,10 @@ A layer with your contours is saved in the group "case-Rijsenhout-output:vector" ## Model 7: determine the influence of the nearby lake East of the project area there is a large lake. What will be the influence of this lake? Let's find out.
-In Tim a lake is added as an inhomogeneity within the total model domain. This domain is described in table "timml Aquifer:Aquifer" we filled in with the first model. +In Tim a lake is added as an inhomogeneity within the total model domain. This domain is described in table "steady-state Aquifer:Aquifer" we filled in with the first model. (@) On the tab *Elements* in QGIS-Tim click on the element "Polygon Semi-Confined Top". -(@) Give the layer a name, e.g. "Lake" and find out that layer "timml Polygon Semi-Confined Top:Lake" is added to the geopackage. +(@) Give the layer a name, e.g. "Lake" and find out that layer "steady-state Polygon Semi-Confined Top:Lake" is added to the geopackage. (@) Start editing with the *Toggle Editing Mode* and use *Add Polygon Feature* button (![](figures/tutorial/button_AddPolygonFeature.png){width=4%}) to add the Lake contour.
**NB** Try to minimize the number of segments because each segment slows down the calculations. With QGIS it is tempting to use detail but the influence of detail on the outcome is small. (@) Fill the Lake feature with the following parameters: aquitard_c = 500, semiconf_top = -7 (bottom of the Lake) and semiconf_head = -2 (water level). (@) Save your changes and rerun the model. @@ -434,7 +434,7 @@ In Tim a lake is added as an inhomogeneity within the total model domain. This d You can not miss the effect of the Lake in this calculation. In many cases you like to analyse or even save this difference. Let's see how we can use Tim and QGIS to isolate the effect. Therefor we rerun the model without the Lake and rename the output. (@) In QGIS-Tim go to the tab *Model Manager*. -(@) In the list of Steady State elements switch off "timml Polygon Semi-Confined Top:Lake". +(@) In the list of Steady State elements switch off "steady-state Polygon Semi-Confined Top:Lake". (@) Go to the tab *Results*. (@) Click the button *Set path as ...* and change the name of the output, e.g. "case-Rijsenhout-NoLake". (@) Click *Compute* to run the model without the Lake. @@ -457,48 +457,48 @@ Now you are ready for the last step: make your model transient. We keep it simpl (@) In the section *Model Setup* turn on the option "Transient". (@) See below that only 5 elements have a transient component. -By selecting the "transient" option, columns containing extra parameters necessary for a transient model have been unhidden now. First of all we see it in the layer "timml Aquifer:Aquifer" where columns "storage" and "porosity are visible now. +By selecting the "transient" option, columns containing extra parameters necessary for a transient model have been unhidden now. First of all we see it in the layer "steady-state Aquifer:Aquifer" where columns "storage" and "porosity are visible now. -(@) In your geopackage select the layer "timml Aquifer:Aquifer". +(@) In your geopackage select the layer "steady-state Aquifer:Aquifer". (@) Open its table, start the editing mode and for every layer set both acquifer_s and acquitard_s to 0.001. Acquitard_s (layer 0) = 0.25. You can use copy and paste to do it quickly. **NB!** In transient mode, Tim can not handle aquitard with zero thickness so let's set the aquitard thickness to 0.1 m (@) Change the values in the column "aquifer_top" to -17.0, -22.1, -27.1 and -47.1 m. -(@) In your geopackage select the layer "ttim Temporal Settings:Aquifer" to define the temporal properties of the model. +(@) In your geopackage select the layer "transient Temporal Settings:Aquifer" to define the temporal properties of the model. (@) Open its table, start the editing mode and add a new feature. (@) Make sure that tmin=0.01, tmax=30, tstart=0, reference_date=2023-03-23 00:00:00. -(@) In your geopackage select the layer "ttim Computation Times:Domain" in order to define the moments in time for which raster output is saved. +(@) In your geopackage select the layer "transient Computation Times:Domain" in order to define the moments in time for which raster output is saved. (@) Open its table, start the editing mode and add 7 features / periods (click 7 times "Add feature"). (@) In the column "time" add the moments 1,2,5,10, 15, 20 and 30. (@) Save and Close the table. For the observations we can define a different set of output moments. -(@) In your geopackage select the layer "ttim Head Observation:Piezometers". +(@) In your geopackage select the layer "transient Head Observation:Piezometers". (@) Open its table, start the editing mode and add 10 features / periods (click 10 times "Add feature"). (@) In the column "time" add the moments 1,2,3,4,5,10,15,20,25 and 30. (@) Save and Close the table. Special attention for the Well package while it has 2 options to make it transient: -- Simple: a well can be switched on and off only once. Parameters are set in the stationary part of the model, so in "timml Well:DewateringWell". -- Detailed: a well can be switched on and off multiple times within the modelled period. Parameters are set in the transient part of the model, so in "ttim Well:DewateringWell". +- Simple: a well can be switched on and off only once. Parameters are set in the stationary part of the model, so in "steady-state Well:DewateringWell". +- Detailed: a well can be switched on and off multiple times within the modelled period. Parameters are set in the transient part of the model, so in "transient Well:DewateringWell". In this tutorial we show you the simple version. -(@) In your geopackage select the layer "timml Well:DewateringWell". +(@) In your geopackage select the layer "steady-state Well:DewateringWell". (@) Open its table, start the editing mode and see that 6 extra columns with time dependent parameters are visible now ("time_start", "time_end", "discharge_transient", "caisson_radius", "slug" and "timeseries_id"). (@) Switch off the Steady State abstraction, make discharge = 0 (was 2000). (@) Switch on the Transient abstraction: time_start = 2, time_end = 30, discharge_transient = 2000, caisson_radius = 1. (@) Save your changes. (@) Compute your transient model in the tab *Results*. -In case of a successful calculation a new layer is added to your Vector output: case-Rijsenhout-ttim Head Observation:Piezometers. This layer contains transient data which is indicated with the clock icon right from the layer name. There are 2 ways to visualize these calculated heads in the observations point a) animation over time and b) timeseries at location. +In case of a successful calculation a new layer is added to your Vector output: case-Rijsenhout-transient Head Observation:Piezometers. This layer contains transient data which is indicated with the clock icon right from the layer name. There are 2 ways to visualize these calculated heads in the observations point a) animation over time and b) timeseries at location. (@) For the animation over time, activate the *Temporal Control Panel* with the button ![](figures/tutorial/button_TemporalControllerPanel.png){width=4%} on the Map Navigation Toolbar. (@) For timeseries at location activate the Timeseries panel with the *Timeseries* button (![](figures/tutorial/button_iMOD-TimeSeries.png){width=4%}) on the iMOD Toolbar. -(@) Be sure that "case-Rijsenhout-ttim Head Observation:Piezometers" is checked and "case-Rijsenhout-timml Head Observation:Piezometers" is unchecked. +(@) Be sure that "case-Rijsenhout-transient Head Observation:Piezometers" is checked and "case-Rijsenhout-steady-state Head Observation:Piezometers" is unchecked. (@) In the Temporal Controller panel click the green play button (![](figures/tutorial/button_TemporalControllerPanel-menu.png){width=14%}). Navigation buttons appear. (@) Increase the *Step* to 16 hours and start the animation with a click on the *Play* button (![](figures/tutorial/button_TemporalControler-play.png){width=4%}). @@ -514,7 +514,7 @@ Only the first few days you see most prominent drawdown. Let's now display the t In the same way you can display the time series from the Observations. -(@) In the iMOD time series panel select the layer "case-Rijsenhout-ttim Head Observation:Piezometers". +(@) In the iMOD time series panel select the layer "case-Rijsenhout-transient Head Observation:Piezometers". (@) For "ID column:" select *label* and for "Variable:" select *head_layer0*. Don't forget to **deselect *fid***. (@) Click the button *Select Points* and draw a box with your mouse to select one or more observation points. (@) Click the *Plot* button and the selected timeseries are added to the chart. diff --git a/docs/tutorial_TheHague.qmd b/docs/tutorial_TheHague.qmd index cb665f6..b01997e 100644 --- a/docs/tutorial_TheHague.qmd +++ b/docs/tutorial_TheHague.qmd @@ -244,13 +244,13 @@ Your window looks like in @fig-Panel-QGIS-Tim_TheHague. ![QGIS-Tim panel](figures/tutorial/Panel-QGIS-Tim_TheHague.png){width=50% #fig-Panel-QGIS-Tim_TheHague fig-align="left"} -(@) Check in the *Layers* panel on the left that your new geopackage is added as a group.
A sub group **timml** for the steady state model input, the sub group **ttim** for the transient model input and a series of output formats (vector/mesh/raster). +(@) Check in the *Layers* panel on the left that your new geopackage is added as a group.
A sub group **steady-state** for the steady state model input, the sub group **transient** for the transient model input and a series of output formats (vector/mesh/raster). If you had no introduction to the Tim plugin, read the Intermezzo below for a general explanation of the components. > **Intermezzo:** *introduction Tabs on the Tim panel* > -> - Model Manager: an overview of the elements in your geopackage. In case you switch to transient modelling, an extra column with *ttim* elements is added. +> - Model Manager: an overview of the elements in your geopackage. In case you switch to transient modelling, an extra column with *transient* elements is added. > - Elements: a list of at least 16 Tim elements from which you can build your model. > - Results: here you can define your domain and cell size, decide if your model is transient or not and manage the output files. @@ -281,7 +281,7 @@ For marine deposits at -12 a value of 50 to 100 days per meter layer thickness i We are now ready to define our first steady state model by parameterizing our Aquifer. -(@) From the *Layers* panel, select the layer *timml Aquifer:Aquifer*. +(@) From the *Layers* panel, select the layer *steady-state Aquifer:Aquifer*. (@) Click your right mouse button and from the menu select *Open Attribute table* (![](figures/tutorial/button-Qgis-OpenAttributeTable.png){width=3%}). Search for the same icon somewhere on the *Attributes Toolbar*. (@) Switch to the editing mode in the table with a click on (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}) *Toggle Editing*. (@) Then by clicking 3 times on (![](figures/tutorial/button-Qgis-AttributeTable-AddFeature.png){width=4%}) *Add feature* you will see new rows are added. @@ -297,17 +297,17 @@ We are now ready to define our first steady state model by parameterizing our Aq In the QGIS-Tim Window we now introduce the following elements for ground water modelling in the QGIS-Tim tab *Element*: -- Leaky Line Doublet +- Leaky Wall - Well -### Adding a Leaky Line Doublet +### Adding a Leaky Wall -(@) In the QGIS-Tim window go to tab *Elements* and select the button *Leaky Line Doublet*. +(@) In the QGIS-Tim window go to tab *Elements* and select the button *Leaky Wall*. (@) Fill in the name of the layer in the pop-up panel, e.g. 'sheet_pile', and click *OK* and this new Layer is added to the *Layers* panel. First, we will *draw* the location of the sheet pile before *adding* the parameter values. -(@) In the *Layers* panel right click on the layer ![](figures/tutorial/figure_Leakylinedoublet_icon.png){width=4%} *timml Leaky Line Doublet:sheet_pile* and start the editing mode by clicking the *Toggle Editing* button (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}). +(@) In the *Layers* panel right click on the layer ![](figures/tutorial/figure_Leakylinedoublet_icon.png){width=4%} *steady-state Leaky Wall:sheet_pile* and start the editing mode by clicking the *Toggle Editing* button (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}). Two important remarks before drawing the sheet pile: @@ -323,20 +323,20 @@ Two important remarks before drawing the sheet pile: (@) Draw the sheet pile around the building pit (start south corner) with your left mouse button and close the feature on the first point. (@) In the pop-up window fill in the resistance (1000 d, see \* below) and layer number (layer=0, see \*\* below) as in @fig-LeakylinedoubletFeatureAttributes and click OK to close the window. -![The characteristics of the Leaky line doublet](figures/tutorial/figure_LeakylinedoubletFeatureAttributes.png){width=60% #fig-LeakylinedoubletFeatureAttributes fig-align="left"} +![The characteristics of the Leaky Wall](figures/tutorial/figure_LeakylinedoubletFeatureAttributes.png){width=60% #fig-LeakylinedoubletFeatureAttributes fig-align="left"} > Remarks to the provided values:
> \* Because of a known issue in the TimML software, until this issue is resolved, the value of the resistance must be multiplied by the permeability. For normal sheet pile walls a resistance value of 100-250 d for interlock leakage is a good choice. In this case the chosen value needs to be increased by multiplying with the applicable aquifer permeability in the effected layer (R=100 d becomes R=10*100 d).
> \*\* In the real-world counting starts with 1. However, Tim is programmed in Python and in Python counting starts with 0. You will get used to it. (@) Close the editing mode with a click on (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}) and you are asked to save your changes. -(@) Open the attribute table for *Leaky Line Doublet* (click ![](figures/tutorial/button-Qgis-OpenAttributeTable.png){width=3%} or press F6) to check hydraulic resistance values for the sheet pile walls. +(@) Open the attribute table for *Leaky Wall* (click ![](figures/tutorial/button-Qgis-OpenAttributeTable.png){width=3%} or press F6) to check hydraulic resistance values for the sheet pile walls. ### Adding a Well (@) In GIS-Tim go to the tab *Elements* and select the *Well* element. (@) A name for the element can be given in the pop-up panel, e.g. *pumping_wells*. -(@) In the *Layers* panel right click on the layer ![](figures/tutorial/figure_well_icon.png){width=3%} *timml Well:pumping_wells* and start the editing mode by clicking the *Toggle Editing* button (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}). +(@) In the *Layers* panel right click on the layer ![](figures/tutorial/figure_well_icon.png){width=3%} *steady-state Well:pumping_wells* and start the editing mode by clicking the *Toggle Editing* button (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png ){width=4%}). (@) Next click on *Add point feature* (![](figures/tutorial/button_AddPointFeature.png){width=4%}). (@) With you left mouse button add the first well location similar to point 1 in @fig-SchematizationTheHague. (@) In the pop-up window, fill in the well parameters discharge (50 m3/d), radius (0.1 m), resistance (1 d) and layer (0). @@ -344,16 +344,16 @@ Two important remarks before drawing the sheet pile: ![Schematization of the pumping wells, sheet piles and observation locations](figures/tutorial/figure_SchematizationTheHague.png){width=60% #fig-SchematizationTheHague fig-align="left"} -(@) In the *Layers* panel right select layer *timml Well:pumping_wells* and open the *Attribute Table (F6)*. +(@) In the *Layers* panel right select layer *steady-state Well:pumping_wells* and open the *Attribute Table (F6)*. (@) Start the editing mode and fill in the values shown in @fig-WellAttributeTable. Don't forget the column 'Label'.
The discharge value in the table is a first guess to be adjusted later to desired level of -3.5 m groundwater lowering in the building pit. (@) Stop the editing mode, save your work and close the window. -(@) Select layer *timml Well:pumping_wells* again, click right and from the menu select *Show labels*. +(@) Select layer *steady-state Well:pumping_wells* again, click right and from the menu select *Show labels*. ![Well properties](figures/tutorial/figure_WellAttributeTable.png){width=100% #fig-WellAttributeTable} When you finished the input of the wells and their parameters, you have to look back to the combination of wells and sheet pile wall. The reason is that near a well the flow is strong and therefore the flow through the wall is increased. This may lead to extremities in the calculation if wall segments are chosen too large. Tim uses control points but they are set at regular distances on the doublet (the number of control points is 1+order). It is necessary to divide the wall in smaller sections near well locations. The length of each section should be chosen equal to approximately the distance of the wall to the nearest well. -(@) Select the Leaky Line Doublet in the *Layers* panel and start the editing mode. +(@) Select the Leaky Wall in the *Layers* panel and start the editing mode. (@) Activate the Vertex Tool (![](figures/tutorial/button_VertexTool.png){width=4%}) and then hoover along the sheet pile line in your drawing. The line element near your pointer lights up. (@) With the combination of **Shift + double left click**, you can add a new vertex to the line. Repeat that for the number of points you want to add. @@ -393,7 +393,7 @@ The city authorities that perform quality checks on the effect of construction p (@) In the QGIS-Tim panel go to the *Elements* tab and select the element *Observation*. (@) Give a name in the pop-up panel, e.g. "observations". -(@) Then go to the *Layers* panel and select the layer ![](figures/tutorial/figure_Observation_icon.png){width=3%}*timml Observation:observations*. +(@) Then go to the *Layers* panel and select the layer ![](figures/tutorial/figure_Observation_icon.png){width=3%}*steady-state Observation:observations*. (@) Go to the toolbar with drawing options and activate Toggle editing (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png){width=4%}). (@) Go right to the Add point feature (![](figures/tutorial/button_AddPointFeature.png){width=3%}) and drop some piezometers in the drawing.
We propose to use 5 points (see @fig-SchematizationTheHague): 1 point in the centre of the building pit, 1 near the lower corner outside, 1 outside near the middle of the eastern sheet pile section and just 2 near street corners. (@) Compute the model again. @@ -402,7 +402,7 @@ Results of calculations at the observation locations are presented as *Vector* d (@) Uncheck/check layers in order to display observation results only. -By default, the label at each observation location is the calculated head for layer 0. Perhaps you see a second number near the location. For your information: this is the "location number" label belonging to the model input in layer *timml Observation:observations*. +By default, the label at each observation location is the calculated head for layer 0. Perhaps you see a second number near the location. For your information: this is the "location number" label belonging to the model input in layer *steady-state Observation:observations*. We can observe that the lowering of groundwater around the building pit is quite high due to leakage of the sheet piles or leakage through the bottom clay layer with small resistance. Therefore, it is needed to improve the wall quality or the length. First we check the effect of the clay layer by studying a cross section. @@ -425,12 +425,12 @@ The authorities demand a drawdown effect of dewatering at a maximum of 0.10 m at To check whether the wall resistance or the bottom resistance of the layer 1 (below the building pit) is more important we can make 2 variations; one with C-clay=200 d and one with R-wall=500 d.
Of course you can change your model input, rerun the model and overwrite your model results. The next steps show you how to change the model input and save the results in separate *.gpkg and *.nc files. -(@) In the input group select layer *timml Aquifer:...* +(@) In the input group select layer *steady-state Aquifer:...* (@) Open the *Attrribute Table* (F6) and change the value for "aquitard_c" in layer 1 into 200 d. (@) In the QGIS-Tim panel go to the tab *Results* and change the name of the output, e.g. case-TheHague_v1. (@) Click *Compute* to run variant 1. -Check in the *Layers* panel and see that the results are not overwritten but added to the groups, e.g. layer *case-TheHague_v1-timml Observation:observations* is added to the group *Vector*. +Check in the *Layers* panel and see that the results are not overwritten but added to the groups, e.g. layer *case-TheHague_v1-steady-state Observation:observations* is added to the group *Vector*. (@) Fill in your calculated heads at the observation locations in @tbl-CalculatedHeads2Variants or use Excel. @@ -447,8 +447,8 @@ Check in the *Layers* panel and see that the results are not overwritten but add Let's now run Variant 2. -(@) In layer *timml Aquifer:...* reset the value for "aquitard_c" in layer 1 to the default of 40 d. -(@) In layer *timml Leaky Line Doublet:...* change the value for "resistance" into 5000 d (500x10). +(@) In layer *steady-state Aquifer:...* reset the value for "aquitard_c" in layer 1 to the default of 40 d. +(@) In layer *steady-state Leaky Wall:...* change the value for "resistance" into 5000 d (500x10). (@) In the QGIS-Tim panel go to the tab *Results* and change the name of the output, e.g. case-TheHague_v2. (@) Click *Compute* to run variant 2. (@) Fill in your calculated heads at the observation locations in the table above. @@ -461,16 +461,16 @@ Suppose the best guess value of the clay layer resistance was right, then a miti If we want to create extra depth of the sheet pile we will have to introduce it in a deeper layer. There are 2 options to implement it in your model: -- Add a copy of the geometry of the sheet pile wall to the existing *Leaky Line Doublet* shape and assign it to layer 1. -- We recommend to create an extra *Leaky Line Doublet* element. In this case it is more easy to switch on/off this additional element in your sensitivity analysis. +- Add a copy of the geometry of the sheet pile wall to the existing *Leaky Wall* shape and assign it to layer 1. +- We recommend to create an extra *Leaky Wall* element. In this case it is more easy to switch on/off this additional element in your sensitivity analysis. -How to copy the sheet pile wall to an extra *Leaky Line Doublet* element? +How to copy the sheet pile wall to an extra *Leaky Wall* element? -(@) In the QGIS-Tim panel go to the tab *Elements* and add a second *Leaky Line Doublet* and give it a name, e.g. "sheet_pile_L1" +(@) In the QGIS-Tim panel go to the tab *Elements* and add a second *Leaky Wall* and give it a name, e.g. "sheet_pile_L1" (@) Go to the tab *Model Manager* and see that the element separately is added to the list. Here is can switch this element on / off for a calculation. -(@) In the *Layers* panel select the new layer *timml Leaky Line Doublet:sheet_pile_l1*. +(@) In the *Layers* panel select the new layer *steady-state Leaky Wall:sheet_pile_l1*. (@) Open its *Attribute Table* (F6) and start the editing mode. The table is empty. -(@) Also open the *Attribute Table* of the first *Leaky Line Doublet* and select the existing element. +(@) Also open the *Attribute Table* of the first *Leaky Wall* and select the existing element. (@) Click on the *Copy* button (![](figures/tutorial/button_Copy_Selected_Row.png){width=3%}) in the source table to copy the selected row to the clipboard. ![](figures/tutorial/figure_Leakylinedoublet_copy.png){width=70%} @@ -509,9 +509,9 @@ Still, probably some decrease of interlock leakage is needed when sheet piles ar ## Effect of a not closed wall (about 20 cm) Authorities are afraid that leakage incidents could be harmful for surrounding monuments. -The effect of leakage can be studied by creating a fictitious little opening in the wall. This can be done e.g. by changing the values of first and last coordinate of the leaky line doublet. +The effect of leakage can be studied by creating a fictitious little opening in the wall. This can be done e.g. by changing the values of first and last coordinate of the Leaky Wall. -(@) Select the *Leaky Line Doublet* in the *Layers* panel +(@) Select the *Leaky Wall* in the *Layers* panel (@) In the editing toolbar go to the toggle editing option (![](figures/tutorial/button-Qgis-AttributeTable-StartEditingMode.png){width=4%}) and check the vertex option (![](figures/tutorial/button_VertexTool.png){width=4%}). (@) On the drawing panel select a point in the line element of the wall and right click. @@ -534,7 +534,7 @@ QGIS-Tim offers the opportunity to export the geopackage of the created model to ![Python script](figures/tutorial/figure_PythonExport01.png){width=90% #fig-figure_PythonExport01} -As can be seen the converted Python file start with calls (e.g. import timml) to main necessary Python packages. After that, for each timm element in the model, all data coordinates and parameter values follow. At the end of the Python file the "model.solve" command is stated after which all head values in the domain with the desired mesh density are determined and also at demanded observation points. +As can be seen the converted Python file start with calls (e.g. import steady-state) to main necessary Python packages. After that, for each timm element in the model, all data coordinates and parameter values follow. At the end of the Python file the "model.solve" command is stated after which all head values in the domain with the desired mesh density are determined and also at demanded observation points. As can be seen the Python script for TimML is written in a very dedicated and condensed manner. @@ -701,7 +701,7 @@ Nevertheless in this section we want to guide you on setting up a basic transien (@) Return to QGIS and in the QGIS-Tim panel go to the tab *Model Manager*. (@) In the section *Model Setup* turn on the option "Transient". -(@) In the panel *Layers* select *timml Aquifer:Aquifer*. +(@) In the panel *Layers* select *steady-state Aquifer:Aquifer*. As can be seen in @fig-Panel-TimmlAquiferAttrTable_v02, the matrix of properties is extended in the transient mode with cells for transient parameters, like specific storage coefficients (aquitard_s, and aquifer_s) and porosities (aquitard_npor and aquifer_npor). Take care that specific storage coefficient is a storage per meter layer thickness. In older MWell course material a speadsheet is presented for estimation of coefficient values but there we calculated storage coefficients per whole layer. Those values should be divided by layer thickness. @@ -709,31 +709,31 @@ As can be seen in @fig-Panel-TimmlAquiferAttrTable_v02, the matrix of properties (@) Fill in the Table with the corresponding values. (@) In the TTim section in the *Layers panel* go to the list of elements for transient calculations. -(@) Select *ttim Temporal Settings:Aquifer* and open its *Attribute Table* (F6). Here the length of the time series is specified. +(@) Select *transient Temporal Settings:Aquifer* and open its *Attribute Table* (F6). Here the length of the time series is specified. (@) Set the starting time to 0. But calculations take place for the range of time steps between "time_min" and "time_max". The time unit is according to central settings in the project, mostly time in days. "Time_min" should not be zero but given a slight offset. Here we also find a "Stehfest_M" number, related to the number of terms in the calculation method performing transformation of formulas in solving differential equations. A reference date can be set to relate the calculation to real time data. (@) Fill in the table according to @fig-Panel-TTimAquiferAttrTable_v01. -![Table for *ttim Temporal Settings:Aquifer* ](figures/tutorial/Panel-TTim AquiferAttrTable_v01.png){width=70% #fig-Panel-TTimAquiferAttrTable_v01} +![Table for *transient Temporal Settings:Aquifer* ](figures/tutorial/Panel-TTim AquiferAttrTable_v01.png){width=70% #fig-Panel-TTimAquiferAttrTable_v01} **NB!**: In QGIS it is an obligation to use a "reference_date" to get the model running and present outcomes! -(@) Select *ttim Computation Times:Domain* and set the time values for time steps where we want to get calculations of spatially distributed heads in mesh or raster points and contours. +(@) Select *transient Computation Times:Domain* and set the time values for time steps where we want to get calculations of spatially distributed heads in mesh or raster points and contours. -![Table for *ttim Computation Times:Domain* ](figures/tutorial/Panel-TTim_DomainAttrTable_v01.png){width=30% #fig-Panel-TTim_DomainAttrTable_v01} +![Table for *transient Computation Times:Domain* ](figures/tutorial/Panel-TTim_DomainAttrTable_v01.png){width=30% #fig-Panel-TTim_DomainAttrTable_v01} For this case we will leave this table blank, because calculating several head distributions at different time steps is rather time consuming during this course. -(@) Select *ttim Observation:observations* and here we can set the time steps for a time series at certain points we want to monitor the calculation results. We set points at intervals that follow a (approximately) logarithmic increase in time intervals. Proposed values are shown in the next table. +(@) Select *transient Observation:observations* and here we can set the time steps for a time series at certain points we want to monitor the calculation results. We set points at intervals that follow a (approximately) logarithmic increase in time intervals. Proposed values are shown in the next table. -![Table for *ttim Observation:observations* ](figures/tutorial/Panel-TTim_ObservationsAttrTable_v01.png){width=40% #fig-Panel-TTim_ObservationsAttrTable_v01} +![Table for *transient Observation:observations* ](figures/tutorial/Panel-TTim_ObservationsAttrTable_v01.png){width=40% #fig-Panel-TTim_ObservationsAttrTable_v01} Don’t choose exactly the same time as when changing the flow. So if 60 is an end value, choose 59.9. -In the *Attribute Table* of layer *ttim Well:pumping_wells* we can set the discharge amount. The value might change during time when excavation is considered or construction is performed in phases. For each change we have to add a line of input. In case there are a lot of switch on/off moments, this is a lot of work.
We just leave this option without any change because there is an other option in case each well has only a singel start and end time. +In the *Attribute Table* of layer *transient Well:pumping_wells* we can set the discharge amount. The value might change during time when excavation is considered or construction is performed in phases. For each change we have to add a line of input. In case there are a lot of switch on/off moments, this is a lot of work.
We just leave this option without any change because there is an other option in case each well has only a singel start and end time. -(@) Therefor go to the layer *timml Well:pumping_wells* layer. This layer contains simple elements to make it behave as a simple Timm element. +(@) Therefor go to the layer *steady-state Well:pumping_wells* layer. This layer contains simple elements to make it behave as a simple Timm element. (@) In the *Attribute Table* make start_time=5, end_time=30 and discharge_transient=15. (@) But fill in a value of 0 m3/d in column "Discharge" because this variable is part of TimML well element. We use the "discharge_transient" variable to define flow in TTim. Remember: Solution of TTim is superposed on solution of TimML. diff --git a/gistim/__main__.py b/gistim/__main__.py index 2c4a053..77f8830 100644 --- a/gistim/__main__.py +++ b/gistim/__main__.py @@ -5,10 +5,6 @@ from contextlib import contextmanager, redirect_stderr, redirect_stdout from os import devnull -# Make sure we explicitly import besselaesnumba for pyinstaller. -# It's a dynamic import inside of timml. -from timml.besselaesnumba import besselaesnumba # noqa: F401 - import gistim.compute diff --git a/gistim/compute.py b/gistim/compute.py index 1c93154..553dab7 100644 --- a/gistim/compute.py +++ b/gistim/compute.py @@ -6,34 +6,33 @@ import numpy as np import pandas as pd -import timml -import ttim +import timflow import xarray as xr from gistim.geopackage import CoordinateReferenceSystem, write_geopackage from gistim.netcdf import write_raster, write_ugrid -TIMML_MAPPING = { - "Constant": timml.Constant, - "Uflow": timml.Uflow, - "CircAreaSink": timml.CircAreaSink, - "Well": timml.Well, - "HeadWell": timml.HeadWell, - "PolygonInhomMaq": timml.PolygonInhomMaq, - "HeadLineSinkString": timml.HeadLineSinkString, - "LineSinkDitchString": timml.LineSinkDitchString, - "LeakyLineDoubletString": timml.LeakyLineDoubletString, - "ImpLineDoubletString": timml.ImpLineDoubletString, - "BuildingPit": timml.BuildingPitMaq, - "LeakyBuildingPit": timml.LeakyBuildingPitMaq, +STEADY_MAPPING = { + "Constant": timflow.steady.Constant, + "Uflow": timflow.steady.Uflow, + "CircAreaSink": timflow.steady.CircAreaSink, + "Well": timflow.steady.Well, + "HeadWell": timflow.steady.HeadWell, + "PolygonInhomMaq": timflow.steady.PolygonInhomMaq, + "RiverString": timflow.steady.RiverString, + "DitchString": timflow.steady.DitchString, + "LeakyWallString": timflow.steady.LeakyWallString, + "ImpermeableWallString": timflow.steady.ImpermeableWallString, + "BuildingPit": timflow.steady.BuildingPitMaq, + "LeakyBuildingPit": timflow.steady.LeakyBuildingPitMaq, } -TTIM_MAPPING = { - "CircAreaSink": ttim.CircAreaSink, - "Well": ttim.Well, - "HeadWell": ttim.HeadWell, - "HeadLineSinkString": ttim.HeadLineSinkString, - "LineSinkDitchString": ttim.LineSinkDitchString, - "LeakyLineDoubletString": ttim.LeakyLineDoubletString, +TRANSIENT_MAPPING = { + "CircAreaSink": timflow.transient.CircAreaSink, + "Well": timflow.transient.Well, + "HeadWell": timflow.transient.HeadWell, + "RiverString": timflow.transient.RiverString, + "DitchString": timflow.transient.DitchString, + "LeakyWallString": timflow.transient.LeakyWallString, } @@ -47,28 +46,28 @@ def initialize_elements(model, mapping, data): return elements -def initialize_timml(data): +def initialize_steady(data): aquifer = data.pop("ModelMaq") - timml_model = timml.ModelMaq(**aquifer) - elements = initialize_elements(timml_model, TIMML_MAPPING, data) - return timml_model, elements + steady_model = timflow.steady.ModelMaq(**aquifer) + elements = initialize_elements(steady_model, STEADY_MAPPING, data) + return steady_model, elements -def initialize_ttim(data, timml_model): +def initialize_transient(data, steady_model): aquifer = data.pop("ModelMaq") - ttim_model = ttim.ModelMaq(**aquifer, timmlmodel=timml_model) - elements = initialize_elements(ttim_model, TTIM_MAPPING, data) - return ttim_model, elements + transient_model = timflow.transient.ModelMaq(**aquifer, steady=steady_model) + elements = initialize_elements(transient_model, TRANSIENT_MAPPING, data) + return transient_model, elements @singledispatch def headgrid(model, **kwargs): - raise TypeError("Expected timml or ttim model") + raise TypeError("Expected steady or transient model") @headgrid.register def _( - model: timml.Model, + model: timflow.steady.Model, xmin: float, xmax: float, ymin: float, @@ -77,12 +76,12 @@ def _( **_, ) -> xr.DataArray: """ - Compute the headgrid of the TimML model, and store the results + Compute the headgrid of the steady model, and store the results in an xarray DataArray with the appropriate dimensions. Parameters ---------- - model: timml.Model + model: timflow.steady.Model Solved model to get heads from data: Dict[str, Any] @@ -96,7 +95,7 @@ def _( y = np.arange(ymax, ymin, -spacing) - 0.5 * spacing head = model.headgrid(xg=x, yg=y) nlayer = model.aq.find_aquifer_data(x[0], y[0]).naq - layer = [i for i in range(nlayer)] + layer = list(range(nlayer)) return xr.DataArray( data=head, name="head", @@ -107,7 +106,7 @@ def _( @headgrid.register def _( - model: ttim.ModelMaq, + model: timflow.transient.ModelMaq, xmin: float, xmax: float, ymin: float, @@ -126,14 +125,14 @@ def _( nlayer = model.aq.find_aquifer_data(x[0], y[0]).naq if 0.0 in time: - steady_head = model.timmlmodel.headgrid(xg=x, yg=y)[:, np.newaxis, :, :] + steady_head = model.steady.headgrid(xg=x, yg=y)[:, np.newaxis, :, :] transient_head = model.headgrid(xg=x, yg=y, t=time[1:]) head = np.hstack((steady_head, transient_head)) else: head = model.headgrid(xg=x, yg=y, t=time) # Other coordinates - layer = [i for i in range(nlayer)] + layer = list(range(nlayer)) time = pd.to_datetime(start_date) + pd.to_timedelta(time, "D") return xr.DataArray( data=head, @@ -145,12 +144,12 @@ def _( @singledispatch def compute_head_observations(model, observations): - raise TypeError("Expected timml or ttim model") + raise TypeError("Expected steady or transient model") @compute_head_observations.register def _( - model: timml.Model, + model: timflow.steady.Model, observations: Dict, **_, ) -> Dict[str, pd.DataFrame]: @@ -169,7 +168,7 @@ def _( @compute_head_observations.register def _( - model: ttim.ModelMaq, observations: Dict, start_date: pd.Timestamp + model: timflow.transient.ModelMaq, observations: Dict, start_date: pd.Timestamp ) -> Dict[str, pd.DataFrame]: d = { "geometry": [], @@ -205,7 +204,7 @@ def extract_discharges(elements, nlayers, **_): for layername, content in elements.items(): sample = content[0] - if isinstance(sample, timml.WellBase): + if isinstance(sample, timflow.steady.WellBase): table_rows = [] for well in content: row = {f"discharge_layer{i}": q for i, q in enumerate(well.discharge())} @@ -216,7 +215,9 @@ def extract_discharges(elements, nlayers, **_): table_rows.append(row) tables[f"discharge-{layername}"] = pd.DataFrame.from_records(table_rows) - elif isinstance(sample, (timml.LineSinkDitchString, timml.HeadLineSinkString)): + elif isinstance( + sample, (timflow.steady.DitchString, timflow.steady.RiverString) + ): table_rows = [] for linestring in content: discharges = linestring.discharge_per_linesink() @@ -235,11 +236,11 @@ def extract_discharges(elements, nlayers, **_): @singledispatch def compute_discharge_observations(model, observations): - raise TypeError("Expected timml or ttim model") + raise TypeError("Expected steady or transient model") @compute_discharge_observations.register -def _(model: timml.Model, observations: Dict): +def _(model: timflow.steady.Model, observations: Dict): table_rows = [] for kwargs in observations: xy = kwargs["xy"] @@ -261,13 +262,13 @@ def _(model: timml.Model, observations: Dict): @compute_discharge_observations.register -def _(model: ttim.ModelMaq, observations: Dict): - # intnormflux is not supported by ttim (yet). +def _(model: timflow.transient.ModelMaq, observations: Dict): + # intnormflux is not supported by transient (yet). return None def write_output( - model: Union[timml.Model, ttim.ModelMaq], + model: Union[timflow.steady.Model, timflow.transient.ModelMaq], elements: Dict[str, Any], data: Dict[str, Any], path: Union[pathlib.Path, str], @@ -317,11 +318,11 @@ def compute_steady( with open(path, "r") as f: data = json.load(f) - timml_model, elements = initialize_timml(data["timml"]) - timml_model.solve() + steady_model, elements = initialize_steady(data["steady-state"]) + steady_model.solve() write_output( - timml_model, + steady_model, elements, data, path, @@ -335,14 +336,16 @@ def compute_transient( with open(path, "r") as f: data = json.load(f) - timml_model, _ = initialize_timml(data["timml"]) - ttim_model, ttim_elements = initialize_ttim(data["ttim"], timml_model) - timml_model.solve() - ttim_model.solve() + steady_model, _ = initialize_steady(data["steady-state"]) + transient_model, transient_elements = initialize_transient( + data["transient"], steady_model + ) + steady_model.solve() + transient_model.solve() write_output( - ttim_model, - ttim_elements, + transient_model, + transient_elements, data, path, ) diff --git a/pixi.lock b/pixi.lock index 4b21328..e227abe 100644 --- a/pixi.lock +++ b/pixi.lock @@ -44,19 +44,14 @@ environments: - pypi: https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/0b/43/a81f20050a3115b57d62c8e781446949512eac36690dc384ccea65ff4cc1/fonttools-4.63.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/f1/bbecd2f867b97abebe0f9b53d750f862251b40337e061b36676ded3d920f/pandas-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/44/0b/0615dbedb98f5b32a35a53290fbdc6e22306968109278d7e58df82d7a9f6/numba-0.65.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/46/27/5799b020e4cdfb25a7c951c06a96397c135efcdc21b78d853bbd9c814c7d/llvmlite-0.47.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/79/db/e28c1b83e3680740aa78925f5fb2ae4d16207207419ad75ea9fe604f8676/matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/c5/9fcb7e0e69cef59cf10c746b84f7d58b08bc66a6b7d459783c5a4f6101a6/numpy-2.4.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -89,18 +84,13 @@ environments: - pypi: https://files.pythonhosted.org/packages/01/88/a8952b6d5c21e74cbf158515b779666f692846502623e9e3c39d8e8ba25f/llvmlite-0.47.0.tar.gz - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/16/b5c76b838fd9bf6ce84d3a53346b8874ec05c5f0040d75ef2c320100cd2a/pandas-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl - pypi: https://files.pythonhosted.org/packages/49/50/965308c703f085f225db2886813b27e015b8b3438c350b22dd65b52c2a2c/fonttools-4.63.0-cp311-cp311-macosx_10_9_x86_64.whl - pypi: https://files.pythonhosted.org/packages/4c/8c/290f021104741fea63769c31494f5324c0cd249bf536a65a4350767b1f22/matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl - pypi: https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -137,22 +127,17 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_36.conda - pypi: https://files.pythonhosted.org/packages/08/60/defa5e69641db890a63be281f41345f4c33b157824eaf0b9fad3e08b0dcb/fonttools-4.63.0-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/0d/271aace3342157c64700c9ff4c59c7b392f3dbab393692e8db6fbe7ab96c/matplotlib-3.10.9-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/50/59227d06bdc96e23322713c381af4e77420949d8cd8a042c79e0043096cc/llvmlite-0.47.0-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/63/05d193dbb4b5eec1eca73822d80da98b511f8328ad4ae3ca4caf0f4db91d/numpy-2.4.4-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/bd/9a/af61ec03b3116c161fd7a06b9e8a265729a8718458333e8ffbb06d9a3978/numba-0.65.1-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/eb/62/c321f13b5ba1819fc8dca456c7fce578da2dcfecff1abbf0eaddf8406c0f/pandas-3.0.3-cp311-cp311-win_amd64.whl @@ -189,19 +174,14 @@ environments: - pypi: https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/0b/43/a81f20050a3115b57d62c8e781446949512eac36690dc384ccea65ff4cc1/fonttools-4.63.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/f1/bbecd2f867b97abebe0f9b53d750f862251b40337e061b36676ded3d920f/pandas-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/44/0b/0615dbedb98f5b32a35a53290fbdc6e22306968109278d7e58df82d7a9f6/numba-0.65.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/46/27/5799b020e4cdfb25a7c951c06a96397c135efcdc21b78d853bbd9c814c7d/llvmlite-0.47.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/79/db/e28c1b83e3680740aa78925f5fb2ae4d16207207419ad75ea9fe604f8676/matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/c5/9fcb7e0e69cef59cf10c746b84f7d58b08bc66a6b7d459783c5a4f6101a6/numpy-2.4.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl @@ -226,18 +206,13 @@ environments: - pypi: https://files.pythonhosted.org/packages/01/88/a8952b6d5c21e74cbf158515b779666f692846502623e9e3c39d8e8ba25f/llvmlite-0.47.0.tar.gz - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/16/b5c76b838fd9bf6ce84d3a53346b8874ec05c5f0040d75ef2c320100cd2a/pandas-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl - pypi: https://files.pythonhosted.org/packages/49/50/965308c703f085f225db2886813b27e015b8b3438c350b22dd65b52c2a2c/fonttools-4.63.0-cp311-cp311-macosx_10_9_x86_64.whl - pypi: https://files.pythonhosted.org/packages/4c/8c/290f021104741fea63769c31494f5324c0cd249bf536a65a4350767b1f22/matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl - pypi: https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl - pypi: https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl @@ -263,22 +238,17 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_36.conda - pypi: https://files.pythonhosted.org/packages/08/60/defa5e69641db890a63be281f41345f4c33b157824eaf0b9fad3e08b0dcb/fonttools-4.63.0-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/0d/271aace3342157c64700c9ff4c59c7b392f3dbab393692e8db6fbe7ab96c/matplotlib-3.10.9-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/50/59227d06bdc96e23322713c381af4e77420949d8cd8a042c79e0043096cc/llvmlite-0.47.0-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/63/05d193dbb4b5eec1eca73822d80da98b511f8328ad4ae3ca4caf0f4db91d/numpy-2.4.4-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/bd/9a/af61ec03b3116c161fd7a06b9e8a265729a8718458333e8ffbb06d9a3978/numba-0.65.1-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -652,22 +622,17 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - pypi: https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/0b/43/a81f20050a3115b57d62c8e781446949512eac36690dc384ccea65ff4cc1/fonttools-4.63.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/26/30/5b1a619941bb458d1d3768377254d5d9e9965405daa2bd75f4317eae86f0/qgis_plugin_manager-1.7.5.tar.gz - pypi: https://files.pythonhosted.org/packages/32/f1/bbecd2f867b97abebe0f9b53d750f862251b40337e061b36676ded3d920f/pandas-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/33/d5/9b8482ed572be40d51c3fcbb87451e446e56b5e19487cd60340b8ef51eb4/PyQt5_stubs-5.15.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/44/0b/0615dbedb98f5b32a35a53290fbdc6e22306968109278d7e58df82d7a9f6/numba-0.65.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/46/27/5799b020e4cdfb25a7c951c06a96397c135efcdc21b78d853bbd9c814c7d/llvmlite-0.47.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/79/db/e28c1b83e3680740aa78925f5fb2ae4d16207207419ad75ea9fe604f8676/matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c2/97/e0ab7241e2b9f35e03d288f2bb1304c1a1d47219601d0df971a851f9db38/qgis_stubs-0.2.0.post1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl @@ -716,22 +681,17 @@ environments: - pypi: https://files.pythonhosted.org/packages/01/88/a8952b6d5c21e74cbf158515b779666f692846502623e9e3c39d8e8ba25f/llvmlite-0.47.0.tar.gz - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/26/30/5b1a619941bb458d1d3768377254d5d9e9965405daa2bd75f4317eae86f0/qgis_plugin_manager-1.7.5.tar.gz - pypi: https://files.pythonhosted.org/packages/33/d5/9b8482ed572be40d51c3fcbb87451e446e56b5e19487cd60340b8ef51eb4/PyQt5_stubs-5.15.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/16/b5c76b838fd9bf6ce84d3a53346b8874ec05c5f0040d75ef2c320100cd2a/pandas-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl - pypi: https://files.pythonhosted.org/packages/49/50/965308c703f085f225db2886813b27e015b8b3438c350b22dd65b52c2a2c/fonttools-4.63.0-cp311-cp311-macosx_10_9_x86_64.whl - pypi: https://files.pythonhosted.org/packages/4c/8c/290f021104741fea63769c31494f5324c0cd249bf536a65a4350767b1f22/matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl - pypi: https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c2/97/e0ab7241e2b9f35e03d288f2bb1304c1a1d47219601d0df971a851f9db38/qgis_stubs-0.2.0.post1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl - pypi: https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl @@ -1025,24 +985,19 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/zlib-ng-2.3.3-h0261ad2_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda - pypi: https://files.pythonhosted.org/packages/08/60/defa5e69641db890a63be281f41345f4c33b157824eaf0b9fad3e08b0dcb/fonttools-4.63.0-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/26/30/5b1a619941bb458d1d3768377254d5d9e9965405daa2bd75f4317eae86f0/qgis_plugin_manager-1.7.5.tar.gz - pypi: https://files.pythonhosted.org/packages/33/d5/9b8482ed572be40d51c3fcbb87451e446e56b5e19487cd60340b8ef51eb4/PyQt5_stubs-5.15.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/0d/271aace3342157c64700c9ff4c59c7b392f3dbab393692e8db6fbe7ab96c/matplotlib-3.10.9-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/50/59227d06bdc96e23322713c381af4e77420949d8cd8a042c79e0043096cc/llvmlite-0.47.0-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/9a/af61ec03b3116c161fd7a06b9e8a265729a8718458333e8ffbb06d9a3978/numba-0.65.1-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/c2/97/e0ab7241e2b9f35e03d288f2bb1304c1a1d47219601d0df971a851f9db38/qgis_stubs-0.2.0.post1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/eb/62/c321f13b5ba1819fc8dca456c7fce578da2dcfecff1abbf0eaddf8406c0f/pandas-3.0.3-cp311-cp311-win_amd64.whl @@ -11353,14 +11308,6 @@ packages: version: 1.5.0 sha256: 3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - name: dill - version: 0.4.1 - sha256: 1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d - requires_dist: - - objgraph>=1.7.2 ; extra == 'graph' - - gprof2dot>=2022.7.29 ; extra == 'profile' - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/26/30/5b1a619941bb458d1d3768377254d5d9e9965405daa2bd75f4317eae86f0/qgis_plugin_manager-1.7.5.tar.gz name: qgis-plugin-manager version: 1.7.5 @@ -11467,41 +11414,6 @@ packages: - pytest ; extra == 'dev' - pytest-xvfb ; extra == 'dev' requires_python: '>=3.5' -- pypi: https://files.pythonhosted.org/packages/38/7e/7b91c89a4cf0f543a83be978657afb20c86af6d725253e319589dcc4ce52/lmfit-1.3.4-py3-none-any.whl - name: lmfit - version: 1.3.4 - sha256: afce1593b42324d37ae2908249b0c55445e2f4c1a0474ff706a8e2f7b5d949fa - requires_dist: - - asteval>=1.0 - - numpy>=1.24 - - scipy>=1.10.0 - - uncertainties>=3.2.2 - - dill>=0.3.4 - - build ; extra == 'dev' - - check-wheel-contents ; extra == 'dev' - - flake8-pyproject ; extra == 'dev' - - pre-commit ; extra == 'dev' - - twine ; extra == 'dev' - - cairosvg ; extra == 'doc' - - corner ; extra == 'doc' - - emcee>=3.0.0 ; extra == 'doc' - - ipykernel ; extra == 'doc' - - jupyter-sphinx>=0.2.4 ; extra == 'doc' - - matplotlib ; extra == 'doc' - - numdifftools ; extra == 'doc' - - pandas ; extra == 'doc' - - pillow ; extra == 'doc' - - pycairo ; sys_platform == 'win32' and extra == 'doc' - - sphinx ; extra == 'doc' - - sphinx-gallery>=0.10 ; extra == 'doc' - - sphinxcontrib-svg2pdfconverter ; extra == 'doc' - - sympy ; extra == 'doc' - - coverage ; extra == 'test' - - flaky ; extra == 'test' - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - - lmfit[dev,doc,test] ; extra == 'all' - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/42/16/b5c76b838fd9bf6ce84d3a53346b8874ec05c5f0040d75ef2c320100cd2a/pandas-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl name: pandas version: 3.0.3 @@ -11748,60 +11660,6 @@ packages: - trove-classifiers>=2024.10.12 ; extra == 'tests' - defusedxml ; extra == 'xmp' requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/77/39/8333b23e230581fd4587fa3edcc5a9b07af5184a9258bacefcda862341b2/timml-6.9.0-py3-none-any.whl - name: timml - version: 6.9.0 - sha256: 018d4c64ebb5f5c1f78aa3ef0087f312ee2e9d8f9320f5459703bbf7dc61b2fa - requires_dist: - - numpy - - scipy - - numba - - matplotlib - - pandas - - pytest ; extra == 'ci' - - pytest-cov ; extra == 'ci' - - pytest-xdist ; extra == 'ci' - - nbval ; extra == 'ci' - - jupyter ; extra == 'ci' - - shapely ; extra == 'ci' - - ruff ; extra == 'ci' - - timml[ci] ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinx-design ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - numpydoc ; extra == 'docs' - - myst-nb ; extra == 'docs' - - sphinxcontrib-bibtex ; extra == 'docs' - - sphinx-autoapi ; extra == 'docs' - requires_python: '>=3.11' -- pypi: https://files.pythonhosted.org/packages/77/ab/04d8ded05ebee9f8959a21b3dd8da637f14a9e08cb33cae435863e5f8564/ttim-0.8.0-py3-none-any.whl - name: ttim - version: 0.8.0 - sha256: ee305609e87b6bb8ffe6b48060bef6f8116da000f4dd20cab2170f5fb41d184f - requires_dist: - - numpy - - scipy - - numba - - matplotlib - - lmfit - - pandas - - pytest ; extra == 'ci' - - pytest-cov ; extra == 'ci' - - pytest-sugar ; extra == 'ci' - - jupyter ; extra == 'ci' - - shapely ; extra == 'ci' - - coveralls ; extra == 'ci' - - ruff ; extra == 'ci' - - timml ; extra == 'ci' - - ttim[ci] ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinx-design ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - numpydoc ; extra == 'docs' - - myst-nb ; extra == 'docs' - - sphinxcontrib-bibtex ; extra == 'docs' - - sphinx-autoapi ; extra == 'docs' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/79/db/e28c1b83e3680740aa78925f5fb2ae4d16207207419ad75ea9fe604f8676/matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl name: matplotlib version: 3.10.9 @@ -11845,21 +11703,6 @@ packages: version: 1.5.0 sha256: 2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27 requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - name: uncertainties - version: 3.2.3 - sha256: 313353900d8f88b283c9bad81e7d2b2d3d4bcc330cbace35403faaed7e78890a - requires_dist: - - numpy ; extra == 'arrays' - - pytest ; extra == 'test' - - pytest-codspeed ; extra == 'test' - - pytest-cov ; extra == 'test' - - scipy ; extra == 'test' - - sphinx ; extra == 'doc' - - sphinx-copybutton ; extra == 'doc' - - python-docs-theme ; extra == 'doc' - - uncertainties[arrays,doc,test] ; extra == 'all' - requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl name: contourpy version: 1.3.3 @@ -11954,19 +11797,6 @@ packages: - pytest-xdist ; extra == 'test-no-images' - wurlitzer ; extra == 'test-no-images' requires_python: '>=3.11' -- pypi: https://files.pythonhosted.org/packages/99/31/6cf181011dc738c33bf6ba7aea2e8e1d3c1f71b7dab1942f3054f66f6202/asteval-1.0.8-py3-none-any.whl - name: asteval - version: 1.0.8 - sha256: 6c64385c6ff859a474953c124987c7ee8354d781c76509b2c598741c4d1d28e9 - requires_dist: - - build ; extra == 'dev' - - twine ; extra == 'dev' - - sphinx ; extra == 'doc' - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - - coverage ; extra == 'test' - - asteval[dev,doc,test] ; extra == 'all' - requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/a2/50/59227d06bdc96e23322713c381af4e77420949d8cd8a042c79e0043096cc/llvmlite-0.47.0-cp311-cp311-win_amd64.whl name: llvmlite version: 0.47.0 @@ -12013,6 +11843,37 @@ packages: version: '2026.2' sha256: bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7 requires_python: '>=2' +- pypi: https://files.pythonhosted.org/packages/cf/5b/6aba31c675c6e1b2726115d4cbaf41ace13d17f08ced4e47f555e5cdd23a/timflow-0.2.0-py3-none-any.whl + name: timflow + version: 0.2.0 + sha256: 028b982598d77646b63314097a4bd0762d53e17ff636c3cffa6620be0b11782d + requires_dist: + - numpy + - scipy + - numba + - matplotlib + - pandas + - ruff ; extra == 'lint' + - tqdm ; extra == 'parallel' + - timflow[parallel] ; extra == 'optional' + - lmfit ; extra == 'optional' + - timflow[lint,optional] ; extra == 'ci' + - pytest ; extra == 'ci' + - pytest-cov ; extra == 'ci' + - pytest-xdist ; extra == 'ci' + - nbval ; extra == 'ci' + - jupyter ; extra == 'ci' + - shapely ; extra == 'ci' + - timflow[ci] ; extra == 'docs' + - sphinx ; extra == 'docs' + - sphinx-design ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - numpydoc ; extra == 'docs' + - myst-nb ; extra == 'docs' + - sphinxcontrib-bibtex ; extra == 'docs' + - sphinx-autoapi ; extra == 'docs' + - timflow[docs] ; extra == 'dev' + requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/cf/c5/9fcb7e0e69cef59cf10c746b84f7d58b08bc66a6b7d459783c5a4f6101a6/numpy-2.4.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl name: numpy version: 2.4.4 diff --git a/pixi.toml b/pixi.toml index 25ab548..2bbc4ee 100644 --- a/pixi.toml +++ b/pixi.toml @@ -1,7 +1,7 @@ [workspace] name = "gistim" version = "0.6.0" -description = "Connects TimML and TTim Analytic Element modeling to QGIS" +description = "Connects timflow Analytic Element modeling to QGIS" authors = ["Huite Bootsma"] channels = ["conda-forge"] platforms = ["win-64", "linux-64", "osx-64"] @@ -25,8 +25,7 @@ pyinstaller = "*" [pypi-dependencies] pandas = "*" -timml = ">=6.3.0" -ttim = ">=0.8.0" +timflow = ">=0.2.0" xarray = "*" numpy = "*" diff --git a/plugin/qgistim/README.txt b/plugin/qgistim/README.txt index 1388787..fd65565 100644 --- a/plugin/qgistim/README.txt +++ b/plugin/qgistim/README.txt @@ -1,16 +1,14 @@ -This QGIS plugin serves to easily create model input TimML and TTim analytic +This QGIS plugin serves to easily create model input timflow analytic element models: -* https://github.com/mbakker7/timml -* https://github.com/mbakker7/ttim +* [timflow](https://github.com/timflow-org/timflow) Analytic element input is typically a collection of points, lines, and polygons. This plugin represent a single model with a single GeoPackage. The different elements are represented as layers in the GeoPackage, and also as ordinary vector layers in QGIS. -To run the model with TimML and TTim, this plugin relies on a server program called -`gistim`. +To run the model with timflow, this plugin relies on a server program called `gistim`. Find the repository and issue tracker here: https://github.com/Deltares/QGIS-Tim diff --git a/plugin/qgistim/core/elements/__init__.py b/plugin/qgistim/core/elements/__init__.py index 5ef7fce..dec00bd 100644 --- a/plugin/qgistim/core/elements/__init__.py +++ b/plugin/qgistim/core/elements/__init__.py @@ -11,12 +11,12 @@ from qgistim.core.elements.discharge_observation import DischargeObservation from qgistim.core.elements.domain import Domain from qgistim.core.elements.element import Element -from qgistim.core.elements.head_line_sink import HeadLineSink +from qgistim.core.elements.head_line_sink import River from qgistim.core.elements.headwell import HeadWell, RemoteHeadWell -from qgistim.core.elements.impermeable_line_doublet import ImpermeableLineDoublet +from qgistim.core.elements.impermeable_line_doublet import ImpermeableWall from qgistim.core.elements.leaky_building_pit import LeakyBuildingPit -from qgistim.core.elements.leaky_line_doublet import LeakyLineDoublet -from qgistim.core.elements.line_sink_ditch import LineSinkDitch +from qgistim.core.elements.leaky_line_doublet import LeakyWall +from qgistim.core.elements.line_sink_ditch import Ditch from qgistim.core.elements.observation import HeadObservation from qgistim.core.elements.polygon_area_sink import PolygonAreaSink from qgistim.core.elements.polygon_inhomogeneity import PolygonInhomogeneity @@ -34,11 +34,11 @@ Well, HeadWell, RemoteHeadWell, - HeadLineSink, - LineSinkDitch, + River, + Ditch, CircularAreaSink, - ImpermeableLineDoublet, - LeakyLineDoublet, + ImpermeableWall, + LeakyWall, PolygonAreaSink, PolygonSemiConfinedTop, PolygonInhomogeneity, @@ -54,15 +54,15 @@ def parse_name(layername: str) -> Tuple[str, str, str]: """ Based on the layer name find out: - * whether it's a timml or ttim element; + * whether it's a steady-state or transient element; * which element type it is; * what the user provided name is. For example: - parse_name("timml Headwell:drainage") -> ("timml", "Head Well", "drainage") + parse_name("steady-state Headwell:drainage") -> ("steady-state", "Head Well", "drainage") """ prefix, name = layername.split(":") - element_type = re.split("timml |ttim ", prefix)[1] + element_type = re.split("steady-state |transient ", prefix)[1] mapping = { "Computation Times": "Domain", "Temporal Settings": "Aquifer", @@ -71,15 +71,15 @@ def parse_name(layername: str) -> Tuple[str, str, str]: "Leaky Building Pit Properties": "Leaky Building Pit", } element_type = mapping.get(element_type, element_type) - if "timml" in prefix: + if "steady-state" in prefix: if "Properties" in prefix: - tim_type = "timml_assoc" + tim_type = "steady-state_assoc" else: - tim_type = "timml" - elif "ttim" in prefix: - tim_type = "ttim" + tim_type = "steady-state" + elif "transient" in prefix: + tim_type = "transient" else: - raise ValueError("Neither timml nor ttim in layername") + raise ValueError("Neither steady-state nor transient in layername") return tim_type, element_type, name diff --git a/plugin/qgistim/core/elements/aquifer.py b/plugin/qgistim/core/elements/aquifer.py index d3fc498..4ebbd61 100644 --- a/plugin/qgistim/core/elements/aquifer.py +++ b/plugin/qgistim/core/elements/aquifer.py @@ -19,7 +19,7 @@ class AquiferSchema(TableSchema): - timml_schemata = { + steady_schemata = { "layer": AllRequired(Range()), "aquifer_top": AllRequired(StrictlyDecreasing()), "aquifer_bottom": AllRequired(StrictlyDecreasing()), @@ -28,18 +28,18 @@ class AquiferSchema(TableSchema): "semiconf_top": OptionalFirstOnly(), "semiconf_head": OptionalFirstOnly(), } - timml_consistency_schemata = ( + steady_consistency_schemata = ( SemiConfined(), AllGreaterEqual("aquifer_top", "aquifer_bottom"), ) - ttim_schemata = { + transient_schemata = { "aquitard_s": OffsetAllRequired(Positive()), "aquifer_s": AllRequired(Positive()), } class TemporalSettingsSchema(SingleRowSchema): - ttim_schemata = { + transient_schemata = { "time_min": Required(StrictlyPositive()), "laplace_inversion_M": Required(StrictlyPositive()), "start_date": Required(), @@ -49,7 +49,7 @@ class TemporalSettingsSchema(SingleRowSchema): class Aquifer(TransientElement): element_type = "Aquifer" geometry_type = "No Geometry" - timml_attributes = [ + steady_attributes = [ QgsField("layer", QVariant.Int), QgsField("aquifer_top", QVariant.Double), QgsField("aquifer_bottom", QVariant.Double), @@ -62,12 +62,12 @@ class Aquifer(TransientElement): QgsField("aquitard_npor", QVariant.Double), QgsField("aquifer_npor", QVariant.Double), ] - ttim_attributes = ( + transient_attributes = ( QgsField("time_min", QVariant.Double), QgsField("laplace_inversion_M", QVariant.Int), QgsField("start_date", QVariant.DateTime), ) - ttim_defaults = { + transient_defaults = { "time_min": QgsDefaultValue("0.01"), "laplace_inversion_M": QgsDefaultValue("10"), } @@ -82,42 +82,42 @@ class Aquifer(TransientElement): def __init__(self, path: str, name: str): self._initialize_default(path, name) - self.timml_name = f"timml {self.element_type}:Aquifer" - self.ttim_name = "ttim Temporal Settings:Aquifer" + self.steady_name = f"steady-state {self.element_type}:Aquifer" + self.transient_name = "transient Temporal Settings:Aquifer" def write(self): - self.timml_layer = geopackage.write_layer( - self.path, self.timml_layer, self.timml_name, newfile=True + self.steady_layer = geopackage.write_layer( + self.path, self.steady_layer, self.steady_name, newfile=True ) - self.ttim_layer = geopackage.write_layer( - self.path, self.ttim_layer, self.ttim_name + self.transient_layer = geopackage.write_layer( + self.path, self.transient_layer, self.transient_name ) self.set_defaults() def remove_from_geopackage(self): """This element may not be removed.""" - return + pass - def to_timml(self) -> ElementExtraction: - missing = self.check_timml_columns() + def extract_steady_data(self) -> ElementExtraction: + missing = self.check_steady_columns() if missing: return ElementExtraction(errors=missing) - data = self.table_to_dict(layer=self.timml_layer) - errors = self.schema.validate_timml(name=self.timml_layer.name(), data=data) + data = self.table_to_dict(layer=self.steady_layer) + errors = self.schema.validate_steady(name=self.steady_layer.name(), data=data) return ElementExtraction(errors=errors, data=data) - def to_ttim(self) -> ElementExtraction: - missing = self.check_ttim_columns() + def extract_transient_data(self) -> ElementExtraction: + missing = self.check_transient_columns() if missing: return ElementExtraction(errors=missing) - data = self.table_to_dict(layer=self.timml_layer) - time_data = self.table_to_records(layer=self.ttim_layer) + data = self.table_to_dict(layer=self.steady_layer) + time_data = self.table_to_records(layer=self.transient_layer) errors = { - **self.schema.validate_ttim(name=self.timml_layer.name(), data=data), - **self.assoc_schema.validate_ttim( - name=self.ttim_layer.name(), data=time_data + **self.schema.validate_transient(name=self.steady_layer.name(), data=data), + **self.assoc_schema.validate_transient( + name=self.transient_layer.name(), data=time_data ), } if errors: @@ -126,6 +126,6 @@ def to_ttim(self) -> ElementExtraction: def extract_data(self, transient: bool) -> ElementExtraction: if transient: - return self.to_ttim() + return self.extract_transient_data() else: - return self.to_timml() + return self.extract_steady_data() diff --git a/plugin/qgistim/core/elements/building_pit.py b/plugin/qgistim/core/elements/building_pit.py index 645a51c..82d6924 100644 --- a/plugin/qgistim/core/elements/building_pit.py +++ b/plugin/qgistim/core/elements/building_pit.py @@ -23,7 +23,7 @@ class BuildingPitSchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), "inhomogeneity_id": Required(Membership("properties inhomogeneity_id")), "order": Required(Positive()), @@ -32,7 +32,7 @@ class BuildingPitSchema(RowWiseSchema): class AssociatedBuildingPitSchema(TableSchema): - timml_schemata = { + steady_schemata = { "inhomogeneity_id": AllRequired(), "layer": AllRequired(Equals("aquifer layers")), "aquifer_top": AllRequired(StrictlyDecreasing()), @@ -43,7 +43,7 @@ class AssociatedBuildingPitSchema(TableSchema): "semiconf_head": OptionalFirstOnly(), "wall_in_layer": AllRequired(AtleastOneTrue()), } - timml_consistency_schemata = ( + steady_consistency_schemata = ( SemiConfined(), AllGreaterEqual("aquifer_top", "aquifer_bottom"), ) @@ -52,7 +52,7 @@ class AssociatedBuildingPitSchema(TableSchema): class BuildingPit(AssociatedElement): element_type = "Building Pit" geometry_type = "Polygon" - timml_attributes = ( + steady_attributes = ( QgsField("inhomogeneity_id", QVariant.Int), QgsField("order", QVariant.Int), QgsField("ndegrees", QVariant.Int), @@ -70,7 +70,7 @@ class BuildingPit(AssociatedElement): QgsField("aquitard_npor", QVariant.Double), QgsField("aquifer_npor", QVariant.Double), ] - timml_defaults = { + steady_defaults = { "order": QgsDefaultValue("4"), "ndegrees": QgsDefaultValue("6"), "inhomogeneity_id": QgsDefaultValue("1"), @@ -88,7 +88,7 @@ def renderer(cls) -> QgsSingleSymbolRenderer: color=TRANSPARENT_RED, color_border=RED, width_border="0.75" ) - def process_timml_row(self, row: Dict[str, Any], grouped: Dict[int, Any]): + def process_steady_row(self, row: Dict[str, Any], grouped: Dict[int, Any]): inhom_id = row["inhomogeneity_id"] raw_data = grouped[inhom_id] layers = [i for i, active in enumerate(raw_data["wall_in_layer"]) if active] diff --git a/plugin/qgistim/core/elements/circular_area_sink.py b/plugin/qgistim/core/elements/circular_area_sink.py index 4c1b69b..aff6f02 100644 --- a/plugin/qgistim/core/elements/circular_area_sink.py +++ b/plugin/qgistim/core/elements/circular_area_sink.py @@ -20,17 +20,17 @@ class CircularAreaSinkSchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(CircularGeometry()), "rate": Required(), "layer": Required(Membership("aquifer layers")), } - ttim_schemata = { + transient_schemata = { "time_start": Optional(Positive()), "time_end": Optional(Positive()), - "timeseries_id": Optional(Membership("ttim timeseries IDs")), + "timeseries_id": Optional(Membership("transient timeseries IDs")), } - ttim_consistency_schemata = ( + transient_consistency_schemata = ( AllOrNone("time_start", "time_end", "rate_transient"), NotBoth("time_start", "timeseries_id"), ) @@ -44,7 +44,7 @@ class CircularAreaSinkSchema(RowWiseSchema): class CircularAreaSink(TransientElement): element_type = "Circular Area Sink" geometry_type = "Polygon" - timml_attributes = ( + steady_attributes = ( QgsField("rate", QVariant.Double), QgsField("layer", QVariant.Int), QgsField("label", QVariant.String), @@ -53,7 +53,7 @@ class CircularAreaSink(TransientElement): QgsField("rate_transient", QVariant.Double), QgsField("timeseries_id", QVariant.Int), ) - ttim_attributes = ( + transient_attributes = ( QgsField("timeseries_id", QVariant.Int), QgsField("time_start", QVariant.Double), QgsField("rate", QVariant.Double), @@ -80,7 +80,7 @@ def _centroid_and_radius(self, row): radius = ((x - xc) ** 2 + (y - yc) ** 2) ** 0.5 return xc, yc, radius - def process_timml_row(self, row, other=None) -> Dict[str, Any]: + def process_steady_row(self, row, other=None) -> Dict[str, Any]: xc, yc, radius = self._centroid_and_radius(row) return { "xc": xc, @@ -90,7 +90,7 @@ def process_timml_row(self, row, other=None) -> Dict[str, Any]: "label": row["label"], } - def process_ttim_row(self, row, grouped): + def process_transient_row(self, row, grouped): xc, yc, radius = self._centroid_and_radius(row) tsandN, times = self.transient_input(row, grouped, "rate") return { diff --git a/plugin/qgistim/core/elements/constant.py b/plugin/qgistim/core/elements/constant.py index 085cd24..2b13526 100644 --- a/plugin/qgistim/core/elements/constant.py +++ b/plugin/qgistim/core/elements/constant.py @@ -8,18 +8,18 @@ class ConstantSchema(SingleRowSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), "head": Required(), "layer": Required(Membership("aquifer layers")), } - timml_consistency_schemata = (RequiresConfinedAquifer(),) + steady_consistency_schemata = (RequiresConfinedAquifer(),) class Constant(Element): element_type = "Constant" geometry_type = "Point" - timml_attributes = ( + steady_attributes = ( QgsField("head", QVariant.Double), QgsField("layer", QVariant.Int), QgsField("label", QVariant.String), @@ -30,7 +30,7 @@ class Constant(Element): def renderer(cls) -> QgsSingleSymbolRenderer: return cls.marker_renderer(color=RED, name="star", size="5") - def process_timml_row(self, row, other=None): + def process_steady_row(self, row, other=None): x, y = self.point_xy(row) return { "xr": x, diff --git a/plugin/qgistim/core/elements/discharge_observation.py b/plugin/qgistim/core/elements/discharge_observation.py index 4fec743..7f6610d 100644 --- a/plugin/qgistim/core/elements/discharge_observation.py +++ b/plugin/qgistim/core/elements/discharge_observation.py @@ -11,7 +11,7 @@ class DischargeObservationSchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), "legendre_method": Required(), "ndegrees": Required(Positive()), @@ -21,12 +21,12 @@ class DischargeObservationSchema(RowWiseSchema): class DischargeObservation(Element): element_type = "Discharge Observation" geometry_type = "Linestring" - timml_attributes = ( + steady_attributes = ( QgsField("legendre_method", QVariant.Bool), QgsField("ndegrees", QVariant.Int), QgsField("label", QVariant.String), ) - timml_defaults = { + steady_defaults = { "legendre_method": QgsDefaultValue("True"), "ndegrees": QgsDefaultValue("10"), } @@ -36,7 +36,7 @@ class DischargeObservation(Element): def renderer(cls) -> QgsSingleSymbolRenderer: return cls.line_renderer(color=LIGHT_BLUE, width="0.75", outline_style="dash") - def process_timml_row(self, row, other=None): + def process_steady_row(self, row, other=None): return { "xy": self.linestring_xy(row), "method": "legendre" if row["legendre_method"] else "quad", diff --git a/plugin/qgistim/core/elements/domain.py b/plugin/qgistim/core/elements/domain.py index cd01bd1..329f930 100644 --- a/plugin/qgistim/core/elements/domain.py +++ b/plugin/qgistim/core/elements/domain.py @@ -16,7 +16,7 @@ class DomainSchema(SingleRowSchema): - timml_schemata = {"geometry": Required()} + steady_schemata = {"geometry": Required()} timeseries_schemata = { "time": AllRequired(Positive(), StrictlyIncreasing()), } @@ -25,13 +25,13 @@ class DomainSchema(SingleRowSchema): class Domain(TransientElement): element_type = "Domain" geometry_type = "Polygon" - ttim_attributes = (QgsField("time", QVariant.Double),) + transient_attributes = (QgsField("time", QVariant.Double),) schema = DomainSchema() def __init__(self, path: str, name: str): self._initialize_default(path, name) - self.timml_name = f"timml {self.element_type}:Domain" - self.ttim_name = "ttim Computation Times:Domain" + self.steady_name = f"steady-state {self.element_type}:Domain" + self.transient_name = "transient Computation Times:Domain" @classmethod def renderer(cls) -> QgsSingleSymbolRenderer: @@ -46,7 +46,7 @@ def remove_from_geopackage(self): pass def update_extent(self, iface: Any) -> Tuple[float, float]: - provider = self.timml_layer.dataProvider() + provider = self.steady_layer.dataProvider() provider.truncate() # removes all features canvas = iface.mapCanvas() extent = canvas.extent() @@ -66,10 +66,10 @@ def update_extent(self, iface: Any) -> Tuple[float, float]: canvas.refresh() return ymax, ymin - def to_timml(self, other) -> ElementExtraction: - data = self.table_to_records(layer=self.timml_layer) - errors = self.schema.validate_timml( - name=self.timml_layer.name(), data=data, other=other + def extract_steady_data(self, other) -> ElementExtraction: + data = self.table_to_records(layer=self.steady_layer) + errors = self.schema.validate_steady( + name=self.steady_layer.name(), data=data, other=other ) if errors: return ElementExtraction(errors=errors) @@ -85,13 +85,13 @@ def to_timml(self, other) -> ElementExtraction: } ) - def to_ttim(self, other) -> ElementExtraction: - timml_extraction = self.to_timml(other) - data = timml_extraction.data + def extract_transient_data(self, other) -> ElementExtraction: + steady_extraction = self.extract_steady_data(other) + data = steady_extraction.data - timeseries = self.table_to_dict(layer=self.ttim_layer) + timeseries = self.table_to_dict(layer=self.transient_layer) errors = self.schema.validate_timeseries( - name=self.ttim_layer.name(), data=timeseries + name=self.transient_layer.name(), data=timeseries ) if errors: return ElementExtraction(errors=errors) diff --git a/plugin/qgistim/core/elements/element.py b/plugin/qgistim/core/elements/element.py index 6792849..fca3208 100644 --- a/plugin/qgistim/core/elements/element.py +++ b/plugin/qgistim/core/elements/element.py @@ -105,33 +105,33 @@ def __init__(self, parent=None): class Element(ExtractorMixin, abc.ABC): """ - Abstract base class for "ordinary" timml elements. + Abstract base class for "ordinary" tim elements. """ element_type = None geometry_type = None - timml_attributes = () - ttim_attributes = () + steady_attributes = () + transient_attributes = () assoc_attributes = () transient_columns = () - timml_defaults = {} - ttim_defaults = {} + steady_defaults = {} + transient_defaults = {} assoc_defaults = {} def _initialize_default(self, path, name): self.name = name self.path = path - self.timml_name = None - self.ttim_name = None + self.steady_name = None + self.transient_name = None self.assoc_name = None - self.timml_layer = None - self.ttim_layer = None + self.steady_layer = None + self.transient_layer = None self.assoc_layer = None self.item = None def __init__(self, path: str, name: str): self._initialize_default(path, name) - self.timml_name = f"timml {self.element_type}:{name}" + self.steady_name = f"steady-state {self.element_type}:{name}" @classmethod def dialog(cls, path: str, crs: Any, iface: Any, names: List[str]): @@ -159,29 +159,29 @@ def create_layer( layer.setCrs(crs) return layer - def create_timml_layer(self, crs: Any): - self.timml_layer = self.create_layer( + def create_steady_layer(self, crs: Any): + self.steady_layer = self.create_layer( crs=crs, geometry_type=self.geometry_type, - name=self.timml_name, - attributes=self.timml_attributes, + name=self.steady_name, + attributes=self.steady_attributes, ) - def create_ttim_layer(self, crs: Any): + def create_transient_layer(self, crs: Any): pass def create_assoc_layer(self, crs: Any): pass def create_layers(self, crs: Any): - self.create_timml_layer(crs) - self.create_ttim_layer(crs) + self.create_steady_layer(crs) + self.create_transient_layer(crs) self.create_assoc_layer(crs) def set_defaults(self): for layer, defaults in zip( - (self.timml_layer, self.ttim_layer, self.assoc_layer), - (self.timml_defaults, self.ttim_defaults, self.assoc_defaults), + (self.steady_layer, self.transient_layer, self.assoc_layer), + (self.steady_defaults, self.transient_defaults, self.assoc_defaults), ): if layer is None: continue @@ -210,32 +210,32 @@ def polygon_renderer(**kwargs): def renderer(cls): return None - def timml_layer_from_geopackage(self) -> QgsVectorLayer: - self.timml_layer = QgsVectorLayer( - f"{self.path}|layername={self.timml_name}", self.timml_name + def steady_layer_from_geopackage(self) -> QgsVectorLayer: + self.steady_layer = QgsVectorLayer( + f"{self.path}|layername={self.steady_name}", self.steady_name ) - def ttim_layer_from_geopackage(self): + def transient_layer_from_geopackage(self): return def assoc_layer_from_geopackage(self): return def load_layers_from_geopackage(self) -> None: - self.timml_layer_from_geopackage() - self.ttim_layer_from_geopackage() + self.steady_layer_from_geopackage() + self.transient_layer_from_geopackage() self.assoc_layer_from_geopackage() self.set_defaults() return def write(self): - self.timml_layer = geopackage.write_layer( - self.path, self.timml_layer, self.timml_name + self.steady_layer = geopackage.write_layer( + self.path, self.steady_layer, self.steady_name ) self.set_defaults() def remove_from_geopackage(self): - geopackage.remove_layer(self.path, self.timml_name) + geopackage.remove_layer(self.path, self.steady_name) def on_transient_changed(self, _): return @@ -265,35 +265,35 @@ def _check_table_columns(attributes, layer) -> Dict[str, List]: return {"Table:": [msg]} return {} - def check_timml_columns(self): + def check_steady_columns(self): return self._check_table_columns( - attributes=self.timml_attributes, layer=self.timml_layer + attributes=self.steady_attributes, layer=self.steady_layer ) - def to_timml(self, other=None) -> ElementExtraction: - missing = self.check_timml_columns() + def extract_steady_data(self, other=None) -> ElementExtraction: + missing = self.check_steady_columns() if missing: return ElementExtraction(errors=missing) - data = self.table_to_records(layer=self.timml_layer) - errors = self.schema.validate_timml( - name=self.timml_layer.name(), data=data, other=other + data = self.table_to_records(layer=self.steady_layer) + errors = self.schema.validate_steady( + name=self.steady_layer.name(), data=data, other=other ) if errors: return ElementExtraction(errors=errors) else: - elements = [self.process_timml_row(row=row, other=other) for row in data] + elements = [self.process_steady_row(row=row, other=other) for row in data] return ElementExtraction(data=elements) - def to_ttim(self, other=None) -> ElementExtraction: - return self.to_timml(other) + def extract_transient_data(self, other=None) -> ElementExtraction: + return self.extract_steady_data(other) def extract_data(self, transient: bool, other=None) -> ElementExtraction: if transient: - return self.to_ttim(other) + return self.extract_transient_data(other) else: - return self.to_timml(other) + return self.extract_steady_data(other) @staticmethod def aquifer_data(data, transient: bool): @@ -355,53 +355,53 @@ def interleave(a, b): class TransientElement(Element, abc.ABC): """ - Abstract base class for transient (ttim) elements. + Abstract base class for transient (transient) elements. """ def __init__(self, path: str, name: str): self._initialize_default(path, name) - self.timml_name = f"timml {self.element_type}:{name}" - self.ttim_name = f"ttim {self.element_type}:{name}" + self.steady_name = f"steady-state {self.element_type}:{name}" + self.transient_name = f"transient {self.element_type}:{name}" - def create_ttim_layer(self, crs: Any): - self.ttim_layer = self.create_layer( + def create_transient_layer(self, crs: Any): + self.transient_layer = self.create_layer( crs=crs, geometry_type="No Geometry", - name=self.ttim_name, - attributes=self.ttim_attributes, + name=self.transient_name, + attributes=self.transient_attributes, ) - def ttim_layer_from_geopackage(self): - self.ttim_layer = QgsVectorLayer( - f"{self.path}|layername={self.ttim_name}", - self.ttim_name, + def transient_layer_from_geopackage(self): + self.transient_layer = QgsVectorLayer( + f"{self.path}|layername={self.transient_name}", + self.transient_name, ) def write(self): - self.timml_layer = geopackage.write_layer( - self.path, self.timml_layer, self.timml_name + self.steady_layer = geopackage.write_layer( + self.path, self.steady_layer, self.steady_name ) - self.ttim_layer = geopackage.write_layer( - self.path, self.ttim_layer, self.ttim_name + self.transient_layer = geopackage.write_layer( + self.path, self.transient_layer, self.transient_name ) self.set_defaults() def remove_from_geopackage(self): - geopackage.remove_layer(self.path, self.timml_name) - geopackage.remove_layer(self.path, self.ttim_name) + geopackage.remove_layer(self.path, self.steady_name) + geopackage.remove_layer(self.path, self.transient_name) def on_transient_changed(self, transient: bool): if len(self.transient_columns) == 0: return - config = self.timml_layer.attributeTableConfig() + config = self.steady_layer.attributeTableConfig() columns = config.columns() for i, column in enumerate(columns): if column.name in self.transient_columns: config.setColumnHidden(i, not transient) - self.timml_layer.setAttributeTableConfig(config) + self.steady_layer.setAttributeTableConfig(config) return @staticmethod @@ -434,26 +434,26 @@ def transient_input( else: return [(0.0, 0.0)], {0.0} - def check_ttim_columns(self): + def check_transient_columns(self): return self._check_table_columns( - attributes=self.ttim_attributes, layer=self.ttim_layer + attributes=self.transient_attributes, layer=self.transient_layer ) - def to_ttim(self, other): - missing = self.check_ttim_columns() + def extract_transient_data(self, other): + missing = self.check_transient_columns() if missing: return ElementExtraction(errors=missing) other = other.copy() # avoid side-effects - timeseries = self.table_to_dict(self.ttim_layer) + timeseries = self.table_to_dict(self.transient_layer) if timeseries: - other["ttim timeseries IDs"] = set(timeseries["timeseries_id"]) + other["transient timeseries IDs"] = set(timeseries["timeseries_id"]) else: - other["ttim timeseries IDs"] = {None} + other["transient timeseries IDs"] = {None} - data = self.table_to_records(self.timml_layer) - errors = self.schema.validate_ttim( - name=self.timml_layer.name(), data=data, other=other + data = self.table_to_records(self.steady_layer) + errors = self.schema.validate_transient( + name=self.steady_layer.name(), data=data, other=other ) if errors: return ElementExtraction(errors=errors) @@ -475,7 +475,7 @@ def to_ttim(self, other): elements = [] times = set() for row in data: - row_data, row_times = self.process_ttim_row(row, grouped) + row_data, row_times = self.process_transient_row(row, grouped) elements.append(row_data) times.update(row_times) @@ -490,8 +490,8 @@ class AssociatedElement(Element, abc.ABC): def __init__(self, path: str, name: str): self._initialize_default(path, name) - self.timml_name = f"timml {self.element_type}:{name}" - self.assoc_name = f"timml {self.element_type} Properties:{name}" + self.steady_name = f"steady-state {self.element_type}:{name}" + self.assoc_name = f"steady-state {self.element_type} Properties:{name}" def create_assoc_layer(self, crs: Any): self.assoc_layer = self.create_layer( @@ -508,8 +508,8 @@ def assoc_layer_from_geopackage(self): ) def write(self): - self.timml_layer = geopackage.write_layer( - self.path, self.timml_layer, self.timml_name + self.steady_layer = geopackage.write_layer( + self.path, self.steady_layer, self.steady_name ) self.assoc_layer = geopackage.write_layer( self.path, self.assoc_layer, self.assoc_name @@ -517,12 +517,12 @@ def write(self): self.set_defaults() def remove_from_geopackage(self): - geopackage.remove_layer(self.path, self.timml_name) + geopackage.remove_layer(self.path, self.steady_name) geopackage.remove_layer(self.path, self.assoc_name) - def to_timml(self, other) -> ElementExtraction: + def extract_steady_data(self, other) -> ElementExtraction: missing = self._check_table_columns( - attributes=self.timml_attributes, layer=self.timml_layer + attributes=self.steady_attributes, layer=self.steady_layer ) if missing: return ElementExtraction(errors=missing) @@ -536,9 +536,9 @@ def to_timml(self, other) -> ElementExtraction: else: other["properties inhomogeneity_id"] = [None] - data = self.table_to_records(self.timml_layer) - errors = self.schema.validate_timml( - name=self.timml_layer.name(), + data = self.table_to_records(self.steady_layer) + errors = self.schema.validate_steady( + name=self.steady_layer.name(), data=data, other=other, ) @@ -548,7 +548,7 @@ def to_timml(self, other) -> ElementExtraction: grouped = self.groupby(properties, "inhomogeneity_id") errors = {} for inhom_id, group in grouped.items(): - _errors = self.assoc_schema.validate_timml( + _errors = self.assoc_schema.validate_steady( name=f"Properties, inhomogeneity_id {inhom_id}", data=group, other=other, @@ -558,8 +558,8 @@ def to_timml(self, other) -> ElementExtraction: if errors: return ElementExtraction(errors=errors) - elements = [self.process_timml_row(row=row, grouped=grouped) for row in data] + elements = [self.process_steady_row(row=row, grouped=grouped) for row in data] return ElementExtraction(data=elements) - def to_ttim(self, _): + def extract_transient_data(self, _): raise NotImplementedError(f"{type(self).__name__} is not supported in TTim.") diff --git a/plugin/qgistim/core/elements/head_line_sink.py b/plugin/qgistim/core/elements/head_line_sink.py index 7cd3d97..1cf7677 100644 --- a/plugin/qgistim/core/elements/head_line_sink.py +++ b/plugin/qgistim/core/elements/head_line_sink.py @@ -17,8 +17,8 @@ ) -class HeadLineSinkSchema(RowWiseSchema): - timml_schemata = { +class RiverSchema(RowWiseSchema): + steady_schemata = { "geometry": Required(), "head": Required(), "resistance": Required(Positive()), @@ -26,14 +26,14 @@ class HeadLineSinkSchema(RowWiseSchema): "order": Required(Positive()), "layer": Required(Membership("aquifer layers")), } - ttim_consistency_schemata = ( + transient_consistency_schemata = ( AllOrNone("time_start", "time_end", "head_transient"), NotBoth("time_start", "timeseries_id"), ) - ttim_schemata = { + transient_schemata = { "time_start": Optional(Positive()), "time_end": Optional(Positive()), - "timeseries_id": Optional(Membership("ttim timeseries IDs")), + "timeseries_id": Optional(Membership("transient timeseries IDs")), } timeseries_schemata = { "timeseries_id": AllRequired(), @@ -42,10 +42,10 @@ class HeadLineSinkSchema(RowWiseSchema): } -class HeadLineSink(TransientElement): - element_type = "Head Line Sink" +class River(TransientElement): + element_type = "River" geometry_type = "Linestring" - timml_attributes = ( + steady_attributes = ( QgsField("head", QVariant.Double), QgsField("resistance", QVariant.Double), QgsField("width", QVariant.Double), @@ -57,12 +57,12 @@ class HeadLineSink(TransientElement): QgsField("head_transient", QVariant.Double), QgsField("timeseries_id", QVariant.Int), ) - ttim_attributes = ( + transient_attributes = ( QgsField("timeseries_id", QVariant.Int), QgsField("time_start", QVariant.Double), QgsField("head", QVariant.Double), ) - timml_defaults = { + steady_defaults = { "order": QgsDefaultValue("4"), } transient_columns = ( @@ -71,13 +71,13 @@ class HeadLineSink(TransientElement): "head_transient", "timeseries_id", ) - schema = HeadLineSinkSchema() + schema = RiverSchema() @classmethod def renderer(cls) -> QgsSingleSymbolRenderer: return cls.line_renderer(color=BLUE, width="0.75") - def process_timml_row(self, row, other=None): + def process_steady_row(self, row, other=None): return { "xy": self.linestring_xy(row), "hls": row["head"], @@ -88,7 +88,7 @@ def process_timml_row(self, row, other=None): "label": row["label"], } - def process_ttim_row(self, row, grouped): + def process_transient_row(self, row, grouped): tsandh, times = self.transient_input(row, grouped, "head") return { "xy": self.linestring_xy(row), diff --git a/plugin/qgistim/core/elements/headwell.py b/plugin/qgistim/core/elements/headwell.py index 1de149e..6fb02b4 100644 --- a/plugin/qgistim/core/elements/headwell.py +++ b/plugin/qgistim/core/elements/headwell.py @@ -27,19 +27,19 @@ class HeadWellSchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), "head": Required(), "radius": Required(StrictlyPositive()), "resistance": Required(Positive()), "layer": Required(Membership("aquifer layers")), } - ttim_schemata = { + transient_schemata = { "time_start": Optional(Positive()), "time_end": Optional(Positive()), - "timeseries_id": Optional(Membership("ttim timeseries IDs")), + "timeseries_id": Optional(Membership("transient timeseries IDs")), } - ttim_consistency_schemata = ( + transient_consistency_schemata = ( AllOrNone(("time_start", "time_end", "head_transient")), NotBoth("time_start", "timeseries_id"), ) @@ -53,7 +53,7 @@ class HeadWellSchema(RowWiseSchema): class HeadWell(TransientElement): element_type = "Head Well" geometry_type = "Point" - timml_attributes = ( + steady_attributes = ( QgsField("head", QVariant.Double), QgsField("radius", QVariant.Double), QgsField("resistance", QVariant.Double), @@ -64,12 +64,12 @@ class HeadWell(TransientElement): QgsField("head_transient", QVariant.Double), QgsField("timeseries_id", QVariant.Int), ) - ttim_attributes = ( + transient_attributes = ( QgsField("timeseries_id", QVariant.Int), QgsField("time_start", QVariant.Double), QgsField("head", QVariant.Double), ) - timml_defaults = { + steady_defaults = { "radius": QgsDefaultValue("0.1"), "resistance": QgsDefaultValue("0.0"), } @@ -85,7 +85,7 @@ class HeadWell(TransientElement): def renderer(cls) -> QgsSingleSymbolRenderer: return cls.marker_renderer(color=BLUE, size="3") - def process_timml_row(self, row, other=None) -> Dict[str, Any]: + def process_steady_row(self, row, other=None) -> Dict[str, Any]: x, y = self.point_xy(row) return { "xw": x, @@ -97,7 +97,7 @@ def process_timml_row(self, row, other=None) -> Dict[str, Any]: "label": row["label"], } - def process_ttim_row(self, row, grouped): + def process_transient_row(self, row, grouped): x, y = self.point_xy(row) tsandh, times = self.transient_input(row, grouped, "head") return { @@ -125,7 +125,7 @@ def renderer(cls) -> QgsSingleSymbolRenderer: symbol.changeSymbolLayer(0, arrow) return QgsSingleSymbolRenderer(symbol) - def process_timml_row(self, row, other=None) -> Dict[str, Any]: + def process_steady_row(self, row, other=None) -> Dict[str, Any]: xy = self.linestring_xy(row) xw, yw = xy[-1] xc, yc = xy[0] diff --git a/plugin/qgistim/core/elements/impermeable_line_doublet.py b/plugin/qgistim/core/elements/impermeable_line_doublet.py index e74fb36..c925460 100644 --- a/plugin/qgistim/core/elements/impermeable_line_doublet.py +++ b/plugin/qgistim/core/elements/impermeable_line_doublet.py @@ -7,32 +7,32 @@ from qgistim.core.schemata import Membership, Positive, Required -class ImpermeableLineDoubletSchema(RowWiseSchema): - timml_schemata = { +class ImpermeableWallSchema(RowWiseSchema): + steady_schemata = { "geometry": Required(), "order": Required(Positive()), "layer": Required(Membership("aquifer layers")), } -class ImpermeableLineDoublet(Element): - element_type = "Impermeable Line Doublet" +class ImpermeableWall(Element): + element_type = "Impermeable Wall" geometry_type = "Linestring" - timml_attributes = ( + steady_attributes = ( QgsField("order", QVariant.Int), QgsField("layer", QVariant.Int), QgsField("label", QVariant.String), ) - timml_defaults = { + steady_defaults = { "order": QgsDefaultValue("4"), } - schema = ImpermeableLineDoubletSchema() + schema = ImpermeableWallSchema() @classmethod def renderer(cls) -> QgsSingleSymbolRenderer: return cls.line_renderer(color=RED, width="0.75") - def process_timml_row(self, row, other=None): + def process_steady_row(self, row, other=None): return { "xy": self.linestring_xy(row), "layers": row["layer"], @@ -40,10 +40,10 @@ def process_timml_row(self, row, other=None): "label": row["label"], } - def to_ttim(self, other): - # TTim doesn't have an ImpermeableLineDoublet, we need to add "imp" as + def extract_transient_data(self, other): + # TTim doesn't have an ImpermeableWall, we need to add "imp" as # the resistance entry. - _, data = self.to_timml(other) + _, data = self.extract_steady_data(other) out = [] for row in data: out.append( diff --git a/plugin/qgistim/core/elements/leaky_building_pit.py b/plugin/qgistim/core/elements/leaky_building_pit.py index c46c0ac..ffaf781 100644 --- a/plugin/qgistim/core/elements/leaky_building_pit.py +++ b/plugin/qgistim/core/elements/leaky_building_pit.py @@ -24,7 +24,7 @@ class LeakyBuildingPitSchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), "inhomogeneity_id": Required(Membership("properties inhomogeneity_id")), "order": Required(Positive()), @@ -33,7 +33,7 @@ class LeakyBuildingPitSchema(RowWiseSchema): class AssociatedLeakyBuildingPitchema(TableSchema): - timml_schemata = { + steady_schemata = { "inhomogeneity_id": AllRequired(), "layer": AllRequired(Equals("aquifer layers")), "aquifer_top": AllRequired(StrictlyDecreasing()), @@ -45,7 +45,7 @@ class AssociatedLeakyBuildingPitchema(TableSchema): "resistance": RequiredFirstOnly(StrictlyPositive()), "wall_in_layer": AllRequired(AtleastOneTrue()), } - timml_consistency_schemata = ( + steady_consistency_schemata = ( SemiConfined(), AllGreaterEqual("aquifer_top", "aquifer_bottom"), ) @@ -54,7 +54,7 @@ class AssociatedLeakyBuildingPitchema(TableSchema): class LeakyBuildingPit(AssociatedElement): element_type = "Leaky Building Pit" geometry_type = "Polygon" - timml_attributes = ( + steady_attributes = ( QgsField("inhomogeneity_id", QVariant.Int), QgsField("order", QVariant.Int), QgsField("ndegrees", QVariant.Int), @@ -73,7 +73,7 @@ class LeakyBuildingPit(AssociatedElement): QgsField("aquitard_npor", QVariant.Double), QgsField("aquifer_npor", QVariant.Double), ] - timml_defaults = { + steady_defaults = { "order": QgsDefaultValue("4"), "ndegrees": QgsDefaultValue("6"), "inhomogeneity_id": QgsDefaultValue("1"), @@ -94,7 +94,7 @@ def renderer(cls) -> QgsSingleSymbolRenderer: outline_style="dash", ) - def process_timml_row(self, row: Dict[str, Any], grouped: Dict[int, Any]): + def process_steady_row(self, row: Dict[str, Any], grouped: Dict[int, Any]): inhom_id = row["inhomogeneity_id"] raw_data = grouped[inhom_id] aquifer_data = self.aquifer_data(raw_data, transient=False) diff --git a/plugin/qgistim/core/elements/leaky_line_doublet.py b/plugin/qgistim/core/elements/leaky_line_doublet.py index b67becc..f7c8fac 100644 --- a/plugin/qgistim/core/elements/leaky_line_doublet.py +++ b/plugin/qgistim/core/elements/leaky_line_doublet.py @@ -7,8 +7,8 @@ from qgistim.core.schemata import Membership, Positive, Required, StrictlyPositive -class LeakyLineDoubletSchema(RowWiseSchema): - timml_schemata = { +class LeakyWallSchema(RowWiseSchema): + steady_schemata = { "geometry": Required(), "resistance": Required(StrictlyPositive()), "order": Required(Positive()), @@ -16,25 +16,25 @@ class LeakyLineDoubletSchema(RowWiseSchema): } -class LeakyLineDoublet(Element): - element_type = "Leaky Line Doublet" +class LeakyWall(Element): + element_type = "Leaky Wall" geometry_type = "Linestring" - timml_attributes = ( + steady_attributes = ( QgsField("resistance", QVariant.Double), QgsField("order", QVariant.Int), QgsField("layer", QVariant.Int), QgsField("label", QVariant.String), ) - timml_defaults = { + steady_defaults = { "order": QgsDefaultValue("4"), } - schema = LeakyLineDoubletSchema() + schema = LeakyWallSchema() @classmethod def renderer(cls) -> QgsSingleSymbolRenderer: return cls.line_renderer(color=RED, width="0.75", outline_style="dash") - def process_timml_row(self, row, other=None): + def process_steady_row(self, row, other=None): return { "xy": self.linestring_xy(row), "res": row["resistance"], diff --git a/plugin/qgistim/core/elements/line_sink_ditch.py b/plugin/qgistim/core/elements/line_sink_ditch.py index ac4dd9b..898ee61 100644 --- a/plugin/qgistim/core/elements/line_sink_ditch.py +++ b/plugin/qgistim/core/elements/line_sink_ditch.py @@ -17,8 +17,8 @@ ) -class LineSinkDitchSchema(RowWiseSchema): - timml_schemata = { +class DitchSchema(RowWiseSchema): + steady_schemata = { "geometry": Required(), "discharge": Required(), "resistance": Required(Positive()), @@ -26,14 +26,14 @@ class LineSinkDitchSchema(RowWiseSchema): "order": Required(Positive()), "layer": Required(Membership("aquifer layers")), } - ttim_consistency_schemata = ( + transient_consistency_schemata = ( AllOrNone("time_start", "time_end", "discharge_transient"), NotBoth("time_start", "timeseries_id"), ) - ttim_schemata = { + transient_schemata = { "time_start": Optional(Positive()), "time_end": Optional(Positive()), - "timeseries_id": Optional(Membership("ttim timeseries IDs")), + "timeseries_id": Optional(Membership("transient timeseries IDs")), } timeseries_schemata = { "timeseries_id": AllRequired(), @@ -42,10 +42,10 @@ class LineSinkDitchSchema(RowWiseSchema): } -class LineSinkDitch(TransientElement): - element_type = "Line Sink Ditch" +class Ditch(TransientElement): + element_type = "Ditch" geometry_type = "Linestring" - timml_attributes = ( + steady_attributes = ( QgsField("discharge", QVariant.Double), QgsField("resistance", QVariant.Double), QgsField("width", QVariant.Double), @@ -57,12 +57,12 @@ class LineSinkDitch(TransientElement): QgsField("discharge_transient", QVariant.Double), QgsField("timeseries_id", QVariant.Int), ) - ttim_attributes = ( + transient_attributes = ( QgsField("timeseries_id", QVariant.Int), QgsField("time_start", QVariant.Double), QgsField("discharge", QVariant.Double), ) - timml_defaults = { + steady_defaults = { "order": QgsDefaultValue("4"), } transient_columns = ( @@ -71,13 +71,13 @@ class LineSinkDitch(TransientElement): "discharge_transient", "timeseries_id", ) - schema = LineSinkDitchSchema() + schema = DitchSchema() @classmethod def renderer(cls) -> QgsSingleSymbolRenderer: return cls.line_renderer(color=GREEN, width="0.75") - def process_timml_row(self, row, other=None): + def process_steady_row(self, row, other=None): return { "xy": self.linestring_xy(row), "Qls": row["discharge"], @@ -88,7 +88,7 @@ def process_timml_row(self, row, other=None): "label": row["label"], } - def process_ttim_row(self, row, grouped): + def process_transient_row(self, row, grouped): tsandQ, times = self.transient_input(row, grouped, "discharge") return { "xy": self.linestring_xy(row), diff --git a/plugin/qgistim/core/elements/observation.py b/plugin/qgistim/core/elements/observation.py index 142cbab..d7c7352 100644 --- a/plugin/qgistim/core/elements/observation.py +++ b/plugin/qgistim/core/elements/observation.py @@ -14,10 +14,12 @@ class HeadObservationSchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), } - ttim_schemata = {"timeseries_id": Required(Membership("ttim timeseries IDs"))} + transient_schemata = { + "timeseries_id": Required(Membership("transient timeseries IDs")) + } timeseries_schemata = { "timeseries_id": AllRequired(), "time": AllRequired(Positive(), StrictlyIncreasing()), @@ -27,18 +29,18 @@ class HeadObservationSchema(RowWiseSchema): class HeadObservation(TransientElement): element_type = "Head Observation" geometry_type = "Point" - timml_attributes = ( + steady_attributes = ( QgsField("label", QVariant.String), QgsField("timeseries_id", QVariant.Int), ) - ttim_attributes = ( + transient_attributes = ( QgsField("timeseries_id", QVariant.Int), QgsField("time", QVariant.Double), ) - timml_defaults = { + steady_defaults = { "timeseries_id": QgsDefaultValue("1"), } - ttim_defaults = { + transient_defaults = { "timeseries_id": QgsDefaultValue("1"), } transient_columns = ("timeseries_id",) @@ -48,7 +50,7 @@ class HeadObservation(TransientElement): def renderer(cls) -> QgsSingleSymbolRenderer: return cls.marker_renderer(color=LIGHT_BLUE, name="triangle", size="3") - def process_timml_row(self, row, other=None): + def process_steady_row(self, row, other=None): x, y = self.point_xy(row) return { "x": x, @@ -56,7 +58,7 @@ def process_timml_row(self, row, other=None): "label": row["label"], } - def process_ttim_row(self, row, grouped): + def process_transient_row(self, row, grouped): x, y = self.point_xy(row) times = grouped[row["timeseries_id"]]["time"] return { diff --git a/plugin/qgistim/core/elements/polygon_area_sink.py b/plugin/qgistim/core/elements/polygon_area_sink.py index bfbcf36..0b0e4fa 100644 --- a/plugin/qgistim/core/elements/polygon_area_sink.py +++ b/plugin/qgistim/core/elements/polygon_area_sink.py @@ -10,7 +10,7 @@ class PolygonAreaSinkSchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), "rate": Required(), "order": Required(Positive()), @@ -21,12 +21,12 @@ class PolygonAreaSinkSchema(RowWiseSchema): class PolygonAreaSink(Element): element_type = "Polygon Area Sink" geometry_type = "Polygon" - timml_attributes = ( + steady_attributes = ( QgsField("rate", QVariant.Double), QgsField("order", QVariant.Int), QgsField("ndegrees", QVariant.Int), ) - timml_defaults = { + steady_defaults = { "order": QgsDefaultValue("4"), "ndegrees": QgsDefaultValue("6"), } @@ -38,7 +38,7 @@ def renderer(cls) -> QgsSingleSymbolRenderer: color=TRANSPARENT_GREEN, color_border=GREEN, width_border="0.75" ) - def process_timml_row(self, row, other): + def process_steady_row(self, row, other): raw_data = deepcopy(other["global_aquifer"]) raw_data["aquitard_c"][0] = None raw_data["semiconf_top"][0] = None diff --git a/plugin/qgistim/core/elements/polygon_inhomogeneity.py b/plugin/qgistim/core/elements/polygon_inhomogeneity.py index a2d078d..2465a5f 100644 --- a/plugin/qgistim/core/elements/polygon_inhomogeneity.py +++ b/plugin/qgistim/core/elements/polygon_inhomogeneity.py @@ -22,7 +22,7 @@ class PolygonInhomogeneitySchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), "inhomogeneity_id": Required(Membership("properties inhomogeneity_id")), "order": Required(Positive()), @@ -31,7 +31,7 @@ class PolygonInhomogeneitySchema(RowWiseSchema): class AssociatedPolygonInhomogeneitySchema(TableSchema): - timml_schemata = { + steady_schemata = { "inhomogeneity_id": AllRequired(), "layer": AllRequired(Equals("aquifer layers")), "aquifer_top": AllRequired(StrictlyDecreasing()), @@ -42,7 +42,7 @@ class AssociatedPolygonInhomogeneitySchema(TableSchema): "semiconf_head": OptionalFirstOnly(), "rate": OptionalFirstOnly(), } - timml_consistency_schemata = ( + steady_consistency_schemata = ( SemiConfined(), AllGreaterEqual("aquifer_top", "aquifer_bottom"), ) @@ -51,7 +51,7 @@ class AssociatedPolygonInhomogeneitySchema(TableSchema): class PolygonInhomogeneity(AssociatedElement): element_type = "Polygon Inhomogeneity" geometry_type = "Polygon" - timml_attributes = ( + steady_attributes = ( QgsField("inhomogeneity_id", QVariant.Int), QgsField("order", QVariant.Int), QgsField("ndegrees", QVariant.Int), @@ -69,7 +69,7 @@ class PolygonInhomogeneity(AssociatedElement): QgsField("aquitard_npor", QVariant.Double), QgsField("aquifer_npor", QVariant.Double), ] - timml_defaults = { + steady_defaults = { "order": QgsDefaultValue("4"), "ndegrees": QgsDefaultValue("6"), "inhomogeneity_id": QgsDefaultValue("1"), @@ -86,7 +86,7 @@ def renderer(cls) -> QgsSingleSymbolRenderer: color=TRANSPARENT_GREY, color_border=GREY, width_border="0.75" ) - def process_timml_row(self, row: Dict[str, Any], grouped: Dict[int, Any]): + def process_steady_row(self, row: Dict[str, Any], grouped: Dict[int, Any]): inhom_id = row["inhomogeneity_id"] raw_data = grouped[inhom_id] aquifer_data = self.aquifer_data(raw_data, transient=False) diff --git a/plugin/qgistim/core/elements/polygon_semi_confined_top.py b/plugin/qgistim/core/elements/polygon_semi_confined_top.py index b5d5f86..213729c 100644 --- a/plugin/qgistim/core/elements/polygon_semi_confined_top.py +++ b/plugin/qgistim/core/elements/polygon_semi_confined_top.py @@ -10,7 +10,7 @@ class PolygonSemiConfinedTopSchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), "aquitard_c": Required(StrictlyPositive()), "semiconf_top": Required(), @@ -23,14 +23,14 @@ class PolygonSemiConfinedTopSchema(RowWiseSchema): class PolygonSemiConfinedTop(Element): element_type = "Polygon Semi-Confined Top" geometry_type = "Polygon" - timml_attributes = ( + steady_attributes = ( QgsField("aquitard_c", QVariant.Double), QgsField("semiconf_top", QVariant.Double), QgsField("semiconf_head", QVariant.Double), QgsField("order", QVariant.Int), QgsField("ndegrees", QVariant.Int), ) - timml_defaults = { + steady_defaults = { "order": QgsDefaultValue("4"), "ndegrees": QgsDefaultValue("6"), } @@ -42,7 +42,7 @@ def renderer(cls) -> QgsSingleSymbolRenderer: color=TRANSPARENT_BLUE, color_border=BLUE, width_border="0.75" ) - def process_timml_row(self, row, other): + def process_steady_row(self, row, other): raw_data = deepcopy(other["global_aquifer"]) raw_data["aquitard_c"][0] = row["aquitard_c"] raw_data["semiconf_top"][0] = row["semiconf_top"] diff --git a/plugin/qgistim/core/elements/schemata.py b/plugin/qgistim/core/elements/schemata.py index ee8ed47..229f7e8 100644 --- a/plugin/qgistim/core/elements/schemata.py +++ b/plugin/qgistim/core/elements/schemata.py @@ -19,10 +19,10 @@ class ValidationData(NamedTuple): class SchemaBase(abc.ABC): # TODO: check for presence of columns - timml_schemata: Dict[str, Union[SchemaContainer, IterableSchemaContainer]] = {} - timml_consistency_schemata: Tuple[ConsistencySchema] = () - ttim_schemata: Dict[str, Union[SchemaContainer, IterableSchemaContainer]] = {} - ttim_consistency_schemata: Tuple[ConsistencySchema] = () + steady_schemata: Dict[str, Union[SchemaContainer, IterableSchemaContainer]] = {} + steady_consistency_schemata: Tuple[ConsistencySchema] = () + transient_schemata: Dict[str, Union[SchemaContainer, IterableSchemaContainer]] = {} + transient_consistency_schemata: Tuple[ConsistencySchema] = () timeseries_schemata: Dict[str, Union[SchemaContainer, IterableSchemaContainer]] = {} @staticmethod @@ -51,20 +51,24 @@ def validate_timeseries( return cls._validate_table(vd) @classmethod - def validate_timml( + def validate_steady( cls, name: str, data: Dict[str, Any], other=None ) -> Dict[str, List]: vd = ValidationData( - cls.timml_schemata, cls.timml_consistency_schemata, name, data, other + cls.steady_schemata, cls.steady_consistency_schemata, name, data, other ) return cls._validate(vd) @classmethod - def validate_ttim( + def validate_transient( cls, name: str, data: Dict[str, Any], other=None ) -> Dict[str, List]: vd = ValidationData( - cls.ttim_schemata, cls.ttim_consistency_schemata, name, data, other + cls.transient_schemata, + cls.transient_consistency_schemata, + name, + data, + other, ) return cls._validate(vd) diff --git a/plugin/qgistim/core/elements/uniform_flow.py b/plugin/qgistim/core/elements/uniform_flow.py index 8e01b52..13957be 100644 --- a/plugin/qgistim/core/elements/uniform_flow.py +++ b/plugin/qgistim/core/elements/uniform_flow.py @@ -7,24 +7,24 @@ class UniformFlowSchema(SingleRowSchema): - timml_schemata = { + steady_schemata = { "slope": Required(), "angle": Required(), } - timml_consistency_schemata = (RequiresConfinedAquifer(),) + steady_consistency_schemata = (RequiresConfinedAquifer(),) class UniformFlow(Element): element_type = "Uniform Flow" geometry_type = "No geometry" - timml_attributes = ( + steady_attributes = ( QgsField("slope", QVariant.Double), QgsField("angle", QVariant.Double), QgsField("label", QVariant.String), ) schema = UniformFlowSchema() - def process_timml_row(self, row, other=None): + def process_steady_row(self, row, other=None): return { "slope": row["slope"], "angle": row["angle"], diff --git a/plugin/qgistim/core/elements/well.py b/plugin/qgistim/core/elements/well.py index affaf25..132649d 100644 --- a/plugin/qgistim/core/elements/well.py +++ b/plugin/qgistim/core/elements/well.py @@ -20,22 +20,22 @@ class WellSchema(RowWiseSchema): - timml_schemata = { + steady_schemata = { "geometry": Required(), "discharge": Required(), "radius": Required(StrictlyPositive()), "resistance": Required(Positive()), "layer": Required(Membership("aquifer layers")), } - timml_consistency_schemata = (ConditionallyRequired("slug", "caisson_radius"),) - ttim_schemata = { + steady_consistency_schemata = (ConditionallyRequired("slug", "caisson_radius"),) + transient_schemata = { "caisson_radius": Optional(StrictlyPositive()), "slug": Required(), "time_start": Optional(Positive()), "time_end": Optional(Positive()), - "timeseries_id": Optional(Membership("ttim timeseries IDs")), + "timeseries_id": Optional(Membership("transient timeseries IDs")), } - ttim_consistency_schemata = ( + transient_consistency_schemata = ( AllOrNone(("time_start", "time_end", "discharge_transient")), NotBoth("time_start", "timeseries_id"), ) @@ -49,7 +49,7 @@ class WellSchema(RowWiseSchema): class Well(TransientElement): element_type = "Well" geometry_type = "Point" - timml_attributes = ( + steady_attributes = ( QgsField("discharge", QVariant.Double), QgsField("radius", QVariant.Double), QgsField("resistance", QVariant.Double), @@ -62,12 +62,12 @@ class Well(TransientElement): QgsField("slug", QVariant.Bool), QgsField("timeseries_id", QVariant.Int), ) - ttim_attributes = ( + transient_attributes = ( QgsField("timeseries_id", QVariant.Int), QgsField("time_start", QVariant.Double), QgsField("discharge", QVariant.Double), ) - timml_defaults = { + steady_defaults = { "radius": QgsDefaultValue("0.1"), "resistance": QgsDefaultValue("0.0"), "slug": QgsDefaultValue("False"), @@ -86,7 +86,7 @@ class Well(TransientElement): def renderer(cls) -> QgsSingleSymbolRenderer: return cls.marker_renderer(color=GREEN, size="3") - def process_timml_row(self, row, other=None) -> Dict[str, Any]: + def process_steady_row(self, row, other=None) -> Dict[str, Any]: x, y = self.point_xy(row) return { "xw": x, @@ -98,7 +98,7 @@ def process_timml_row(self, row, other=None) -> Dict[str, Any]: "label": row["label"], } - def process_ttim_row(self, row, grouped): + def process_transient_row(self, row, grouped): x, y = self.point_xy(row) tsandQ, times = self.transient_input(row, grouped, "discharge") return { diff --git a/plugin/qgistim/core/formatting.py b/plugin/qgistim/core/formatting.py index 8ed59cd..54d8137 100644 --- a/plugin/qgistim/core/formatting.py +++ b/plugin/qgistim/core/formatting.py @@ -12,7 +12,7 @@ from qgistim.widgets.compute_widget import OutputOptions -TIMML_MAPPING = { +STEADY_MAPPING = { "Constant": "Constant", "Uniform Flow": "Uflow", "Circular Area Sink": "CircAreaSink", @@ -22,10 +22,10 @@ "Polygon Inhomogeneity": "PolygonInhomMaq", "Polygon Area Sink": "PolygonInhomMaq", "Polygon Semi-Confined Top": "PolygonInhomMaq", - "Head Line Sink": "HeadLineSinkString", - "Line Sink Ditch": "LineSinkDitchString", - "Leaky Line Doublet": "LeakyLineDoubletString", - "Impermeable Line Doublet": "ImpLineDoubletString", + "River": "RiverString", + "Ditch": "DitchString", + "Leaky Wall": "LeakyWallString", + "Impermeable Wall": "ImpermeableWallString", "Building Pit": "BuildingPit", "Leaky Building Pit": "LeakyBuildingPit", "Head Observation": "Head Observation", @@ -33,16 +33,16 @@ } # In TTim, a constant or uniform flow may be added, but they have no effect on # the transient superposed result. -TTIM_MAPPING = { +TRANSIENT_MAPPING = { "Constant": None, "Uniform Flow": None, "Circular Area Sink": "CircAreaSink", "Well": "Well", "Head Well": "HeadWell", - "Head Line Sink": "HeadLineSinkString", - "Line Sink Ditch": "LineSinkDitchString", - "Leaky Line Doublet": "LeakyLineDoubletString", - "Impermeable Line Doublet": "LeakyLineDoubletString", + "River": "RiverString", + "Ditch": "DitchString", + "Leaky Wall": "LeakyWallString", + "Impermeable Wall": "LeakyWallString", "Head Observation": "Head Observation", } PREFIX = " " @@ -133,13 +133,14 @@ def headgrid_code(domain) -> Tuple[str, str]: return xg, yg, t -def elements_and_observations(data, mapping: Dict[str, str], tim: str): +def elements_and_observations(data, mapping: Dict[str, str], temporal_mode: str): strings = [] observations = [] - model_string = textwrap.indent(f"model={tim}_model,", prefix=PREFIX) + model_string = textwrap.indent(f"model={temporal_mode}_model,", prefix=PREFIX) + for layername, element_data in data.items(): prefix, name = layername.split(":") - plugin_name = re.split("timml |ttim ", prefix)[1] + plugin_name = re.split("steady-state |transient ", prefix)[1] tim_name = mapping[plugin_name] if tim_name is None: continue @@ -148,85 +149,86 @@ def elements_and_observations(data, mapping: Dict[str, str], tim: str): if plugin_name == "Head Observation": # Should not be added to the model. # Would result in e.g.: - # observation_piezometer_0 = timml.head( + # observation_piezometer_0 = timflow.steady.head( # x=10.0, # y=20.0, # ) kwargs.pop("label") observations.append( - f"observation_{sanitized(name)}_{i}={tim}_model.head(\n{format_kwargs(kwargs)}\n)" + f"observation_{sanitized(name)}_{i}={temporal_mode}_model.head(\n{format_kwargs(kwargs)}\n)" ) elif plugin_name == "Discharge Observation": kwargs.pop("label") observations.append( - f"discharge_observation_{sanitized(name)}_{i}={tim}_model.intnormflux(\n{format_kwargs(kwargs)}\n)" + f"discharge_observation_{sanitized(name)}_{i}={temporal_mode}_model.intnormflux(\n{format_kwargs(kwargs)}\n)" ) else: # Has to be added to the model. # Would result in e.g.: - # timml_extraction_0 = timml.Well( - # model=timml_model, + # steady-state_extraction_0 = timflow.steady.Well( + # model=steady-state_model, # ... # ) kwargs = format_kwargs(kwargs) strings.append( - f"{tim}_{sanitized(name)}_{i} = {tim}.{tim_name}(\n{model_string}\n{kwargs}\n)" + f"{temporal_mode}_{sanitized(name)}_{i} = timflow.{temporal_mode}.{tim_name}(\n{model_string}\n{kwargs}\n)" ) return strings, observations -def timml_script_content(data: Dict[str, Any]): +def steady_script_content(data: Dict[str, Any]): data = data.copy() # avoid side-effects - aquifer_data = data.pop("timml Aquifer:Aquifer") - data.pop("timml Domain:Domain") + aquifer_data = data.pop("steady-state Aquifer:Aquifer") + data.pop("steady-state Domain:Domain") strings = [ "import numpy as np", - "import timml", + "import timflow", "", - f"timml_model = timml.ModelMaq(\n{format_kwargs(aquifer_data)}\n)", + f"steady-state_model = timflow.steady.ModelMaq(\n{format_kwargs(aquifer_data)}\n)", ] element_strings, observations = elements_and_observations( - data, TIMML_MAPPING, tim="timml" + data, STEADY_MAPPING, temporal_mode="steady-state" ) strings = strings + element_strings return strings, observations -def timml_script(data: Dict[str, Any]) -> str: - strings, observations = timml_script_content(data) - strings.append("\ntimml_model.solve()\n") - xg, yg, _ = headgrid_code(data["timml Domain:Domain"]) - strings.append(f"head = timml_model.headgrid(\n{xg},\n{yg}\n)") +def steady_script(data: Dict[str, Any]) -> str: + strings, observations = steady_script_content(data) + strings.append("\nsteady-state_model.solve()\n") + xg, yg, _ = headgrid_code(data["steady-state Domain:Domain"]) + strings.append(f"head = steady-state_model.headgrid(\n{xg},\n{yg}\n)") strings.append("\n") strings.extend(observations) return "\n".join(strings) -def ttim_script(timml_data: Dict[str, Any], ttim_data: Dict[str, Any]) -> str: - strings, _ = timml_script_content(timml_data) - strings.insert(2, "import ttim") +def transient_script( + steady_data: Dict[str, Any], transient_data: Dict[str, Any] +) -> str: + strings, _ = steady_script_content(steady_data) - data = ttim_data.copy() # avoid side-effects - aquifer_data = data.pop("timml Aquifer:Aquifer") - domain_data = data.pop("timml Domain:Domain") + data = transient_data.copy() # avoid side-effects + aquifer_data = data.pop("steady-state Aquifer:Aquifer") + domain_data = data.pop("steady-state Domain:Domain") data.pop("start_date") strings.append( - f"\nttim_model = ttim.ModelMaq(\n{format_kwargs(aquifer_data)}\n{PREFIX}timmlmodel=timml_model,\n)" + f"\ntransient_model = timflow.transient.ModelMaq(\n{format_kwargs(aquifer_data)}\n{PREFIX}steady=steady-state_model,\n)" ) element_strings, observations = elements_and_observations( - data, TTIM_MAPPING, tim="ttim" + data, TRANSIENT_MAPPING, temporal_mode="transient" ) strings = strings + element_strings - strings.append("\ntimml_model.solve()\nttim_model.solve()\n") + strings.append("\nsteady-state_model.solve()\ntransient_model.solve()\n") if domain_data.get("time"): xg, yg, t = headgrid_code(domain_data) - strings.append(f"head = ttim_model.headgrid(\n{xg},\n{yg},\n{t}\n)") + strings.append(f"head = transient_model.headgrid(\n{xg},\n{yg},\n{t}\n)") strings.append("\n") strings.extend(observations) @@ -234,24 +236,24 @@ def ttim_script(timml_data: Dict[str, Any], ttim_data: Dict[str, Any]) -> str: def data_to_script( - timml_data: Dict[str, Any], - ttim_data: Union[Dict[str, Any], None], + steady_data: Dict[str, Any], + transient_data: Union[Dict[str, Any], None], ) -> str: - if ttim_data is None: - return timml_script(timml_data) + if transient_data is None: + return steady_script(steady_data) else: - return ttim_script(timml_data, ttim_data) + return transient_script(steady_data, transient_data) def json_elements_and_observations(data, mapping: Dict[str, str]): - aquifer_data = data.pop("timml Aquifer:Aquifer") + aquifer_data = data.pop("steady-state Aquifer:Aquifer") observations = {} discharge_observations = {} tim_data = {"ModelMaq": aquifer_data} for layername, element_data in data.items(): prefix, name = layername.split(":") - plugin_name = re.split("timml |ttim ", prefix)[1] + plugin_name = re.split("steady-state |transient ", prefix)[1] tim_name = mapping[plugin_name] if tim_name is None: continue @@ -267,14 +269,14 @@ def json_elements_and_observations(data, mapping: Dict[str, str]): return tim_data, observations, discharge_observations -def timml_json( - timml_data: Dict[str, Any], +def steady_json( + steady_data: Dict[str, Any], output_options: OutputOptions, ) -> Dict[str, Any]: """ Take the data and add: - * the TimML type + * the timflow type * the layer name Parameters @@ -288,13 +290,13 @@ def timml_json( Data ready to dump to JSON. """ # Process TimML elements - data = timml_data.copy() # avoid side-effects - domain_data = data.pop("timml Domain:Domain") + data = steady_data.copy() # avoid side-effects + domain_data = data.pop("steady-state Domain:Domain") elements, observations, discharge_observations = json_elements_and_observations( - data, mapping=TIMML_MAPPING + data, mapping=STEADY_MAPPING ) json_data = { - "timml": elements, + "steady-state": elements, "observations": observations, "discharge_observations": discharge_observations, "window": domain_data, @@ -305,21 +307,21 @@ def timml_json( return json_data -def ttim_json( - timml_data: Dict[str, Any], - ttim_data: Dict[str, Any], +def transient_json( + steady_data: Dict[str, Any], + transient_data: Dict[str, Any], output_options: OutputOptions, ) -> Dict[str, Any]: - json_data = timml_json(timml_data, output_options) + json_data = steady_json(steady_data, output_options) - data = ttim_data.copy() - domain_data = data.pop("timml Domain:Domain") + data = transient_data.copy() + domain_data = data.pop("steady-state Domain:Domain") start_date = data.pop("start_date") elements, observations, _ = json_elements_and_observations( - data, mapping=TTIM_MAPPING + data, mapping=TRANSIENT_MAPPING ) - json_data["ttim"] = elements + json_data["transient"] = elements json_data["start_date"] = start_date json_data["observations"] = observations if output_options.mesh or output_options.raster: @@ -328,11 +330,11 @@ def ttim_json( def data_to_json( - timml_data: Dict[str, Any], - ttim_data: Union[Dict[str, Any], None], + steady_data: Dict[str, Any], + transient_data: Union[Dict[str, Any], None], output_options: OutputOptions, ) -> Dict[str, Any]: - if ttim_data is None: - return timml_json(timml_data, output_options) + if transient_data is None: + return steady_json(steady_data, output_options) else: - return ttim_json(timml_data, ttim_data, output_options) + return transient_json(steady_data, transient_data, output_options) diff --git a/plugin/qgistim/core/server_handler.py b/plugin/qgistim/core/server_handler.py index 2cc10f2..bdf2601 100644 --- a/plugin/qgistim/core/server_handler.py +++ b/plugin/qgistim/core/server_handler.py @@ -1,6 +1,6 @@ """ This module contains the logic for starting, communicating with, and killing a -separate (conda) interpreter, which is running TimML and TTim. +separate (conda) interpreter, which is running timflow. For thread safety: DO NOT INCLUDE QGIS CALLS HERE. """ diff --git a/plugin/qgistim/metadata.txt b/plugin/qgistim/metadata.txt index c8792a3..f3ed907 100644 --- a/plugin/qgistim/metadata.txt +++ b/plugin/qgistim/metadata.txt @@ -4,13 +4,13 @@ [general] name=Qgis-Tim -qgisMinimumVersion=3.28 -description=QGIS plugin to setup TimML multi-layer analytic elements -version=0.6.0 +qgisMinimumVersion=3.40 +description=QGIS plugin to setup Timflow multi-layer analytic elements +version=0.7.0 author=Deltares email=huitebootsma@gmail.com -about=QGIS plugin to setup TimML multi-layer analytic elements +about=QGIS plugin to setup Timflow multi-layer analytic elements tracker=https://github.com/Deltares/QGIS-Tim/issues repository=https://github.com/Deltares/QGIS-Tim @@ -23,7 +23,7 @@ hasProcessingProvider=no # changelog= # Tags are comma separated with spaces allowed -tags=python, groundwater, groundwater modeling, analytic element, TTim, TimML +tags=python, groundwater, groundwater modeling, analytic element, TTim, TimML, Timflow homepage=https://deltares.github.io/QGIS-Tim/ category=Plugins diff --git a/plugin/qgistim/qgistim.py b/plugin/qgistim/qgistim.py index 8eebe69..cd077a9 100644 --- a/plugin/qgistim/qgistim.py +++ b/plugin/qgistim/qgistim.py @@ -41,11 +41,9 @@ def add_action(self, icon_name, text="", callback=None, add_to_menu=False): def initGui(self): icon_name = "icon.png" - self.action_timml = self.add_action( - icon_name, "QGIS-Tim", self.toggle_timml, True - ) + self.action_tim = self.add_action(icon_name, "QGIS-Tim", self.toggle_tim, True) - def toggle_timml(self): + def toggle_tim(self): if self.tim_widget is None: from .widgets.tim_widget import QgisTimWidget diff --git a/plugin/qgistim/qt/qgistim_dockwidget_base.ui b/plugin/qgistim/qt/qgistim_dockwidget_base.ui index 072ebe6..69a07b1 100644 --- a/plugin/qgistim/qt/qgistim_dockwidget_base.ui +++ b/plugin/qgistim/qt/qgistim_dockwidget_base.ui @@ -64,9 +64,9 @@ - + - LineSinkDitch + Ditch @@ -85,9 +85,9 @@ - + - LeakyLineDoublet + LeakyWall @@ -99,16 +99,16 @@ - + - ImpLineDoublet + ImpermeableWall - + - HeadLineSink + River diff --git a/plugin/qgistim/widgets/compute_widget.py b/plugin/qgistim/widgets/compute_widget.py index 65bbffd..c5ac520 100644 --- a/plugin/qgistim/widgets/compute_widget.py +++ b/plugin/qgistim/widgets/compute_widget.py @@ -512,11 +512,11 @@ def load_vector_result(self, path: Union[Path, str]) -> None: # Special-case the labelling for observations and discharge. if ( - "timml Head Observation:" in layername - or "ttim Head Observation" in layername + "steady-state Head Observation:" in layername + or "transient Head Observation" in layername ): labels = layer_styling.number_labels("head_layer0") - elif "timml Discharge Observation:" in layername: + elif "steady-state Discharge Observation:" in layername: labels = layer_styling.number_labels("discharge_layer0") elif "discharge-" in layername: labels = layer_styling.number_labels("discharge_layer0") diff --git a/plugin/qgistim/widgets/dataset_widget.py b/plugin/qgistim/widgets/dataset_widget.py index 472171e..8962302 100644 --- a/plugin/qgistim/widgets/dataset_widget.py +++ b/plugin/qgistim/widgets/dataset_widget.py @@ -3,7 +3,7 @@ This widget also allows enabling or disabling individual elements for a computation. It also forms the link between the geometry layers and the -associated layers for homogeneities, or for timeseries layers for ttim +associated layers for homogeneities, or for timeseries layers for transient elements. Not every TimML element has a TTim equivalent (yet). This means that when a @@ -48,19 +48,19 @@ "Uniform Flow", "Well", "Head Well", - "Head Line Sink", - "Line Sink Ditch", + "River", + "Ditch", "Circular Area Sink", - "Impermeable Line Doublet", - "Leaky Line Doublet", + "Impermeable Wall", + "Leaky Wall", "Head Observation", ] ) class Extraction(NamedTuple): - timml: Dict[str, Any] = None - ttim: Dict[str, Any] = None + steady: Dict[str, Any] = None + transient: Dict[str, Any] = None success: bool = True @@ -91,15 +91,17 @@ def reset(self): self.takeTopLevelItem(index) return - def add_item(self, timml_name: str, ttim_name: str = None, enabled: bool = True): + def add_item( + self, steady_name: str, transient_name: str = None, enabled: bool = True + ): item = QTreeWidgetItem() self.addTopLevelItem(item) - item.timml_checkbox = QCheckBox() - item.timml_checkbox.setChecked(True) - item.timml_checkbox.setEnabled(enabled) - self.setItemWidget(item, 0, item.timml_checkbox) - item.setText(1, timml_name) - item.setText(2, ttim_name) + item.steady_checkbox = QCheckBox() + item.steady_checkbox.setChecked(True) + item.steady_checkbox.setEnabled(enabled) + self.setItemWidget(item, 0, item.steady_checkbox) + item.setText(1, steady_name) + item.setText(2, transient_name) item.assoc_item = None return item @@ -111,7 +113,9 @@ def add_element(self, element) -> None: enabled = True item = self.add_item( - timml_name=element.timml_name, ttim_name=element.ttim_name, enabled=enabled + steady_name=element.steady_name, + transient_name=element.transient_name, + enabled=enabled, ) item.element = element return @@ -122,13 +126,13 @@ def on_transient_changed(self, transient: bool) -> None: Inhomogeneities, or switch them on again. """ self.setColumnHidden(2, not transient) - # Disable unsupported ttim items, such as inhomogeneities + # Disable unsupported transient items, such as inhomogeneities for item in self.items(): prefix, _ = item.text(1).split(":") - _, elementtype = prefix.split("timml ") + _, elementtype = prefix.split("steady-state ") if elementtype not in SUPPORTED_TTIM_ELEMENTS: - item.timml_checkbox.setChecked(not transient) - item.timml_checkbox.setEnabled(not transient) + item.steady_checkbox.setChecked(not transient) + item.steady_checkbox.setEnabled(not transient) # Hide transient columns in the TimML layers: item.element.on_transient_changed(transient) @@ -173,8 +177,8 @@ def remove_geopackage_layers(self) -> None: for element in elements: for layer in [ - element.timml_layer, - element.ttim_layer, + element.steady_layer, + element.transient_layer, element.assoc_layer, ]: # QGIS layers @@ -213,12 +217,12 @@ def extract_data(self, transient: bool) -> Tuple[Dict[str, Any], Dict[str, Any]] elements = { item.text(1): item.element for item in self.items() - if item.timml_checkbox.isChecked() + if item.steady_checkbox.isChecked() } # First convert the aquifer, since we need its data to validate # other elements. - name = "timml Aquifer:Aquifer" + name = "steady-state Aquifer:Aquifer" aquifer = elements.pop(name) aquifer_extraction = aquifer.extract_data(transient) if aquifer_extraction.errors: @@ -258,7 +262,7 @@ def extract_data(self, transient: bool) -> Tuple[Dict[str, Any], Dict[str, Any]] if transient: if times and (times != {0}): - data["timml Aquifer:Aquifer"]["tmax"] = max(times) + data["steady-state Aquifer:Aquifer"]["tmax"] = max(times) else: errors["Model"] = {"TTim input:": ["No transient forcing defined."]} @@ -361,12 +365,12 @@ def add_item_to_qgis(self, item) -> None: suppress = self.suppress_popup_checkbox.isChecked() # Start adding the layers maplayer = self.parent.input_group.add_layer( - element.timml_layer, "timml", element.renderer(), suppress + element.steady_layer, "steady-state", element.renderer(), suppress ) - self.parent.input_group.add_layer(element.ttim_layer, "ttim") - self.parent.input_group.add_layer(element.assoc_layer, "timml") + self.parent.input_group.add_layer(element.transient_layer, "transient") + self.parent.input_group.add_layer(element.assoc_layer, "steady-state") # Set cell size if the item is a domain layer - if item.element.timml_name.split(":")[0] == "timml Domain": + if item.element.steady_name.split(":")[0] == "steady-state Domain": if maplayer.featureCount() <= 0: return feature = next(iter(maplayer.getFeatures())) @@ -405,7 +409,7 @@ def load_geopackage(self, input_group: str = None) -> None: self.dataset_tree.sortByColumn(0, Qt.SortOrder.AscendingOrder) self.parent.enable_geopackage_buttons() self.on_transient_changed() - self.model_crs = self.domain_item().element.timml_layer.crs() + self.model_crs = self.domain_item().element.steady_layer.crs() self.parent.qgs_project.writeEntry("qgistim", "geopackage_path", self.path) self.parent.qgs_project.writeEntry("qgistim", "input_group", input_group) return @@ -531,7 +535,7 @@ def on_transient_changed(self) -> None: def suppress_popup_changed(self): suppress = self.suppress_popup_checkbox.isChecked() for item in self.dataset_tree.items(): - layer = item.element.timml_layer + layer = item.element.steady_layer if layer is not None: config = layer.editFormConfig() config.setSuppress(suppress) @@ -541,8 +545,8 @@ def suppress_popup_changed(self): def active_elements(self): active_elements = {} for item in self.dataset_tree.items(): - active_elements[item.text(1)] = not (item.timml_checkbox.isChecked() == 0) - active_elements[item.text(2)] = not (item.timml_checkbox.isChecked() == 0) + active_elements[item.text(1)] = not (item.steady_checkbox.isChecked() == 0) + active_elements[item.text(2)] = not (item.steady_checkbox.isChecked() == 0) return active_elements def domain_item(self): @@ -574,19 +578,19 @@ def _extract_data(self, transient: bool) -> Extraction: self.validation_dialog.close() self.validation_dialog = None - errors, timml_data = self.dataset_tree.extract_data(transient=False) + errors, steady_data = self.dataset_tree.extract_data(transient=False) if errors: self.validation_dialog = ValidationDialog(errors) return Extraction(success=False) - ttim_data = None + transient_data = None if transient: - errors, ttim_data = self.dataset_tree.extract_data(transient=True) + errors, transient_data = self.dataset_tree.extract_data(transient=True) if errors: self.validation_dialog = ValidationDialog(errors) return Extraction(success=False) - return Extraction(timml=timml_data, ttim=ttim_data) + return Extraction(steady=steady_data, transient=transient_data) def save_as_python(self) -> None: outpath, _ = QFileDialog.getSaveFileName(self, "Select file", "", "*.py") @@ -597,7 +601,7 @@ def save_as_python(self) -> None: if not extraction.success: return - script = data_to_script(extraction.timml, extraction.ttim) + script = data_to_script(extraction.steady, extraction.transient) with open(outpath, "w") as f: f.write(script) @@ -631,8 +635,8 @@ def convert_to_json( return True json_data = data_to_json( - extraction.timml, - extraction.ttim, + extraction.steady, + extraction.transient, output_options=self.parent.compute_widget.output_options, ) diff --git a/plugin/qgistim/widgets/install_dialog.py b/plugin/qgistim/widgets/install_dialog.py index 4806071..4862156 100644 --- a/plugin/qgistim/widgets/install_dialog.py +++ b/plugin/qgistim/widgets/install_dialog.py @@ -24,7 +24,7 @@ def finished(self, result) -> None: if result: self.message_bar.pushMessage( title="Info", - text="Succesfully installed TimML and TTim server", + text="Successfully installed timflow server", level=Qgis.Info, ) else: @@ -35,7 +35,7 @@ def finished(self, result) -> None: self.message_bar.pushMessage( title="Error", - text=f"Failed to install TimML and TTim server. {message}", + text=f"Failed to install timflow server. {message}", level=Qgis.Critical, ) return @@ -87,7 +87,7 @@ class InstallDialog(QDialog): def __init__(self, parent=None): QDialog.__init__(self, parent) self.parent = parent - self.setWindowTitle("Install TimML and TTim server") + self.setWindowTitle("Install timflow server") self.install_task = None # Define widgets @@ -133,7 +133,7 @@ def __init__(self, parent=None): def initialize_version_view(self): version_widgets = {} version_layout = QGridLayout() - for i, package in enumerate(["timml", "ttim", "gistim"]): + for i, package in enumerate(["timflow", "gistim"]): version_view = QLineEdit() version_view.setEnabled(False) widgets = ( @@ -147,20 +147,17 @@ def initialize_version_view(self): def update_versions(self): versions = self.parent.server_handler.versions() - for package in ["timml", "ttim", "gistim"]: + for package in ["timflow", "gistim"]: self.version_widgets[package][1].setText(versions.get(package)) - return def enable_install_buttons(self, enabled: bool) -> None: self.install_github_button.setEnabled(enabled) self.install_zip_button.setEnabled(enabled) - return def set_zip_path(self) -> None: path, _ = QFileDialog.getOpenFileName(self, "Select file", "", "*.zip") if path != "": # Empty string in case of cancel button press self.install_zip_line_edit.setText(path) - return def install_from_zip(self) -> None: path = self.install_zip_line_edit.text() @@ -181,7 +178,6 @@ def install_from_zip(self) -> None: ) self.enable_install_buttons(False) QgsApplication.taskManager().addTask(self.install_task) - return def install_from_github(self) -> None: reply = QMessageBox.question( @@ -196,4 +192,3 @@ def install_from_github(self) -> None: self.install_task = InstallGithubTask(self, message_bar=self.parent.message_bar) self.enable_install_buttons(False) QgsApplication.taskManager().addTask(self.install_task) - return diff --git a/plugin/qgistim/widgets/tim_widget.py b/plugin/qgistim/widgets/tim_widget.py index 4ca326c..a5d858d 100644 --- a/plugin/qgistim/widgets/tim_widget.py +++ b/plugin/qgistim/widgets/tim_widget.py @@ -121,7 +121,7 @@ def add_layer( ---------- layer: QGIS map layer, raster or vector layer. May be None, in which case - nothing is done (useful for optional ttim and associated layers). + nothing is done (useful for optional transient and associated layers). destination: str Legend group renderer: @@ -165,8 +165,8 @@ def add_layer( class InputGroup(LayersPanelGroup): def create_group(self) -> None: self._create_group() - self.create_subgroup("timml") - self.create_subgroup("ttim") + self.create_subgroup("steady-state") + self.create_subgroup("transient") return @@ -208,7 +208,7 @@ def __init__(self, parent, iface): self.compute_widget = ComputeWidget(self) self.install_dialog = InstallDialog(self) - self.config_button = QPushButton("Install TimML and TTim server") + self.config_button = QPushButton("Install timflow server") self.config_button.clicked.connect(self.install_dialog.show) self.config_button.setIcon(QgsApplication.getThemeIcon("/mActionOptions.svg")) @@ -261,7 +261,7 @@ def start_interpreter_task(self) -> Union[StartTask, None]: def execute(self, data: Dict[str, str]) -> Dict[str, Any]: """ - Execute a command, and check whether it executed succesfully. + Execute a command, and check whether it executed successfully. """ response = self.server_handler.send(data) return response @@ -321,13 +321,13 @@ def add_element(self, element: Any): suppress = self.dataset_widget.suppress_popup_checkbox.isChecked() self.dataset_widget.add_element(element) self.input_group.add_layer( - element.timml_layer, - "timml", + element.steady_layer, + "steady-state", renderer=element.renderer(), suppress=suppress, ) - self.input_group.add_layer(element.ttim_layer, "ttim") - self.input_group.add_layer(element.assoc_layer, "timml") + self.input_group.add_layer(element.transient_layer, "transient") + self.input_group.add_layer(element.assoc_layer, "steady-state") # QGIS layers # ----------- diff --git a/pyproject.toml b/pyproject.toml index a821466..3304678 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta" [project] name = "gistim" -description = "Connects TimML and TTim Analytic Element modeling to QGIS" +description = "Connects timflow Analytic Element modeling to QGIS" readme = "README.md" version = "0.6.0" maintainers = [{ name = "Huite Bootsma", email = "huite.bootsma@deltares.nl" }] requires-python = ">=3.11" -dependencies = ['pandas', 'timml>=6.3.0', 'ttim>=0.8.0', 'xarray', 'numpy'] +dependencies = ['pandas', 'timflow>=0.2.0', 'xarray', 'numpy'] classifiers = [ 'Development Status :: 4 - Beta', 'Intended Audience :: Science/Research', diff --git a/scripts/write_backend_versions.py b/scripts/write_backend_versions.py index dbee876..bee3e32 100644 --- a/scripts/write_backend_versions.py +++ b/scripts/write_backend_versions.py @@ -3,14 +3,12 @@ def write_versions(path): - import timml - import ttim + import timflow import gistim versions = { - "timml": timml.__version__, - "ttim": ttim.__version__, + "timflow": timflow.__version__, "gistim": gistim.__version__, } os.makedirs(os.path.dirname(path), exist_ok=True) diff --git a/test_plugin/test_aquifer_schemata.py b/test_plugin/test_aquifer_schemata.py index 7691664..ae7597d 100644 --- a/test_plugin/test_aquifer_schemata.py +++ b/test_plugin/test_aquifer_schemata.py @@ -15,12 +15,12 @@ def test_validate(self): "semiconf_top": [None], "semiconf_head": [None], } - self.assertEqual(schema.validate_timml(data), {}) + self.assertEqual(schema.validate_steady(data), {}) def test_validate_empty(self): schema = AquiferSchema() data = {} - self.assertEqual(schema.validate_timml(data), {"Table:": ["Table is empty."]}) + self.assertEqual(schema.validate_steady(data), {"Table:": ["Table is empty."]}) def test_validate_two_layer(self): schema = AquiferSchema() @@ -33,7 +33,7 @@ def test_validate_two_layer(self): "semiconf_top": [None], "semiconf_head": [None], } - self.assertEqual(schema.validate_timml(data), {}) + self.assertEqual(schema.validate_steady(data), {}) def test_validate_two_layer_invalid(self): schema = AquiferSchema() @@ -47,7 +47,7 @@ def test_validate_two_layer_invalid(self): "semiconf_head": [None], } expected = {"aquitard_c": ["No values provided at row(s): 2"]} - self.assertEqual(schema.validate_timml(data), expected) + self.assertEqual(schema.validate_steady(data), expected) def test_validate_two_layer_consistency(self): schema = AquiferSchema() @@ -65,4 +65,4 @@ def test_validate_two_layer_consistency(self): "aquifer_top is not greater or equal to aquifer_bottom at row(s): 1, 2" ] } - self.assertEqual(schema.validate_timml(data), expected) + self.assertEqual(schema.validate_steady(data), expected)