Example #1
0
    def __init__(self, file_path: str):
        """Create an instance from the path to an iPSP file.

        :param file_path: path to iPSP file
        :type file_path: str
        """
        self._file_path = file_path
        self._loader = PSPDataloader(file_path)
 def test_zone_info(self):
     loader = PSPDataloader(DATASETS["ipsp_fake.hdf5"])
     info = loader.zone_info
     assert "SamplingFrequency" in info
     assert isinstance(info["SamplingFrequency"][0], float)
     assert info["ZoneName"][0] == "UpperSide"
     loader.zone = loader.zone_names[-1]
     info = loader.zone_info
     assert info["ZoneName"][0] == "LowerSide"
 def test_zone(self):
     loader = PSPDataloader(DATASETS["ipsp_fake.hdf5"])
     names = loader.zone_names
     assert "Zone0000" in names and "Zone0001" in names
     assert loader.zone == "Zone0000"
     loader.zone = names[-1]
     assert loader.zone == names[-1]
     loader.zone = ""
     assert loader.zone == names[-1]
Example #4
0
 def test_field_names(self, get_test_data):
     for case in get_test_data.test_files:
         file_path = get_test_data.path + case
         loader = PSPDataloader(file_path)
         first_times = get_test_data.field_names[case]
         assert list(
             loader.field_names().keys())[:len(first_times)] == list(
                 first_times.keys())
         assert list(
             loader.field_names().values())[:len(first_times)] == list(
                 first_times.values())
 def test_info(self):
     loader = PSPDataloader(DATASETS["ipsp_fake.hdf5"])
     info = loader.info
     assert "Mach" in info.keys()
     assert len(info["Mach"]) == 2
     assert isinstance(info["Mach"][0], float)
     assert isinstance(info["Mach"][1], str)
 def test_common_properties(self):
     loader = PSPDataloader(DATASETS["ipsp_fake.hdf5"])
     n_snapshots = 30
     freq = 10
     times = loader.write_times
     assert len(times) == n_snapshots
     assert times[-1] == str(round((n_snapshots - 1) / freq, 8))
     assert times[0] == str(round(0.0, 8))
     fields = loader.field_names
     assert len(fields.keys()) == 1
     assert fields[times[0]][0] == "Cp"
     vertices = loader.vertices
     assert vertices.shape == (50, 20, 3)
     weights = loader.weights
     assert weights.shape == (50, 20)
     loader.zone = loader.zone_names[-1]
     vertices = loader.vertices
     assert vertices.shape == (50, 20, 3)
     weights = loader.weights
     assert weights.shape == (50, 20)
     # load single field, single snapshot
     cp = loader.load_snapshot("Cp", times[-1])
     assert cp.shape == (50, 20)
     # load single field, multiple snapshots
     cp_s = loader.load_snapshot("Cp", times[-10:])
     assert cp_s.shape == (50, 20, 10)
     assert pt.allclose(cp, cp_s[:, :, -1])
     # load multiple fields, single snapshot
     cp, = loader.load_snapshot(["Cp"], times[0])
     assert cp.shape == (50, 20)
     # load multiple fields, multiple snapshots
     cp_s, = loader.load_snapshot(["Cp"], times[:10])
     assert pt.allclose(cp, cp_s[:, :, 0])
Example #7
0
 def test_get_vertices(self, get_test_data):
     for case in get_test_data.test_files:
         file_path = get_test_data.path + case
         loader = PSPDataloader(file_path)
         vertices = loader.get_vertices()
         assert tuple(vertices.size()) == (18750, 3)
         loader.select_dataset("Wing")
         vertices = loader.get_vertices()
         assert tuple(vertices.size()) == (73935, 3)
         vertices = loader.get_vertices(10000, 20000)
         assert tuple(vertices.size()) == (10000, 3)
         vertices = loader.get_vertices(70000, 80000)
         assert tuple(vertices.size()) == (3935, 3)
Example #8
0
 def test_get_weights(self, get_test_data):
     for case in get_test_data.test_files:
         file_path = get_test_data.path + case
         loader = PSPDataloader(file_path)
         weights = loader.get_weights()
         assert weights.size()[0] == 18750
         loader.select_dataset("Wing")
         weights = loader.get_weights()
         assert weights.size()[0] == 73935
Example #9
0
 def test_load_snapshot(self, get_test_data):
     for case in get_test_data.test_files:
         file_path = get_test_data.path + case
         loader = PSPDataloader(file_path)
         sample_time = get_test_data.write_times[case][-1]
         snapshot = loader.load_snapshot("cp", sample_time)
         assert snapshot.size()[0] == 18750
         loader.select_dataset("Wing")
         snapshot = loader.load_snapshot("cp", sample_time)
         assert snapshot.size()[0] == 73935
Example #10
0
 def test_select_dataset(self, get_test_data):
     for case in get_test_data.test_files:
         file_path = get_test_data.path + case
         loader = PSPDataloader(file_path)
         datasets = get_test_data.datasets[case]
         assert loader._dataset_names == datasets
         assert loader._dataset == datasets[0]
         loader.select_dataset(datasets[1])
         assert loader._dataset == datasets[1]
         loader.select_dataset("Banana")
         assert loader._dataset == datasets[1]
Example #11
0
 def test_write_times(self, get_test_data):
     for case in get_test_data.test_files:
         file_path = get_test_data.path + case
         loader = PSPDataloader(file_path)
         first_times = get_test_data.write_times[case]
         assert loader.write_times()[:len(first_times)] == first_times
 def test_time_to_index(self):
     loader = PSPDataloader(DATASETS["ipsp_fake.hdf5"])
     times = loader.write_times
     indices = loader._time_to_index(times)
     assert indices == list(range(30))
Example #13
0
class PSPExplorer(object):
    """Explore iPSP data interactively.
    """
    def __init__(self, file_path: str):
        """Create an instance from the path to an iPSP file.

        :param file_path: path to iPSP file
        :type file_path: str
        """
        self._file_path = file_path
        self._loader = PSPDataloader(file_path)

    def _aspect_ratio(self, vertices: pt.Tensor) -> dict:
        dx = abs(
            (pt.max(vertices[:, :, 0]) - pt.min(vertices[:, :, 0])).item())
        dy = abs(
            (pt.max(vertices[:, :, 1]) - pt.min(vertices[:, :, 1])).item())
        dz = abs(
            (pt.max(vertices[:, :, 2]) - pt.min(vertices[:, :, 2])).item())
        return {"x": 1.0, "y": dy / dx, "z": dz / dx}

    def _create_time_slider(self, times: List[str]) -> dict:
        """Create a time slider to select snapshots.

        :param times: list of write times
        :type times: List[str]
        :return: slider dictionary
        :rtype: dict
        """
        steps = []
        for i in range(len(times)):
            step = dict(method="update",
                        args=[{
                            "visible": [False] * len(times)
                        }, {
                            "title": "Selected time: {:s}".format(times[i])
                        }],
                        label=str(i))
            step["args"][0]["visible"][i] = True
            steps.append(step)
        slider = dict(active=0, pad={"t": 50}, steps=steps)
        return slider

    def _create_surface_trace(self, field: pt.Tensor, vertices: pt.Tensor,
                              weights: pt.Tensor, every: int, cmin: float,
                              cmax: float):
        return go.Surface(x=vertices[::every, ::every, 0],
                          y=vertices[::every, ::every, 1],
                          z=vertices[::every, ::every, 2],
                          surfacecolor=field[::every, ::every] *
                          weights[::every, ::every],
                          cmin=cmin,
                          cmax=cmax)

    def _create_surface_layout(self,
                               vertices: pt.Tensor,
                               width: int,
                               times=None) -> go.Layout:
        aspect = self._aspect_ratio(vertices)
        if times is None:
            sliders = None
        else:
            sliders = [self._create_time_slider(times)]
        layout = go.Layout(width=width,
                           height=int(width * aspect["x"]),
                           scene={
                               "camera_eye": {
                                   "x": 0,
                                   "y": -1.0,
                                   "z": 0.5
                               },
                               "aspectratio": aspect
                           },
                           sliders=sliders)
        return layout

    def interact(self,
                 zone: str,
                 field_name: str,
                 times: list,
                 mask: bool = True,
                 width: int = 1024,
                 every: int = 5,
                 cmin: float = -2,
                 cmax: float = 0.5) -> go.Figure:
        """Show selected snapshots of an iPSP file as interactive surface plot.

        :param zone: name of the zone to display
        :type zone: str
        :param field_name: name of the field to display
        :type field_name: str
        :param times: list of times instances to show
        :type times: list
        :param mask: if True, the data is masked using the mask provided
            in the iPSP dataset, defaults to True
        :type mask: bool, optional
        :param width: width of the plot, defaults to 1024
        :type width: int, optional
        :param every: plot only every nth point, defaults to 5
        :type every: int, optional
        :param cmin: lower bound for color range, defaults to -2
        :type cmin: float, optional
        :param cmax: upper bound for color range, defaults to 0.5
        :type cmax: float, optional
        :return: interactive iPSP surface plot
        :rtype: go.Figure
        """
        self._loader.zone = zone
        vertices = self._loader.vertices
        weights = self._loader.weights
        if not mask:
            weights = 1.0
        fields = self._loader.load_snapshot(field_name, times)
        layout = self._create_surface_layout(vertices, width, times)
        fig = go.Figure(layout=layout)
        for i in range(len(times)):
            field = fields[:, :, i]
            surface = self._create_surface_trace(field, vertices, weights,
                                                 every, cmin, cmax)
            fig.add_trace(surface)
        return fig

    def mean(self,
             zone: str,
             field_name: str,
             times: list,
             mask: bool = True,
             width: int = 1024,
             every=5,
             cmin: float = -2,
             cmax: float = 0.5) -> go.Figure:
        """Show temporal mean of an iPSP file as interactive surface plot.

        :param zone: name of the zone to display
        :type zone: str
        :param field_name: name of the field to display
        :type field_name: str
        :param times: snapshot times over which to compute the mean
        :type times: list
        :param mask: if True, the data is masked using the mask provided
            in the iPSP dataset, defaults to True
        :type mask: bool, optional
        :param width: width of the plot, defaults to 1024
        :type width: int, optional
        :param every: use only every nth point for plotting,
            defaults to 5
        :type every: int, optional
        :param cmin: lower bound for color range, defaults to -2
        :type cmin: float, optional
        :param cmax: upper bound for color range, defaults to 0.5
        :type cmax: float, optional
        :return: interactive iPSP surface plot showing the temporal mean
        :rtype: go.Figure
        """
        self._loader.zone = zone
        vertices = self._loader.vertices
        weights = self._loader.weights
        if not mask:
            weights = 1.0
        fields = self._loader.load_snapshot(field_name, times)
        mean = pt.mean(fields, dim=2)
        layout = self._create_surface_layout(vertices, width)
        fig = go.Figure(layout=layout)
        surface = self._create_surface_trace(mean, vertices, weights, every,
                                             cmin, cmax)
        fig.add_trace(surface)
        return fig

    def std(self,
            zone: str,
            field_name: str,
            times: list,
            mask: bool = True,
            width: int = 1024,
            every=5,
            cmin: float = 0,
            cmax: float = 0.5) -> go.Figure:
        """Show temporal standard deviation as interactive surface plot.

        :param zone: name of the zone to display
        :type zone: str
        :param field_name: name of the field to display
        :type field_name: str
        :param times: snapshot times over which to compute the standard
            deviation
        :type times: list
        :param mask: if True, the data is masked using the mask provided
            in the iPSP dataset, defaults to True
        :type mask: bool, optional
        :param width: width of the plot, defaults to 1024
        :type width: int, optional
        :param every: use only every nth point for plotting,
            defaults to 5
        :type every: int, optional
        :param cmin: lower bound for color range, defaults to -2
        :type cmin: float, optional
        :param cmax: upper bound for color range, defaults to 0.5
        :type cmax: float, optional
        :return: interactive iPSP surface plot
        :rtype: go.Figure
        """
        self._loader.zone = zone
        vertices = self._loader.vertices
        weights = self._loader.weights
        if not mask:
            weights = 1.0
        fields = self._loader.load_snapshot(field_name, times)
        std = pt.std(fields, dim=2)
        layout = self._create_surface_layout(vertices, width)
        fig = go.Figure(layout=layout)
        surface = self._create_surface_trace(std, vertices, weights, every,
                                             cmin, cmax)
        fig.add_trace(surface)
        return fig

    @property
    def loader(self) -> PSPDataloader:
        """Get the `PSPdataloader` instance used to access data.

        This propertie allows accessing the loader's metadata via
        the explorer without having to create a new loader instance.

        :return: PSP dataloader instance
        :rtype: PSPDataloader
        """
        return self._loader