Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add checks related to vegetation and variable friction #353

Merged
merged 25 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f22fc08
Update pyproject to correct schema version
margrietpalm Jan 17, 2024
5f16b37
Add check if plural parameters content can be converted to list of fl…
margrietpalm Jan 17, 2024
15d73a8
Add check if plural parameters content can be converted to list of fl…
margrietpalm Jan 17, 2024
ec23912
Add check for correct lengths of cross section variables
margrietpalm Jan 18, 2024
aa9936a
Add range checks
margrietpalm Jan 19, 2024
e1bd841
Merge branch 'margriet_339-var-friction-and-veg' of github.com:nens/t…
margrietpalm Jan 19, 2024
1eb5317
Check for friction type combined with vegetation
margrietpalm Jan 19, 2024
d44bbe4
Check for friction type and vegetation parameters
margrietpalm Jan 19, 2024
70f9393
Adapt tests to allow for tabulated yz shapes without friction value a…
margrietpalm Jan 22, 2024
7dd9154
Add warnings for cases where both friction_value and friction_values …
margrietpalm Jan 22, 2024
be2210d
Add checks for allowed profile shape
margrietpalm Jan 22, 2024
fe1dcf1
Clean up error messages
margrietpalm Jan 23, 2024
f51b047
Clean up error codes
margrietpalm Jan 23, 2024
3807151
Merge branch 'master' into margriet_339-var-friction-and-veg
margrietpalm Jan 23, 2024
f99393e
Upgrade schema version and fix some bugs
margrietpalm Jan 23, 2024
90a7f13
Include friction values in check
margrietpalm Jan 24, 2024
6c125d6
Fix bug in combining list and item
margrietpalm Jan 25, 2024
1869f68
Clarify message and parameter names
margrietpalm Jan 29, 2024
0fe8960
Fix typo in message
margrietpalm Jan 29, 2024
47b95f1
Rename some more variables
margrietpalm Jan 29, 2024
4119c7d
Merge branch 'margriet_339-var-friction-and-veg' of github.com:nens/t…
margrietpalm Jan 29, 2024
254272e
Remove duplicate check
margrietpalm Jan 29, 2024
439f5bd
Update changelog
margrietpalm Jan 29, 2024
dee6407
Renumber and reorder some checks, remove duplicates, update changelog
margrietpalm Jan 29, 2024
01b07ae
Add check that ensures that either none or all vegetation parameters …
margrietpalm Jan 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ dependencies = [
"Click",
"GeoAlchemy2>=0.9,!=0.11.*",
"SQLAlchemy>=1.4",
"threedi-schema==0.217.*",
"threedi-schema==0.219.*",
]

[project.optional-dependencies]
Expand Down
162 changes: 162 additions & 0 deletions threedi_modelchecker/checks/cross_section_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -583,3 +583,165 @@ def description(self):
"of friction is recommended in case there is a significant variation "
"of the bed level (for instance, in a scenario with overflowing floodplains)."
)


class CrossSectionVariableCorrectLengthCheck(CrossSectionBaseCheck):
"""Variable friction and vegetation properties should 1 value for each element; len(var_property) = len(width)-1"""
margrietpalm marked this conversation as resolved.
Show resolved Hide resolved

def get_invalid(self, session):
invalids = []
for record in self.to_check(session).filter(
(self.column.name != None) & (self.column.name != "")
):
try:
# only take widths because another check already ensures len(widths) = len(heights)
widths = [float(x) for x in record.width.split(" ")]
values = [
float(x) for x in getattr(record, self.column.name).split(" ")
]
except ValueError:
continue # other check catches this
if not (len(widths) - 1 == len(values)):
invalids.append(record)
return invalids

def description(self):
return f"{self.column_name} should contain exactly 1 value less as the lenght and width"
margrietpalm marked this conversation as resolved.
Show resolved Hide resolved


class CrossSectionVariableRangeCheck(CrossSectionBaseCheck):
def __init__(
self,
min_value=None,
max_value=None,
left_inclusive=True,
right_inclusive=True,
*args,
**kwargs,
):
if min_value is None and max_value is None:
raise ValueError("Please supply at least one of {min_value, max_value}.")
str_parts = []
if min_value is None:
self.min_valid = lambda x: True
else:
self.min_valid = (
(lambda x: x >= min_value)
if left_inclusive
else (lambda x: x > min_value)
)
str_parts.append(f"{'< ' if left_inclusive else '<= '}{min_value}")
if max_value is None:
self.max_valid = lambda x: True
else:
self.max_valid = (
(lambda x: x <= max_value)
if right_inclusive
else (lambda x: x < max_value)
)
str_parts.append(f"{'> ' if right_inclusive else '>= '}{max_value}")
self.range_str = " and/or ".join(str_parts)
super().__init__(*args, **kwargs)

def get_invalid(self, session):
invalids = []
for record in self.to_check(session).filter(
(self.column != None) & (self.column != "")
):
try:
values = [
float(x) for x in getattr(record, self.column.name).split(" ")
]
except ValueError:
invalids.append(record)
if not self.min_valid(min(values)):
invalids.append(record)
elif not self.max_valid(max(values)):
invalids.append(record)
return invalids

def description(self):
return f"some values in {self.column_name} are {self.range_str}"


class CrossSectionVariableFrictionRangeCheck(CrossSectionVariableRangeCheck):
def __init__(
self,
friction_types,
*args,
**kwargs,
):
self.friction_types = friction_types
super().__init__(*args, **kwargs)

def get_invalid(self, session):
invalids = []
def_table = models.CrossSectionDefinition
loc_table = models.CrossSectionLocation
records = set(
self.to_check(session)
.join(loc_table, loc_table.definition_id == def_table.id)
.filter(
loc_table.friction_type.in_(self.friction_types)
& def_table.friction_values.is_not(None)
)
.filter((self.column != None) & (self.column != ""))
.all()
)
for record in records:
try:
values = [
float(x) for x in getattr(record, self.column.name).split(" ")
]
except ValueError:
continue
if not self.min_valid(min(values)):
invalids.append(record)
elif not self.max_valid(max(values)):
invalids.append(record)
return invalids


class OpenIncreasingCrossSectionVariableCheck(CrossSectionBaseCheck):
"""
Check if cross sections used with friction with conveyance
are open and monotonically increasing in width
"""

def __init__(self, *args, **kwargs):
super().__init__(
shapes=(constants.CrossSectionShape.TABULATED_YZ,), *args, **kwargs
)

def get_invalid(self, session):
invalids = []
records = self.to_check(session).filter(
(self.column != None) & (self.column != "")
)
for record in records:
try:
# Only used for TABULATED_YZ
widths = [float(x) for x in record.width.split(" ")]
heights = [float(x) for x in record.height.split(" ")]
except ValueError:
continue # other check catches this

_, _, configuration = cross_section_configuration(
shape=record.shape.value, heights=heights, widths=widths
)

# friction with conveyance can only be used for cross-sections
# which are open *and* have a monotonically increasing width
if configuration == "closed" or (
len(widths) > 1
and any(
next_width < previous_width
for (previous_width, next_width) in zip(widths[:-1], widths[1:])
)
):
invalids.append(record)

return invalids

def description(self):
return f"{self.column_name} can only be used in an open channel with monotonically increasing width values"
Loading
Loading