Commit 56a3279b authored by Berutti, Michael (Contractor) Charles's avatar Berutti, Michael (Contractor) Charles
Browse files

Merge branch 'master' into 'master'

Make public

Closes #12, #11, #14, #15, and #13

See merge request !47
parents b6555a23 ee50f1c4
......@@ -651,6 +651,27 @@ class SeriesOfHydraulicCells:
return df
def average_temperature(self):
"""Returns a weighted average temperature for a
series of hydraulic cells"""
edges = self._cell_edges
lengths = []
total_length = 0
temperatures = []
for index in range(len(edges) - 1):
dx = edges[index + 1] - edges[index]
lengths.append(dx)
total_length += dx
midpoint = dx / 2 + edges[index]
midpoint = np.array([midpoint])
temperatures.append(self._cell_property_by_location(
'temperature', midpoint))
numerator = 0
for index, temp in enumerate(temperatures):
numerator += temp[0] * lengths[index]
return numerator / total_length
def cell_edges(self):
"""Returns the edges of each of the cells
......
import numpy as np
import datetime
import math
import os
import warnings
from copy import deepcopy
import h5py
import numpy as np
from fluegg.hydraulics import from_csv
from fluegg.hydraulics import RoughBottomSeriesOfHydraulicCells
from fluegg.simclock import SimulationClock
......@@ -8,10 +14,6 @@ from fluegg.asiancarpeggs import BigheadCarpEggs
from fluegg.asiancarpeggs import SilverCarpEggs
from fluegg.asiancarpeggs import GrassCarpEggs
from fluegg.transporter import init_transporter
import h5py
import os
import datetime
import warnings
try:
from fluegg.ras import RASProject
......@@ -111,6 +113,14 @@ class Simulation:
if configuration is None:
configuration = {}
if "hydraulic_mode" in configuration.keys():
if configuration['hydraulic_mode'] == "hecras":
configuration['temperature'] = \
configuration['hecras_temperature']
else:
average_temp = self._hydraulic_model.average_temperature()
configuration['temperature'] = average_temp
# Initialize simulation results
simulation_results = SimulationResults(
self._simclock, self._particles, configuration)
......@@ -307,8 +317,7 @@ class SimulationResults:
location : int or float
Identifies the specific location for the plot.
location_direction : {'x', 'y', 'z'} or equivalently {0, 1, 2}, optional
If `axis_0` is `location`, direction specifies whether
the axis is in the x-, y-, or z-direction.
Direction specifies whether the axis is in the x-, y-, or z-direction.
Returns
-------
......@@ -329,13 +338,11 @@ class SimulationResults:
if location_direction not in valid_directions:
raise ValueError(
"Invalid value for direction: {}".format(location_direction))
if isinstance(location_direction, str):
elif isinstance(location_direction, str):
location_direction = 'xyz'.find(location_direction)
# get summary data
summary = self.summarize(axis_0='time',
axis_1='quantile',
summary = self.summarize(type='time quantile',
location_direction=location_direction)
time_axis = summary[:, 0]
egg_locations = summary[:, 1:]
......@@ -379,8 +386,7 @@ class SimulationResults:
Parameters
----------
location_direction : {'x', 'y', 'z'} or equivalently {0, 1, 2}, optional
If `axis_0` is `location`, direction specifies whether
the axis is in the x-, y-, or z-direction.
Direction specifies whether the axis is in the x-, y-, or z-direction.
Returns
-------
......@@ -396,8 +402,7 @@ class SimulationResults:
if location_direction not in valid_directions:
raise ValueError(
"Invalid value for direction: {}".format(location_direction))
if isinstance(location_direction, str):
elif isinstance(location_direction, str):
location_direction = 'xyz'.find(location_direction)
# get and validate fractional
......@@ -406,38 +411,37 @@ class SimulationResults:
raise ValueError(
"Invalid value for fractional: {}".format(fractional))
summary = self.summarize(axis_0='time',
axis_1='quantile',
summary = self.summarize(type='time quantile',
location_direction=location_direction,
fractional=fractional)
time_axis = summary[:, 0]
egg_locations = summary[:, 1:]
min = []
minimum = []
ten_percent = []
first_quartile = []
centroid = []
second_quartile = []
ninety_percent = []
max = []
maximum = []
for space_increment in egg_locations:
min.append(np.min(space_increment))
minimum.append(np.min(space_increment))
ten_percent.append(np.percentile(space_increment, 10))
first_quartile.append(np.percentile(space_increment, 25))
centroid.append(np.median(space_increment))
second_quartile.append(np.percentile(space_increment, 75))
ninety_percent.append(np.percentile(space_increment, 90))
max.append(np.max(space_increment))
maximum.append(np.max(space_increment))
return np.array([time_axis,
np.array(min),
np.array(minimum),
np.array(ten_percent),
np.array(first_quartile),
np.array(centroid),
np.array(second_quartile),
np.array(ninety_percent),
np.array(max)])
np.array(maximum)])
elif plot_name == "longitudinal distribution of eggs at time":
"""
......@@ -446,8 +450,7 @@ class SimulationResults:
time : int or float
Identifies the specific time for the plot.
location_direction : {'x', 'y', 'z'} or equivalently {0, 1, 2}, optional
If `axis_0` is `location`, direction specifies whether
the axis is in the x-, y-, or z-direction.
Direction specifies whether the axis is in the x-, y-, or z-direction.
bins : int, optional
The number of bins if `axis_1` is `histogram`
(the default is 20).
......@@ -488,8 +491,7 @@ class SimulationResults:
"Invalid value for fractional: {}".format(fractional))
# get summary data
summary = self.summarize(axis_0='location',
axis_1='histogram',
summary = self.summarize(type='location histogram',
histogram_bins=bins,
position=time,
location_direction=location_direction,
......@@ -510,21 +512,17 @@ class SimulationResults:
{time axis, x-axis, y-axis, z-axis}
"""
# get and validate fractional
fractional = kwargs.pop('fractional', False)
if not isinstance(fractional, bool):
raise ValueError(
"Invalid value for fractional: {}".format(fractional))
# get summary data for all three axes
x_summary = self.summarize(axis_0='time',
axis_1='quantile',
x_summary = self.summarize(type='time quantile',
location_direction='x')
y_summary = self.summarize(axis_0='time',
axis_1='quantile',
y_summary = self.summarize(type='time quantile',
location_direction='y')
z_summary = self.summarize(axis_0='time',
axis_1='quantile',
z_summary = self.summarize(type='time quantile',
location_direction='z',
fractional=fractional)
......@@ -623,21 +621,15 @@ class SimulationResults:
Parameters
----------
axis_0 : {'time', 'location'}
axis_1 : {'quantile', 'histogram'}
type : {'time quantile', 'location histogram'}
position : float
Time or location position to summarize. If `axis_0` is
`location`, `position` will be used as the time to
summarize. If `axis_0` is `time`, `position` will be
Time or location position to summarize. If `type` is
`location histogram`, `position` will be used as the time to
summarize. If `type` is `time quantile`, `position` will be
used as the location to summarize.
window : float, optional
Time or location window (the default is 0).
location_direction : {'x', 'y', 'z'} or equivalently {0, 1, 2}, optional
If `axis_0` is `location`, direction specifies whether
the axis is in the x-, y-, or z-direction.
secondary_direction : {'x', 'y', 'z'} or equivalently {0, 1, 2}, optional
If `axis_0` is `location`, secondary direction specifies whether
the dependent axis is in the x-, y-, or z-direction.
Direction specifies whether the axis is in the
x-, y-, or z-direction (the default is 'x').
histogram_bins : int, optional
The number of bins if `axis_1` is `histogram`
(the default is 20).
......@@ -652,130 +644,48 @@ class SimulationResults:
"""
def get_position_axis_from_direction(closest=False, secondary=False):
# get direction
if secondary:
direction = kwargs.pop('secondary_direction', 1)
valid_directions = ['x', 'y', 'z', 0, 1, 2]
if direction not in valid_directions:
raise ValueError(
"Invalid value for secondary_direction: {}".format(direction))
if isinstance(direction, str):
direction = 'xyz'.find(direction)
else:
direction = kwargs.pop('location_direction', 0)
valid_directions = ['x', 'y', 'z', 0, 1, 2]
if direction not in valid_directions:
raise ValueError(
"Invalid value for direction: {}".format(direction))
if isinstance(direction, str):
direction = 'xyz'.find(direction)
# get and validate fractional
fractional = kwargs.pop('fractional', False)
if not isinstance(fractional, bool):
raise ValueError(
"Invalid value for fractional: {}".format(fractional))
if closest:
# get position
position = kwargs.pop('position', 0.0)
if not isinstance(position, (int, float)):
raise ValueError("Invalid value for position: {}"
.format(position))
closest = 0.0
closest_index = 0
# find closest time step
for time_index, time_step in enumerate(self._time_series):
if abs(time_step - position) < abs(closest - position):
closest_index = time_index
closest = time_step
if time_step == position:
break
# get depth if depth fraction is requested
depth = 0
if fractional and direction == 2:
# raise warning if there is no depth data for backwards
# compatibility
try:
depth = self._depth[closest_index]
except TypeError:
fractional = False
warnings.warn(
"Old file. Cannot compute fractional depth.", Warning)
# get raw position values
dataset = self._positions
values = []
for egg_index, egg in enumerate(dataset[closest_index]):
if fractional and direction == 2:
values.append(egg[direction] / depth[egg_index])
else:
values.append(egg[direction])
values = np.sort(values)
return np.array(values)
else:
# get depth if depth fraction is requested
if fractional and direction == 2 and self._depth is None:
fractional = False
# get and validate type
dataset_type = kwargs.pop('type', 'time quantile')
valid_types = ['time quantile', 'location histogram']
if dataset_type not in valid_types:
raise ValueError(
"Invalid value for axis_0: {}".format(dataset_type))
# get and validate direction
direction = kwargs.pop('location_direction', 0)
valid_directions = ['x', 'y', 'z', 0, 1, 2]
if direction not in valid_directions:
raise ValueError(
"Invalid value for direction: {}".format(direction))
elif isinstance(direction, str):
direction = 'xyz'.find(direction)
# get and validate fractional
fractional = kwargs.pop('fractional', False)
if not isinstance(fractional, bool):
raise ValueError(
"Invalid value for fractional: {}".format(fractional))
if dataset_type == 'time quantile':
axis_0 = []
axis_0.extend(self._time_series)
axis_1 = self._positions[:, :, direction]
# get depth if depth fraction is requested
if fractional and direction == 2:
# raise warning if there is no depth data for backwards
# compatibility
try:
axis_1 = np.divide(axis_1, self._depth)
except TypeError:
warnings.warn(
"Old file. Cannot compute fractional depth.", Warning)
# get all locations
values = []
for time_index in range(len(self._time_series)):
time_step_values = []
for egg_index, egg in enumerate(
self._positions[time_index]):
if fractional and direction == 2:
time_step_values.append(
egg[direction] / self._depth[time_index, egg_index])
else:
time_step_values.append(egg[direction])
values.append(np.array(time_step_values))
return np.array(values)
# get and validate axis_0
axis_0 = kwargs.pop('axis_0', 'time')
valid_axes = ['time', 'location']
if axis_0 not in valid_axes:
raise ValueError("Invalid value for axis_0: {}".format(axis_0))
# get and validate axis_1
axis_1 = kwargs.pop('axis_1', 'quantile')
valid_axes = ['quantile', 'histogram']
if axis_1 not in valid_axes:
raise ValueError("Invalid value for axis_1: {}".format(axis_1))
# get data for axis_0
axis_0_data = []
if axis_0 is 'time':
axis_0_data.extend(self._time_series)
else:
values = get_position_axis_from_direction(closest=True)
axis_0_data.extend(values)
"Depth data not included in file. Cannot compute fractional depth.",
Warning)
# get data for axis_1
axis_1_data = []
if axis_1 is 'quantile':
if axis_0 is 'location':
values = get_position_axis_from_direction(secondary=True)
axis_1_data = values.T
else:
values = get_position_axis_from_direction()
axis_1_data = values
# combine axes into one array
array_0 = np.array(axis_0_data)
array_1 = np.array(axis_1_data)
array_0 = np.array(axis_0)
array_1 = np.array(axis_1)
array_0 = np.vstack(array_0)
......@@ -783,18 +693,54 @@ class SimulationResults:
return out
else:
axis_0 = []
# get and validate position
position = kwargs.pop('position', 0.0)
if not isinstance(position, (int, float)):
raise ValueError("Invalid value for position: {}"
.format(position))
closest = 0.0
closest_index = 0
# find closest time step
for time_index, time_step in enumerate(self._time_series):
if abs(time_step - position) < abs(closest - position):
closest_index = time_index
closest = time_step
if time_step == position:
break
# get raw position values
axis_0 = self._positions[closest_index, :, direction]
# get depth if depth fraction is requested
if fractional and direction == 2:
# raise warning if there is no depth data for backwards
# compatibility
try:
axis_0 = np.divide(axis_0, self._depth[closest_index, :])
except TypeError:
warnings.warn(
"Depth data not included in file. Cannot compute fractional depth.",
Warning)
# get range and bins
axis_0_min = axis_0_data[0]
axis_0_max = axis_0_data[-1]
axis_0_min = np.min(axis_0)
axis_0_max = np.max(axis_0)
# get and validate histogram_bins
histogram_bins = kwargs.pop('histogram_bins', 20)
if (not isinstance(histogram_bins, int)) or histogram_bins <= 0:
raise ValueError("Invalid value for histogram_bins: {}"
.format(histogram_bins))
# get histogram
hist = np.histogram(axis_0_data,
hist = np.histogram(axis_0,
bins=histogram_bins,
range=(math.floor(axis_0_min),
math.ceil(axis_0_max)))
# convert to array
bin_bounds = hist[1]
bins = []
......
......@@ -234,7 +234,7 @@ class LongitudinalTransporter(Transporter):
class ReverseLongitudinalTransporter(LongitudinalTransporter):
def _get_next_longitudinal_positions(self, hydraulic_results):
def _next_longitudinal_positions(self, hydraulic_results):
"""Returns incremented longitudinal particle positions
:param hydraulic_results: hydraulic results at current particle
......@@ -245,10 +245,10 @@ class ReverseLongitudinalTransporter(LongitudinalTransporter):
"""
# Initialize necessary calculations
longitudinal_position = self._particles.get_position()[:, 0]
longitudinal_position = self._particles.position()[:, 0]
num_particles = longitudinal_position.shape[0]
random_num = self._random_num(num_particles)
time_step = self._simulation_clock.get_time_step_size()
time_step = self._simulation_clock.time_step_size()
longitudinal_velocity = hydraulic_results.streamwise_velocity()
depth = hydraulic_results.depth()
shear_velocity = hydraulic_results.shear_velocity()
......@@ -259,9 +259,9 @@ class ReverseLongitudinalTransporter(LongitudinalTransporter):
reversal = -1
# Calculate incremented longitudinal positions
next_longitudinal_position = longitudinal_position + reversal * \
longitudinal_velocity * time_step + random_num * \
np.sqrt(2 * turbulent_diffusion * time_step)
next_longitudinal_position = longitudinal_position \
+ longitudinal_velocity * time_step * reversal \
+ random_num * np.sqrt(2 * turbulent_diffusion * time_step)
return next_longitudinal_position
......
......@@ -81,7 +81,7 @@ class TestRASProject(unittest.TestCase):
fetched_data = project.hydraulic_model_data('Unsteady')
for dataset in fetched_data.columns:
self.assertTrue(
set(combined_data[dataset].values) ==
set(combined_data[dataset].values) ==
set(fetched_data[dataset].values))
# Tests setting plan names
......@@ -150,7 +150,7 @@ class TestRASProject(unittest.TestCase):
self.assertEqual(
ras_data['Vel Chnl'][1] * feet_to_meters,
profile_data['Vmag_mps'][1])
self.assertEqual(
self.assertAlmostEqual(
ras_data['ChannelDist'][2] * feet_to_meters / 1000 / 2,
profile_data['CumlDistance_km'][1])
self.assertEqual(
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment