Skip to content

Commit 52d8bf8

Browse files
authored
Merge pull request #48 from DHI/feature/result_network_auto_completion
Feature: Implementation of ResultNetwork for Res1D auto-completion.
2 parents 96ca018 + 1c88318 commit 52d8bf8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+4348
-654
lines changed

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,15 @@ mikeio1d/bin/*.dll
138138
mikeio1d/bin/*.pfs
139139
mikeio1d/bin/*.ubg
140140
mikeio1d/bin/*.xml
141+
142+
# Specific files
143+
tests/testdata/NetworkRiver.mod.res1d
144+
tests/testdata/NetworkRiver.extract.csv
145+
tests/testdata/NetworkRiver.extract.dfs0
146+
tests/testdata/NetworkRiver.extract.txt
147+
tests/testdata/DischargeInStructure.extract.csv
148+
tests/testdata/DischargeInStructure.extract.dfs0
149+
tests/testdata/DischargeInStructure.extract.txt
150+
tests/testdata/W_right_DischargeInStructure.extract.csv
151+
tests/testdata/W_right_DischargeInStructure.extract.dfs0
152+
tests/testdata/W_right_DischargeInStructure.extract.txt

CHANGELOG.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,20 @@
22

33
## [Unreleased]
44

5-
## [0.2] - 2022-06-20
5+
## [0.3] - 2023-04-21
6+
7+
### Added
8+
9+
- Ability to add queries using auto-completion
10+
- Ability to modify res1d file contents using a data frame
11+
- Ability to extract time series to csv, dfs0, and txt files
12+
- Support for querying structures and global data items
13+
14+
### Changed
15+
16+
- Use MIKE 1D NuGet packages v21.0.0
17+
18+
## [0.2] - 2023-03-14
619

720
### Added
821

@@ -32,6 +45,7 @@
3245
- Reading of res1d and xns11 files into pandas data frames
3346

3447

35-
[unreleased]: https://github.com/DHI/mikeio1d/compare/v0.2...HEAD
48+
[unreleased]: https://github.com/DHI/mikeio1d/compare/v0.3...HEAD
49+
[0.3]: https://github.com/DHI/mikeio1d/releases/tag/v0.3
3650
[0.2]: https://github.com/DHI/mikeio1d/releases/tag/v0.2
3751
[0.1]: https://github.com/DHI/mikeio1d/releases/tag/v0.1

mikeio1d/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
# Dev branch marker is: 'X.Y.dev' or 'X.Y.devN' where N is an integer.
2020
# 'X.Y.dev0' is the canonical version of 'X.Y.dev'
2121
#
22-
__version__ = "0.2.0"
22+
__version__ = "0.3.0"
2323

2424
if "64" not in architecture()[0]:
2525
raise Exception("This library has not been tested for a 32 bit system.")
@@ -30,7 +30,8 @@
3030
clr.AddReference("System")
3131
clr.AddReference("System.Runtime")
3232
clr.AddReference("System.Runtime.InteropServices")
33-
# clr.AddReference("DHI.Generic.MikeZero.EUM")
33+
clr.AddReference("DHI.Generic.MikeZero.DFS")
34+
clr.AddReference("DHI.Generic.MikeZero.EUM")
3435
# clr.AddReference("DHI.PFS")
3536
# clr.AddReference("DHI.Projections")
3637
clr.AddReference("DHI.Mike1D.Generic")

mikeio1d/custom_exceptions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,8 @@ def __init__(self, query_string):
4747
class InvalidQuantity(ValueError):
4848
def __init__(self, message="Invalid quantity."):
4949
super().__init__(message)
50+
51+
52+
class InvalidStructure(ValueError):
53+
def __init__(self, message="Invalid structure ID."):
54+
super().__init__(message)

mikeio1d/query.py

Lines changed: 6 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,6 @@
1-
import numpy as np
2-
3-
from .custom_exceptions import NoDataForQuery, InvalidQuantity
4-
from .various import NAME_DELIMITER
5-
6-
7-
class QueryData:
8-
"""
9-
Base query class that declares what data to extract from a .res1d file.
10-
"""
11-
12-
def __init__(self, quantity, name=None, validate=True):
13-
self._name = name
14-
self._quantity = quantity
15-
16-
if validate:
17-
self._validate()
18-
19-
def _validate(self):
20-
if not isinstance(self.quantity, str):
21-
raise TypeError("Quantity must be a string.")
22-
23-
if self.name is not None and not isinstance(self.name, str):
24-
raise TypeError("Argument 'name' must be either None or a string.")
25-
26-
@staticmethod
27-
def from_dotnet_to_python(array):
28-
"""Convert .NET array to numpy."""
29-
return np.fromiter(array, np.float64)
30-
31-
@property
32-
def quantity(self):
33-
return self._quantity
34-
35-
@property
36-
def name(self):
37-
return self._name
38-
39-
def _check_invalid_quantity(self, res1d):
40-
if self._quantity not in res1d.quantities:
41-
raise InvalidQuantity(f"Undefined quantity {self._quantity}. "
42-
f"Allowed quantities are: {', '.join(res1d.quantities)}.")
43-
44-
def _check_invalid_values(self, values):
45-
if values is None:
46-
raise NoDataForQuery(str(self))
47-
48-
def __repr__(self):
49-
return NAME_DELIMITER.join([self._quantity, self._name])
50-
51-
52-
class QueryDataReach(QueryData):
53-
"""A query object that declares what reach data to extract from a .res1d file.
54-
55-
Parameters
56-
----------
57-
quantity: str
58-
e.g. 'WaterLevel' or 'Discharge'. Call mike1d_quantities() to get all quantities.
59-
name: str, optional
60-
Reach name
61-
62-
Examples
63-
--------
64-
`QueryDataReach('WaterLevel', 'reach1', 10)` is a valid query.
65-
"""
66-
67-
def __init__(self, quantity, name=None, chainage=None, validate=True):
68-
super().__init__(quantity, name, validate=False)
69-
self._chainage = chainage
70-
71-
if validate:
72-
self._validate()
73-
74-
def _validate(self):
75-
super()._validate()
76-
77-
if self.chainage is not None and not isinstance(self.chainage, (int, float)):
78-
raise TypeError("Argument 'chainage' must be either None or a number.")
79-
80-
if self.name is None and self.chainage is not None:
81-
raise ValueError("Argument 'chainage' cannot be set if name is None.")
82-
83-
def get_values(self, res1d):
84-
self._check_invalid_quantity(res1d)
85-
86-
name = self._name
87-
chainage = self._chainage
88-
quantity = self._quantity
89-
90-
values = ( res1d.query.GetReachValues(name, chainage, quantity)
91-
if chainage is not None else
92-
res1d.query.GetReachStartValues(name, quantity) )
93-
94-
self._check_invalid_values(values)
95-
96-
return self.from_dotnet_to_python(values)
97-
98-
@property
99-
def chainage(self):
100-
return self._chainage
101-
102-
def __repr__(self):
103-
name = self._name
104-
chainage = self._chainage
105-
quantity = self._quantity
106-
107-
return ( NAME_DELIMITER.join([quantity, name, f'{chainage:g}'])
108-
if chainage is not None else
109-
NAME_DELIMITER.join([quantity, name]) )
110-
111-
112-
class QueryDataNode(QueryData):
113-
"""A query object that declares what node data to extract from a .res1d file.
114-
115-
Parameters
116-
----------
117-
quantity: str
118-
e.g. 'WaterLevel' or 'Discharge'. Call mike1d_quantities() to get all quantities.
119-
name: str, optional
120-
Node name
121-
122-
Examples
123-
--------
124-
`QueryDataNode('WaterLevel', 'node1')` is a valid query.
125-
"""
126-
127-
def __init__(self, quantity, name=None, validate=True):
128-
super().__init__(quantity, name, validate)
129-
130-
def get_values(self, res1d):
131-
self._check_invalid_quantity(res1d)
132-
133-
values = res1d.query.GetNodeValues(self._name, self._quantity)
134-
135-
self._check_invalid_values(values)
136-
137-
return self.from_dotnet_to_python(values)
138-
139-
140-
class QueryDataCatchment(QueryData):
141-
"""A query object that declares what catchment data to extract from a .res1d file.
142-
143-
Parameters
144-
----------
145-
quantity: str
146-
e.g. 'TotalRunoff'. Call mike1d_quantities() to get all quantities.
147-
name: str, optional
148-
Catchment name
149-
150-
Examples
151-
--------
152-
`QueryDataCatchment('TotalRunoff', 'catchment1')` is a valid query.
153-
"""
154-
155-
def __init__(self, quantity, name=None, validate=True):
156-
super().__init__(quantity, name, validate)
157-
158-
def get_values(self, res1d):
159-
self._check_invalid_quantity(res1d)
160-
161-
values = res1d.query.GetCatchmentValues(self._name, self._quantity)
162-
163-
self._check_invalid_values(values)
164-
165-
return self.from_dotnet_to_python(values)
1+
from .result_query import QueryData
2+
from .result_query import QueryDataCatchment
3+
from .result_query import QueryDataGlobal
4+
from .result_query import QueryDataNode
5+
from .result_query import QueryDataReach
6+
from .result_query import QueryDataStructure

0 commit comments

Comments
 (0)