Example #1
0
    def _helper_get_impulse_response_handles(self, num_inputs, num_outputs):
        # Get state space system
        A, B, C = parallel.call_and_bcast(
            get_system_arrays, self.num_states, num_inputs, num_outputs)

        # Run impulse responses
        direct_vec_array = parallel.call_and_bcast(
            get_direct_impulse_response_array, A, B, self.num_steps)
        adjoint_vec_array = parallel.call_and_bcast(
            get_adjoint_impulse_response_array, A, C, self.num_steps,
            np.identity(self.num_states))

        # Save data to disk
        direct_vec_handles = [
            VecHandlePickle(self.direct_vec_path % i)
            for i in range(direct_vec_array.shape[1])]
        adjoint_vec_handles = [
            VecHandlePickle(self.adjoint_vec_path % i)
            for i in range(adjoint_vec_array.shape[1])]
        if parallel.is_rank_zero():
            for idx, handle in enumerate(direct_vec_handles):
                handle.put(direct_vec_array[:, idx])
            for idx, handle in enumerate(adjoint_vec_handles):
                handle.put(adjoint_vec_array[:, idx])

        parallel.barrier()
        return direct_vec_handles, adjoint_vec_handles
Example #2
0
    def test_Hankel(self):
        """Test forming Hankel array from first column and last row."""
        for num_rows in [1, 4, 6]:
            for num_cols in [1, 3, 6]:

                # Generate simple integer values so structure of array is easy
                # to see.  This doesn't affect the robustness of the test, as
                # all we are concerned about is structure.
                first_col = np.arange(1, num_rows + 1)
                last_row = np.arange(1, num_cols + 1) * 10
                last_row[0] = first_col[-1]

                # Fill in Hankel array.  Recall that along skew diagonals, i +
                # j is constant.
                Hankel_true = np.zeros((num_rows, num_cols))
                for i in range(num_rows):
                    for j in range(num_cols):

                        # Upper left triangle of values.  Fill skew diagonals
                        # until we hit the lower left corner of the array, where
                        # i + j = num_rows - 1.
                        if i + j < num_rows:
                            Hankel_true[i, j] = first_col[i + j]

                        # Lower right triangle of values.  Starting on skew
                        # diagonal just to right of lower left corner of array,
                        # fill in rest of values.
                        else:
                            Hankel_true[i, j] = last_row[i + j - num_rows + 1]

                # Compute Hankel array using util and test
                Hankel_test = util.Hankel(first_col, last_row)
                np.testing.assert_equal(Hankel_test, Hankel_true)
Example #3
0
    def test_Hankel(self):
        """Test forming Hankel array from first column and last row."""
        for num_rows in [1, 4, 6]:
            for num_cols in [1, 3, 6]:

                # Generate simple integer values so structure of array is easy
                # to see.  This doesn't affect the robustness of the test, as
                # all we are concerned about is structure.
                first_col = np.arange(1, num_rows + 1)
                last_row = np.arange(1, num_cols + 1) * 10
                last_row[0] = first_col[-1]

                # Fill in Hankel array.  Recall that along skew diagonals, i +
                # j is constant.
                Hankel_true = np.zeros((num_rows, num_cols))
                for i in range(num_rows):
                    for j in range(num_cols):

                        # Upper left triangle of values.  Fill skew diagonals
                        # until we hit the lower left corner of the array, where
                        # i + j = num_rows - 1.
                        if i + j < num_rows:
                            Hankel_true[i, j] = first_col[i + j]

                        # Lower right triangle of values.  Starting on skew
                        # diagonal just to right of lower left corner of array,
                        # fill in rest of values.
                        else:
                            Hankel_true[i, j] = last_row[i + j - num_rows + 1]

                # Compute Hankel array using util and test
                Hankel_test = util.Hankel(first_col, last_row)
                np.testing.assert_equal(Hankel_test, Hankel_true)
Example #4
0
    def _helper_get_impulse_response_handles(self, num_inputs, num_outputs):
        # Get state space system
        A, B, C = parallel.call_and_bcast(get_system_arrays, self.num_states,
                                          num_inputs, num_outputs)

        # Run impulse responses
        direct_vec_array = parallel.call_and_bcast(
            get_direct_impulse_response_array, A, B, self.num_steps)
        adjoint_vec_array = parallel.call_and_bcast(
            get_adjoint_impulse_response_array, A, C, self.num_steps,
            np.identity(self.num_states))

        # Save data to disk
        direct_vec_handles = [
            VecHandlePickle(self.direct_vec_path % i)
            for i in range(direct_vec_array.shape[1])
        ]
        adjoint_vec_handles = [
            VecHandlePickle(self.adjoint_vec_path % i)
            for i in range(adjoint_vec_array.shape[1])
        ]
        if parallel.is_rank_zero():
            for idx, handle in enumerate(direct_vec_handles):
                handle.put(direct_vec_array[:, idx])
            for idx, handle in enumerate(adjoint_vec_handles):
                handle.put(adjoint_vec_array[:, idx])

        parallel.barrier()
        return direct_vec_handles, adjoint_vec_handles
Example #5
0
    def test_assemble_Hankel(self):
        """ Tests Hankel arrays are symmetric given
        ``[CB CAB CA**P CA**(P+1)B ...]``."""
        rtol = 1e-10
        atol = 1e-12
        for num_inputs in [1, 3]:
            for num_outputs in [1, 2, 4]:
                for sample_interval in [1]:
                    num_time_steps = 50
                    num_states = 5
                    A, B, C = util.drss(num_states, num_inputs, num_outputs)
                    time_steps = make_time_steps(num_time_steps,
                                                 sample_interval)
                    Markovs = util.impulse(A, B, C, time_steps[-1] + 1)
                    Markovs = Markovs[time_steps]

                    if sample_interval == 2:
                        time_steps, Markovs = era.make_sampled_format(
                            time_steps, Markovs)

                    my_ERA = era.ERA(verbosity=0)
                    my_ERA._set_Markovs(Markovs)
                    my_ERA._assemble_Hankel()
                    H = my_ERA.Hankel_array
                    Hp = my_ERA.Hankel_array2

                    for row in range(my_ERA.mc):
                        for col in range(my_ERA.mo):
                            np.testing.assert_equal(
                                H[row * num_outputs:(row + 1) * num_outputs,
                                  col * num_inputs:(col + 1) * num_inputs],
                                H[col * num_outputs:(col + 1) * num_outputs,
                                  row * num_inputs:(row + 1) * num_inputs])
                            np.testing.assert_equal(
                                Hp[row * num_outputs:(row + 1) * num_outputs,
                                   col * num_inputs:(col + 1) * num_inputs],
                                Hp[col * num_outputs:(col + 1) * num_outputs,
                                   row * num_inputs:(row + 1) * num_inputs])
                            np.testing.assert_allclose(
                                H[row * num_outputs:(row + 1) * num_outputs,
                                  col * num_inputs:(col + 1) * num_inputs],
                                C.dot(
                                    np.linalg.matrix_power(
                                        A,
                                        time_steps[(row + col) * 2]).dot(B)),
                                rtol=rtol,
                                atol=atol)
                            np.testing.assert_allclose(
                                Hp[row * num_outputs:(row + 1) * num_outputs,
                                   col * num_inputs:(col + 1) * num_inputs],
                                C.dot(
                                    np.linalg.matrix_power(
                                        A, time_steps[(row + col) * 2 +
                                                      1]).dot(B)),
                                rtol=rtol,
                                atol=atol)
Example #6
0
    def test_assemble_Hankel(self):
        """ Tests Hankel arrays are symmetric given
        ``[CB CAB CA**P CA**(P+1)B ...]``."""
        rtol = 1e-10
        atol = 1e-12
        for num_inputs in [1,3]:
            for num_outputs in [1, 2, 4]:
                for sample_interval in [1]:
                    num_time_steps = 50
                    num_states = 5
                    A, B, C = util.drss(num_states, num_inputs, num_outputs)
                    time_steps = make_time_steps(
                        num_time_steps, sample_interval)
                    Markovs = util.impulse(A, B, C, time_steps[-1] + 1)
                    Markovs = Markovs[time_steps]

                    if sample_interval == 2:
                        time_steps, Markovs = era.make_sampled_format(
                            time_steps, Markovs)

                    my_ERA = era.ERA(verbosity=0)
                    my_ERA._set_Markovs(Markovs)
                    my_ERA._assemble_Hankel()
                    H = my_ERA.Hankel_array
                    Hp = my_ERA.Hankel_array2

                    for row in range(my_ERA.mc):
                        for col in range(my_ERA.mo):
                            np.testing.assert_equal(
                                H[row * num_outputs:(row + 1) * num_outputs,
                                  col * num_inputs:(col + 1) * num_inputs],
                                H[col * num_outputs:(col + 1) * num_outputs,
                                  row * num_inputs:(row + 1) * num_inputs])
                            np.testing.assert_equal(
                                Hp[row * num_outputs:(row + 1) * num_outputs,
                                   col * num_inputs:(col + 1) * num_inputs],
                                Hp[col * num_outputs:(col + 1) * num_outputs,
                                   row * num_inputs:(row + 1) * num_inputs])
                            np.testing.assert_allclose(
                                H[row * num_outputs:(row + 1) * num_outputs,
                                  col * num_inputs:(col + 1) * num_inputs],
                                C.dot(
                                    np.linalg.matrix_power(
                                        A, time_steps[(row + col) * 2]).dot(
                                            B)),
                                rtol=rtol, atol=atol)
                            np.testing.assert_allclose(
                                Hp[row * num_outputs:(row + 1) * num_outputs,
                                   col * num_inputs:(col + 1) * num_inputs],
                                C.dot(
                                    np.linalg.matrix_power(
                                        A, time_steps[(row + col) * 2 + 1]).dot(
                                            B)),
                                rtol=rtol, atol=atol)
Example #7
0
    def test_impulse(self):
        """Test impulse response of discrete system"""
        rtol = 1e-10
        atol = 1e-12
        for num_states in [1, 10]:
            for num_inputs in [1, 3]:
                for num_outputs in [1, 2, 3, 5]:
                    # Generate state-space system arrays
                    A, B, C = util.drss(num_states, num_inputs, num_outputs)

                    # Check that can give time_steps as argument
                    outputs = util.impulse(A, B, C)
                    num_time_steps = len(outputs)
                    outputs_true = np.zeros(
                        (num_time_steps, num_outputs, num_inputs))
                    for ti in range(num_time_steps):
                        outputs_true[ti] = C.dot(
                            np.linalg.matrix_power(A, ti).dot(B))
                    np.testing.assert_allclose(
                        outputs, outputs_true, rtol=rtol, atol=atol)

                    # Check can give num_time_steps as an argument
                    outputs = util.impulse(
                        A, B, C, num_time_steps=num_time_steps)
                    np.testing.assert_allclose(
                        outputs, outputs_true, rtol=rtol, atol=atol)
Example #8
0
    def test_load_impulse_outputs(self):
        """
        Test loading multiple signal files in [t sig1 sig2 ...] format.

        Creates signals, saves them, loads them, tests are equal to the
        originals.
        """
        signal_path = join(self.test_dir, 'file%03d.txt')
        for num_paths in [1, 4]:
            for num_signals in [1, 2, 4, 5]:
                for num_time_steps in [1, 10, 100]:
                    all_signals_true = np.random.random((num_paths,
                        num_time_steps, num_signals))
                    # Time steps need not be sequential
                    time_values_true = np.random.random(num_time_steps)

                    signal_paths = []
                    # Save signals to file
                    for path_num in range(num_paths):
                        signal_paths.append(signal_path%path_num)
                        data_to_save = np.concatenate( \
                          (time_values_true.reshape(len(time_values_true), 1),
                          all_signals_true[path_num]), axis=1)
                        util.save_array_text(data_to_save, signal_path%path_num)

                    time_values, all_signals = util.load_multiple_signals(
                        signal_paths)
                    np.testing.assert_allclose(all_signals, all_signals_true)
                    np.testing.assert_allclose(time_values, time_values_true)
Example #9
0
    def test_lin_combine(self):
        """ Test that linear combinations are correctly computed """
        # Set test tolerances
        rtol = 1e-10
        atol = 1e-12

        # Generate data
        num_states = 100
        num_vecs = 30
        num_modes = 10
        vecs_array = (
            np.random.random((num_states, num_vecs)) +
            1j * np.random.random((num_states, num_vecs)))
        coeffs_array = (
            np.random.random((num_vecs, num_modes)) +
            1j * np.random.random((num_vecs, num_modes)))
        modes_array_true = vecs_array.dot(coeffs_array)

        # Do computation using a vector space object.  Check an explicit
        # mode_indices argument, as well as a None value.
        vec_space = vspc.VectorSpaceArrays()
        mode_indices_trunc = np.random.randint(
            0, high=num_modes, size=num_modes // 2)
        for mode_idxs_arg, mode_idxs_vals in zip(
            [None, mode_indices_trunc],
            [range(num_modes), mode_indices_trunc]):
            modes_array = vec_space.lin_combine(
                vecs_array, coeffs_array, coeff_array_col_indices=mode_idxs_arg)
            np.testing.assert_allclose(
                modes_array, modes_array_true[:, mode_idxs_vals],
                rtol=rtol, atol=atol)
Example #10
0
    def setUp(self):
        # Specify output locations
        if not os.access('.', os.W_OK):
            raise RuntimeError('Cannot write to current directory')
        self.test_dir = 'files_POD_DELETE_ME'
        if not os.path.isdir(self.test_dir):
            parallel.call_from_rank_zero(os.mkdir, self.test_dir)
        self.vec_path = join(self.test_dir, 'vec_%03d.pkl')
        self.mode_path = join(self.test_dir, 'mode_%03d.pkl')

        # Specify data dimensions
        self.num_states = 30
        self.num_vecs = 10

        # Generate random data and write to disk using handles
        self.vecs_array = (
            parallel.call_and_bcast(np.random.random,
                                    (self.num_states, self.num_vecs)) +
            1j * parallel.call_and_bcast(np.random.random,
                                         (self.num_states, self.num_vecs)))
        self.vec_handles = [
            VecHandlePickle(self.vec_path % i) for i in range(self.num_vecs)
        ]
        for idx, hdl in enumerate(self.vec_handles):
            hdl.put(self.vecs_array[:, idx])

        parallel.barrier()
Example #11
0
    def setUp(self):
        # Specify output locations
        if not os.access('.', os.W_OK):
            raise RuntimeError('Cannot write to current directory')
        self.test_dir = 'files_POD_DELETE_ME'
        if not os.path.isdir(self.test_dir):
            parallel.call_from_rank_zero(os.mkdir, self.test_dir)
        self.vec_path = join(self.test_dir, 'vec_%03d.pkl')
        self.mode_path = join(self.test_dir, 'mode_%03d.pkl')

        # Specify data dimensions
        self.num_states = 30
        self.num_vecs = 10

        # Generate random data and write to disk using handles
        self.vecs_array = (
            parallel.call_and_bcast(
                np.random.random, (self.num_states, self.num_vecs)) +
            1j * parallel.call_and_bcast(
                np.random.random, (self.num_states, self.num_vecs)))
        self.vec_handles = [
            VecHandlePickle(self.vec_path % i) for i in range(self.num_vecs)]
        for idx, hdl in enumerate(self.vec_handles):
            hdl.put(self.vecs_array[:, idx])

        parallel.barrier()
Example #12
0
    def test_impulse(self):
        """Test impulse response of discrete system"""
        rtol = 1e-10
        atol = 1e-12
        for num_states in [1, 10]:
            for num_inputs in [1, 3]:
                for num_outputs in [1, 2, 3, 5]:
                    # Generate state-space system arrays
                    A, B, C = util.drss(num_states, num_inputs, num_outputs)

                    # Check that can give time_steps as argument
                    outputs = util.impulse(A, B, C)
                    num_time_steps = len(outputs)
                    outputs_true = np.zeros(
                        (num_time_steps, num_outputs, num_inputs))
                    for ti in range(num_time_steps):
                        outputs_true[ti] = C.dot(
                            np.linalg.matrix_power(A, ti).dot(B))
                    np.testing.assert_allclose(outputs,
                                               outputs_true,
                                               rtol=rtol,
                                               atol=atol)

                    # Check can give num_time_steps as an argument
                    outputs = util.impulse(A,
                                           B,
                                           C,
                                           num_time_steps=num_time_steps)
                    np.testing.assert_allclose(outputs,
                                               outputs_true,
                                               rtol=rtol,
                                               atol=atol)
    def test_lin_combine(self):
        """ Test that linear combinations are correctly computed """
        # Set test tolerances
        rtol = 1e-10
        atol = 1e-12

        # Generate data
        num_states = 100
        num_vecs = 30
        num_modes = 10
        vecs_array = (
            np.random.random((num_states, num_vecs)) +
            1j * np.random.random((num_states, num_vecs)))
        coeffs_array = (
            np.random.random((num_vecs, num_modes)) +
            1j * np.random.random((num_vecs, num_modes)))
        modes_array_true = vecs_array.dot(coeffs_array)

        # Do computation using a vector space object.  Check an explicit
        # mode_indices argument, as well as a None value.
        vec_space = vspc.VectorSpaceArrays()
        mode_indices_trunc = np.random.randint(
            0, high=num_modes, size=num_modes // 2)
        for mode_idxs_arg, mode_idxs_vals in zip(
            [None, mode_indices_trunc],
            [range(num_modes), mode_indices_trunc]):
            modes_array = vec_space.lin_combine(
                vecs_array, coeffs_array, coeff_array_col_indices=mode_idxs_arg)
            np.testing.assert_allclose(
                modes_array, modes_array_true[:, mode_idxs_vals],
                rtol=rtol, atol=atol)
Example #14
0
    def test_compute_proj_coeffs(self):
        rtol = 1e-10
        atol = 1e-12

        # Compute POD using modred.  (The properties defining a projection onto
        # POD modes require manipulations involving the correct decomposition
        # and modes, so we cannot isolate the mode computation from those
        # computations.)
        POD = pod.PODHandles(inner_product=np.vdot, verbosity=0)
        POD.compute_decomp(self.vec_handles)
        mode_idxs = range(POD.eigvals.size)
        mode_handles = [VecHandlePickle(self.mode_path % i) for i in mode_idxs]
        POD.compute_modes(mode_idxs,
                          mode_handles,
                          vec_handles=self.vec_handles)

        # Compute true projection coefficients by computing the inner products
        # between modes and snapshots.
        proj_coeffs_true = POD.vec_space.compute_inner_product_array(
            mode_handles, self.vec_handles)

        # Compute projection coefficients using POD object, which avoids
        # actually manipulating handles and computing their inner products,
        # instead using elements of the decomposition for a more efficient
        # computations.
        proj_coeffs = POD.compute_proj_coeffs()

        # Test values
        np.testing.assert_allclose(proj_coeffs,
                                   proj_coeffs_true,
                                   rtol=rtol,
                                   atol=atol)
Example #15
0
    def test_load_impulse_outputs(self):
        """
        Test loading multiple signal files in [t sig1 sig2 ...] format.

        Creates signals, saves them, loads them, tests are equal to the
        originals.
        """
        signal_path = join(self.test_dir, 'file%03d.txt')
        for num_paths in [1, 4]:
            for num_signals in [1, 2, 4, 5]:
                for num_time_steps in [1, 10, 100]:
                    all_signals_true = np.random.random(
                        (num_paths, num_time_steps, num_signals))
                    # Time steps need not be sequential
                    time_values_true = np.random.random(num_time_steps)

                    signal_paths = []
                    # Save signals to file
                    for path_num in range(num_paths):
                        signal_paths.append(signal_path % path_num)
                        data_to_save = np.concatenate( \
                          (time_values_true.reshape(len(time_values_true), 1),
                          all_signals_true[path_num]), axis=1)
                        util.save_array_text(data_to_save,
                                             signal_path % path_num)

                    time_values, all_signals = util.load_multiple_signals(
                        signal_paths)
                    np.testing.assert_allclose(all_signals, all_signals_true)
                    np.testing.assert_allclose(time_values, time_values_true)
Example #16
0
    def test_compute_proj_coeffs(self):
        rtol = 1e-10
        atol = 1e-12

        # Compute POD using modred.  (The properties defining a projection onto
        # POD modes require manipulations involving the correct decomposition
        # and modes, so we cannot isolate the mode computation from those
        # computations.)
        POD = pod.PODHandles(np.vdot, verbosity=0)
        POD.compute_decomp(self.vec_handles)
        mode_idxs = range(POD.eigvals.size)
        mode_handles = [VecHandlePickle(self.mode_path % i) for i in mode_idxs]
        POD.compute_modes(mode_idxs, mode_handles, vec_handles=self.vec_handles)

        # Compute true projection coefficients by computing the inner products
        # between modes and snapshots.
        proj_coeffs_true = POD.vec_space.compute_inner_product_array(
            mode_handles, self.vec_handles)

        # Compute projection coefficients using POD object, which avoids
        # actually manipulating handles and computing their inner products,
        # instead using elements of the decomposition for a more efficient
        # computations.
        proj_coeffs = POD.compute_proj_coeffs()

        # Test values
        np.testing.assert_allclose(
            proj_coeffs, proj_coeffs_true, rtol=rtol, atol=atol)
Example #17
0
 def test_derivs(self):
     """Test can take derivs"""
     dt = 0.1
     true_derivs = []
     num_vecs = len(self.basis_vec_handles)
     for i in range(num_vecs):
         true_derivs.append((
             self.A_on_basis_vec_handles[i].get() -
             self.basis_vec_handles[i].get()).squeeze() / dt)
     deriv_handles = [
         VecHandlePickle(join(self.test_dir, 'deriv_test%d' % i))
         for i in range(num_vecs)]
     lgp.compute_derivs_handles(
         self.basis_vec_handles, self.A_on_basis_vec_handles,
         deriv_handles, dt)
     derivs_loaded = [v.get() for v in deriv_handles]
     derivs_loaded = list(map(np.squeeze, derivs_loaded))
     list(map(np.testing.assert_allclose, derivs_loaded, true_derivs))
Example #18
0
def get_direct_impulse_response_array(A, B, num_steps):
    num_states, num_inputs = B.shape
    direct_vecs = np.zeros((num_states, num_steps * num_inputs), dtype=A.dtype)
    A_powers = np.identity(num_states)
    for idx in range(num_steps):
        direct_vecs[:, idx * num_inputs:(idx + 1) * num_inputs] =\
            A_powers.dot(B)
        A_powers = A_powers.dot(A)
    return direct_vecs
Example #19
0
def get_direct_impulse_response_array(A, B, num_steps):
    num_states, num_inputs = B.shape
    direct_vecs = np.zeros((num_states, num_steps * num_inputs), dtype=A.dtype)
    A_powers = np.identity(num_states)
    for idx in range(num_steps):
        direct_vecs[:, idx * num_inputs:(idx + 1) * num_inputs] =\
            A_powers.dot(B)
        A_powers = A_powers.dot(A)
    return direct_vecs
Example #20
0
    def test_Hankel_chunks(self):
        """Test forming Hankel array using chunks."""
        chunk_num_rows = 2
        chunk_num_cols = 2
        chunk_shape = (chunk_num_rows, chunk_num_cols)
        for num_row_chunks in [1, 4, 6]:
            for num_col_chunks in [1, 3, 6]:

                # Generate simple values that make it easy to see the array
                # structure
                first_col_chunks = [
                    np.ones(chunk_shape) * (i + 1)
                    for i in range(num_row_chunks)
                ]
                last_row_chunks = [
                    np.ones(chunk_shape) * (j + 1) * 10
                    for j in range(num_col_chunks)
                ]
                last_row_chunks[0] = first_col_chunks[-1]

                # Fill in Hankel array chunk by chunk
                Hankel_true = np.zeros((num_row_chunks * chunk_shape[0],
                                        num_col_chunks * chunk_shape[1]))
                for i in range(num_row_chunks):
                    for j in range(num_col_chunks):

                        # Upper left triangle of values
                        if i + j < num_row_chunks:
                            Hankel_true[
                                i * chunk_num_rows:(i + 1) * chunk_num_rows,
                                j * chunk_num_cols:(j + 1) * chunk_num_cols] =\
                                first_col_chunks[i + j]

                        # Lower right triangle of values
                        else:
                            Hankel_true[
                                i * chunk_num_rows:(i + 1) * chunk_num_rows,
                                j * chunk_num_cols:(j + 1) * chunk_num_cols] =\
                                last_row_chunks[i + j - num_row_chunks + 1]

                # Compute Hankel array using util and test
                Hankel_test = util.Hankel_chunks(
                    first_col_chunks, last_row_chunks=last_row_chunks)
                np.testing.assert_equal(Hankel_test, Hankel_true)
Example #21
0
 def test_derivs(self):
     """Test can take derivs"""
     dt = 0.1
     true_derivs = []
     num_vecs = len(self.basis_vec_handles)
     for i in range(num_vecs):
         true_derivs.append(
             (self.A_on_basis_vec_handles[i].get() -
              self.basis_vec_handles[i].get()).squeeze() / dt)
     deriv_handles = [
         VecHandlePickle(join(self.test_dir, 'deriv_test%d' % i))
         for i in range(num_vecs)
     ]
     lgp.compute_derivs_handles(self.basis_vec_handles,
                                self.A_on_basis_vec_handles, deriv_handles,
                                dt)
     derivs_loaded = [v.get() for v in deriv_handles]
     derivs_loaded = list(map(np.squeeze, derivs_loaded))
     list(map(np.testing.assert_allclose, derivs_loaded, true_derivs))
Example #22
0
 def test_tutorial_examples(self):
     """Runs all tutorial examples. If run without errors, passes test"""
     example_script = 'tutorial_ex%d.py'
     for example_num in range(1, 7):
         # Example 3 isn't meant to work in parallel
         if not (parallel.is_distributed() and example_num != 3):
             #printing(False)
             parallel.barrier()
             mr.run_script(join(examples_dir, example_script % example_num))
             parallel.barrier()
Example #23
0
    def test_Hankel_chunks(self):
        """Test forming Hankel array using chunks."""
        chunk_num_rows = 2
        chunk_num_cols = 2
        chunk_shape = (chunk_num_rows, chunk_num_cols)
        for num_row_chunks in [1, 4, 6]:
            for num_col_chunks in [1, 3, 6]:

                # Generate simple values that make it easy to see the array
                # structure
                first_col_chunks = [
                    np.ones(chunk_shape) * (i + 1)
                    for i in range(num_row_chunks)]
                last_row_chunks = [
                    np.ones(chunk_shape) * (j + 1) * 10
                    for j in range(num_col_chunks)]
                last_row_chunks[0] = first_col_chunks[-1]

                # Fill in Hankel array chunk by chunk
                Hankel_true = np.zeros((
                    num_row_chunks * chunk_shape[0],
                    num_col_chunks * chunk_shape[1]))
                for i in range(num_row_chunks):
                    for j in range(num_col_chunks):

                        # Upper left triangle of values
                        if i + j < num_row_chunks:
                            Hankel_true[
                                i * chunk_num_rows:(i + 1) * chunk_num_rows,
                                j * chunk_num_cols:(j + 1) * chunk_num_cols] =\
                                first_col_chunks[i + j]

                        # Lower right triangle of values
                        else:
                            Hankel_true[
                                i * chunk_num_rows:(i + 1) * chunk_num_rows,
                                j * chunk_num_cols:(j + 1) * chunk_num_cols] =\
                                last_row_chunks[i + j - num_row_chunks + 1]

                # Compute Hankel array using util and test
                Hankel_test = util.Hankel_chunks(
                    first_col_chunks, last_row_chunks=last_row_chunks)
                np.testing.assert_equal(Hankel_test, Hankel_true)
Example #24
0
def get_adjoint_impulse_response_array(A, C, num_steps, weights_array):
    num_outputs, num_states = C.shape
    A_adjoint = np.linalg.inv(weights_array).dot(A.conj().T.dot(weights_array))
    C_adjoint = np.linalg.inv(weights_array).dot(C.conj().T)
    adjoint_vecs = np.zeros((num_states, num_steps * num_outputs), dtype=A.dtype)
    A_adjoint_powers = np.identity(num_states)
    for idx in range(num_steps):
        adjoint_vecs[:, (idx * num_outputs):(idx + 1) * num_outputs] =\
            A_adjoint_powers.dot(C_adjoint)
        A_adjoint_powers = A_adjoint_powers.dot(A_adjoint)
    return adjoint_vecs
Example #25
0
    def test_compute_inner_product_array_types(self):
        num_row_vecs = 4
        num_col_vecs = 6
        num_states = 7

        row_vec_path = join(self.test_dir, 'row_vec_%03d.pkl')
        col_vec_path = join(self.test_dir, 'col_vec_%03d.pkl')

        # Check complex and real data
        for is_complex in [True, False]:

            # Generate data
            row_vec_array = np.random.random((num_states, num_row_vecs))
            col_vec_array = np.random.random((num_states, num_col_vecs))
            if is_complex:
                row_vec_array = row_vec_array * (
                    1j * np.random.random((num_states, num_row_vecs)))
                col_vec_array = col_vec_array * (
                    1j * np.random.random((num_states, num_col_vecs)))

            # Generate handles and save to file
            row_vec_paths = [row_vec_path % i for i in range(num_row_vecs)]
            col_vec_paths = [col_vec_path % i for i in range(num_col_vecs)]
            row_vec_handles = [
                VecHandlePickle(path) for path in row_vec_paths]
            col_vec_handles = [
                VecHandlePickle(path) for path in col_vec_paths]
            for idx, handle in enumerate(row_vec_handles):
                handle.put(row_vec_array[:, idx])
            for idx, handle in enumerate(col_vec_handles):
                handle.put(col_vec_array[:, idx])

            # Compute inner product array and check type
            inner_product_array = self.vec_space.compute_inner_product_array(
                row_vec_handles, col_vec_handles)
            symm_inner_product_array =\
                self.vec_space.compute_symm_inner_product_array(
                    row_vec_handles)
            self.assertEqual(inner_product_array.dtype, row_vec_array.dtype)
            self.assertEqual(
                symm_inner_product_array.dtype, row_vec_array.dtype)
    def test_compute_inner_product_array_types(self):
        num_row_vecs = 4
        num_col_vecs = 6
        num_states = 7

        row_vec_path = join(self.test_dir, 'row_vec_%03d.pkl')
        col_vec_path = join(self.test_dir, 'col_vec_%03d.pkl')

        # Check complex and real data
        for is_complex in [True, False]:

            # Generate data
            row_vec_array = np.random.random((num_states, num_row_vecs))
            col_vec_array = np.random.random((num_states, num_col_vecs))
            if is_complex:
                row_vec_array = row_vec_array * (
                    1j * np.random.random((num_states, num_row_vecs)))
                col_vec_array = col_vec_array * (
                    1j * np.random.random((num_states, num_col_vecs)))

            # Generate handles and save to file
            row_vec_paths = [row_vec_path % i for i in range(num_row_vecs)]
            col_vec_paths = [col_vec_path % i for i in range(num_col_vecs)]
            row_vec_handles = [
                VecHandlePickle(path) for path in row_vec_paths]
            col_vec_handles = [
                VecHandlePickle(path) for path in col_vec_paths]
            for idx, handle in enumerate(row_vec_handles):
                handle.put(row_vec_array[:, idx])
            for idx, handle in enumerate(col_vec_handles):
                handle.put(col_vec_array[:, idx])

            # Compute inner product array and check type
            inner_product_array = self.vec_space.compute_inner_product_array(
                row_vec_handles, col_vec_handles)
            symm_inner_product_array =\
                self.vec_space.compute_symm_inner_product_array(
                    row_vec_handles)
            self.assertEqual(inner_product_array.dtype, row_vec_array.dtype)
            self.assertEqual(
                symm_inner_product_array.dtype, row_vec_array.dtype)
Example #27
0
def get_adjoint_impulse_response_array(A, C, num_steps, weights_array):
    num_outputs, num_states = C.shape
    A_adjoint = np.linalg.inv(weights_array).dot(A.conj().T.dot(weights_array))
    C_adjoint = np.linalg.inv(weights_array).dot(C.conj().T)
    adjoint_vecs = np.zeros((num_states, num_steps * num_outputs),
                            dtype=A.dtype)
    A_adjoint_powers = np.identity(num_states)
    for idx in range(num_steps):
        adjoint_vecs[:, (idx * num_outputs):(idx + 1) * num_outputs] =\
            A_adjoint_powers.dot(C_adjoint)
        A_adjoint_powers = A_adjoint_powers.dot(A_adjoint)
    return adjoint_vecs
Example #28
0
    def test_all(self):
        # Set test tolerances.  Separate, more relaxed tolerances are required
        # for testing the BPOD modes, since that test requires "squaring" the
        # gramians and thus involves more ill-conditioned arrays.
        rtol = 1e-8
        atol = 1e-10
        rtol_sqr = 1e-8
        atol_sqr = 1e-8

        # Set tolerances for SVD step of BPOD.  This is necessary to avoid
        # dealing with very uncontrollable/unobservable states, which can cause
        # the tests to fail.
        rtol_svd = 1e-6
        atol_svd = 1e-12

        # Generate weights to test different inner products.  Keep most of the
        # weights close to one, to avoid overly weighting certain states over
        # others.  This can dramatically affect the rate at which the tests
        # pass.
        weights_1D = np.random.random(self.num_states)
        weights_2D = np.identity(self.num_states, dtype=np.complex)
        weights_2D[0, 0] = 2.
        weights_2D[2, 1] = 0.3j
        weights_2D[1, 2] = weights_2D[2, 1].conj()
        weights_list = [None, weights_1D, weights_2D]
        weights_array_list = [
            np.identity(self.num_states), np.diag(weights_1D), weights_2D]

        # Check different system sizes.  Make sure to test a single input/output
        # in addition to multiple inputs/outputs.  Also allow for the number of
        # inputs/outputs to exceed the number of states.
        for num_inputs in [1, np.random.randint(2, high=self.num_states + 2)]:

            for num_outputs in [
                1, np.random.randint(2, high=self.num_states + 2)]:

                # Get state space system
                A, B, C = get_system_arrays(
                    self.num_states, num_inputs, num_outputs)

                # Compute direct impulse response
                direct_vecs_array = get_direct_impulse_response_array(
                    A, B, self.num_steps)

                # Loop through different inner product weights
                for weights, weights_array in zip(
                    weights_list, weights_array_list):

                    # Define inner product based on weights
                    IP = VectorSpaceArrays(
                        weights=weights).compute_inner_product_array

                    # Compute adjoint impulse response
                    adjoint_vecs_array = get_adjoint_impulse_response_array(
                        A, C, self.num_steps, weights_array)

                    # Compute BPOD using modred.  Use absolute tolerance to
                    # avoid Hankel singular values that approach numerical
                    # precision.  Use relative tolerance to avoid Hankel
                    # singular values which may correspond to very
                    # uncontrollable/unobservable states.  It is ok to use a
                    # more relaxed tolerance here than in the actual test/assert
                    # statements, as here we are saying it is ok to ignore
                    # highly uncontrollable/unobservable states, rather than
                    # allowing loose tolerances in the comparison of two
                    # numbers.  Furthermore, it is likely that in actual use,
                    # users would want to ignore relatively small Hankel
                    # singular values anyway, as that is the point of doing a
                    # balancing transformation.
                    BPOD_res = bpod.compute_BPOD_arrays(
                        direct_vecs_array, adjoint_vecs_array,
                        num_inputs=num_inputs, num_outputs=num_outputs,
                        inner_product_weights=weights,
                        rtol=rtol_svd, atol=atol_svd)

                    # Check Hankel array values.  These are computed fast
                    # internally by only computing the first column and last row
                    # of chunks.  Here, simply take all the inner products.
                    Hankel_array_slow = IP(
                        adjoint_vecs_array, direct_vecs_array)
                    np.testing.assert_allclose(
                        BPOD_res.Hankel_array, Hankel_array_slow,
                        rtol=rtol, atol=atol)

                    # Check properties of SVD of Hankel array.  Since the SVD
                    # may be truncated, instead of checking orthogonality and
                    # reconstruction of the Hankel array, check that the left
                    # and right singular vectors satisfy eigendecomposition
                    # properties with respect to the Hankel array.  Since this
                    # involves "squaring" the Hankel array, it requires more
                    # relaxed test tolerances.
                    np.testing.assert_allclose(
                        BPOD_res.Hankel_array.dot(
                            BPOD_res.Hankel_array.conj().T.dot(
                                BPOD_res.L_sing_vecs)),
                        BPOD_res.L_sing_vecs.dot(
                            np.diag(BPOD_res.sing_vals ** 2.)),
                        rtol=rtol_sqr, atol=atol_sqr)
                    np.testing.assert_allclose(
                        BPOD_res.Hankel_array.conj().T.dot(
                            BPOD_res.Hankel_array.dot(
                                BPOD_res.R_sing_vecs)),
                        BPOD_res.R_sing_vecs.dot(
                            np.diag(BPOD_res.sing_vals ** 2.)),
                        rtol=rtol_sqr, atol=atol_sqr)

                    # Check that the modes diagonalize the gramians.  This test
                    # requires looser tolerances than the other tests, likely
                    # due to the "squaring" of the arrays in computing the
                    # gramians.
                    np.testing.assert_allclose(
                        IP(BPOD_res.adjoint_modes, direct_vecs_array).dot(
                            IP(direct_vecs_array, BPOD_res.adjoint_modes)),
                        np.diag(BPOD_res.sing_vals),
                        rtol=rtol_sqr, atol=atol_sqr)
                    np.testing.assert_allclose(
                        IP(BPOD_res.direct_modes, adjoint_vecs_array).dot(
                            IP(adjoint_vecs_array, BPOD_res.direct_modes)),
                        np.diag(BPOD_res.sing_vals),
                        rtol=rtol_sqr, atol=atol_sqr)

                    # Check the value of the projection coefficients against a
                    # projection onto the adjoint and direct modes,
                    # respectively.
                    np.testing.assert_allclose(
                        BPOD_res.direct_proj_coeffs,
                        IP(BPOD_res.adjoint_modes, direct_vecs_array),
                        rtol=rtol, atol=atol)
                    np.testing.assert_allclose(
                        BPOD_res.adjoint_proj_coeffs,
                        IP(BPOD_res.direct_modes, adjoint_vecs_array),
                        rtol=rtol, atol=atol)

                    # Check that if mode indices are passed in, the correct
                    # modes are returned.  Test both an explicit selection of
                    # mode indices and a None argument.
                    mode_indices_trunc = np.unique(np.random.randint(
                        0, high=BPOD_res.sing_vals.size,
                        size=(BPOD_res.sing_vals.size // 2)))
                    for mode_indices_arg, mode_indices_vals in zip(
                        [None, mode_indices_trunc],
                        [range(BPOD_res.sing_vals.size), mode_indices_trunc]):
                        BPOD_res_sliced = bpod.compute_BPOD_arrays(
                            direct_vecs_array, adjoint_vecs_array,
                            direct_mode_indices=mode_indices_arg,
                            adjoint_mode_indices=mode_indices_arg,
                            num_inputs=num_inputs, num_outputs=num_outputs,
                            inner_product_weights=weights,
                            rtol=rtol_svd, atol=atol_svd)
                        np.testing.assert_allclose(
                            BPOD_res_sliced.direct_modes,
                            BPOD_res.direct_modes[:, mode_indices_vals],
                            rtol=rtol, atol=atol)
                        np.testing.assert_allclose(
                            BPOD_res_sliced.adjoint_modes,
                            BPOD_res.adjoint_modes[:, mode_indices_vals],
                            rtol=rtol, atol=atol)
Example #29
0
    def test_compute_proj_coeffs(self):
        # Set test tolerances.  Use a slightly more relaxed absolute tolerance
        # here because the projection test uses modes that may correspond to
        # smaller Hankel singular values (i.e., less controllable/unobservable
        # states).  Those mode pairs are not as close to biorthogonal, so a more
        # relaxed tolerance is required.
        rtol = 1e-8
        atol = 1e-8

        # Test a single input/output as well as multiple inputs/outputs.  Allow
        # for more inputs/outputs than states.  (This is determined in setUp()).
        for num_inputs in self.num_inputs_list:
            for num_outputs in self.num_outputs_list:

                # Get impulse response data
                direct_vec_handles, adjoint_vec_handles =\
                self._helper_get_impulse_response_handles(
                    num_inputs, num_outputs)

                # Create BPOD object and compute decomposition, modes.  (The
                # properties defining a projection onto BPOD modes require
                # manipulations involving the correct decomposition and modes,
                # so we cannot isolate the projection step from those
                # computations.)  Use relative tolerance to avoid Hankel
                # singular values which may correspond to very
                # uncontrollable/unobservable states.  It is ok to use a
                # more relaxed tolerance here than in the actual test/assert
                # statements, as here we are saying it is ok to ignore
                # highly uncontrollable/unobservable states, rather than
                # allowing loose tolerances in the comparison of two
                # numbers.  Furthermore, it is likely that in actual use,
                # users would want to ignore relatively small Hankel
                # singular values anyway, as that is the point of doing a
                # balancing transformation.
                BPOD = bpod.BPODHandles(np.vdot, verbosity=0)
                BPOD.compute_decomp(
                    direct_vec_handles, adjoint_vec_handles,
                    num_inputs=num_inputs, num_outputs=num_outputs,
                    rtol=1e-6, atol=1e-12)
                mode_idxs = range(BPOD.sing_vals.size)
                direct_mode_handles = [
                    VecHandlePickle(self.direct_mode_path % i)
                    for i in mode_idxs]
                adjoint_mode_handles = [
                    VecHandlePickle(self.adjoint_mode_path % i)
                    for i in mode_idxs]
                BPOD.compute_direct_modes(
                    mode_idxs, direct_mode_handles,
                    direct_vec_handles=direct_vec_handles)
                BPOD.compute_adjoint_modes(
                    mode_idxs, adjoint_mode_handles,
                    adjoint_vec_handles=adjoint_vec_handles)

                # Compute true projection coefficients by computing the inner
                # products between modes and snapshots.
                direct_proj_coeffs_true =\
                BPOD.vec_space.compute_inner_product_array(
                    adjoint_mode_handles, direct_vec_handles)
                adjoint_proj_coeffs_true =\
                BPOD.vec_space.compute_inner_product_array(
                    direct_mode_handles, adjoint_vec_handles)

                # Compute projection coefficients using BPOD object, which
                # avoids actually manipulating handles and computing inner
                # products, instead using elements of the decomposition for a
                # more efficient computation.
                direct_proj_coeffs = BPOD.compute_direct_proj_coeffs()
                adjoint_proj_coeffs = BPOD.compute_adjoint_proj_coeffs()

                # Test values
                np.testing.assert_allclose(
                    direct_proj_coeffs, direct_proj_coeffs_true,
                    rtol=rtol, atol=atol)
                np.testing.assert_allclose(
                    adjoint_proj_coeffs, adjoint_proj_coeffs_true,
                    rtol=rtol, atol=atol)
Example #30
0
    def test_lin_combine(self):
        # Set test tolerances
        rtol = 1e-10
        atol = 1e-12

        # Setup
        mode_path = join(self.test_dir, 'mode_%03d.pkl')
        vec_path = join(self.test_dir, 'vec_%03d.pkl')

        # Test cases where number of modes:
        #   less, equal, more than num_states
        #   less, equal, more than num_vecs
        #   less, equal, more than total_num_vecs_in_mem
        # Also check the case of passing a None value to the mode_indices
        # argument.
        num_states = 20
        num_vecs_list = [1, 15, 40]
        num_modes_list = [
            None, 1, 8, 10, 20, 25, 45,
            int(np.ceil(self.total_num_vecs_in_mem / 2.)),
            self.total_num_vecs_in_mem, self.total_num_vecs_in_mem * 2]

        # Check for correct computations
        for num_vecs in num_vecs_list:
            for num_modes in num_modes_list:
                for squeeze in [True, False]:

                    # Generate data and then broadcast to all procs
                    vec_handles = [
                        VecHandlePickle(vec_path % i)
                        for i in range(num_vecs)]
                    vec_array, coeff_array, true_modes =\
                        parallel.call_and_bcast(
                            self.generate_vecs_modes, num_states, num_vecs,
                            num_modes=num_modes, squeeze=squeeze)
                    if parallel.is_rank_zero():
                        for vec_index, vec_handle in enumerate(vec_handles):
                            vec_handle.put(vec_array[:, vec_index])
                    parallel.barrier()

                    # Choose which modes to compute
                    if num_modes is None:
                        mode_idxs_arg = None
                        mode_idxs_vals = range(true_modes.shape[1])
                    elif num_modes == 1:
                        mode_idxs_arg = 0
                        mode_idxs_vals = [0]
                    else:
                        mode_idxs_arg = np.unique(
                            parallel.call_and_bcast(
                                np.random.randint, 0, high=num_modes,
                                size=num_modes // 2))
                        mode_idxs_vals = mode_idxs_arg
                    mode_handles = [
                        VecHandlePickle(mode_path % mode_num)
                        for mode_num in mode_idxs_vals]

                    # Saves modes to files
                    self.vec_space.lin_combine(
                        mode_handles, vec_handles, coeff_array,
                        coeff_array_col_indices=mode_idxs_arg)

                    # Test modes one by one
                    for mode_idx in mode_idxs_vals:
                        computed_mode = VecHandlePickle(
                            mode_path % mode_idx).get()
                        np.testing.assert_allclose(
                            computed_mode, true_modes[:, mode_idx],
                            rtol=rtol, atol=atol)
                    parallel.barrier()

                parallel.barrier()

            parallel.barrier()

        # Test that errors are caught for mismatched dimensions
        mode_handles = [
            VecHandlePickle(mode_path % i) for i in range(10)]
        vec_handles = [
            VecHandlePickle(vec_path % i) for i in range(15)]
        coeffs_array_too_short = np.zeros(
            (len(vec_handles) - 1, len(mode_handles)))
        coeffs_array_too_fat = np.zeros(
            (len(vec_handles), len(mode_handles) + 1))
        index_list_too_long = range(len(mode_handles) + 1)
        self.assertRaises(
            ValueError, self.vec_space.lin_combine, mode_handles, vec_handles,
            coeffs_array_too_short)
        self.assertRaises(
            ValueError, self.vec_space.lin_combine, mode_handles, vec_handles,
            coeffs_array_too_fat)
Example #31
0
    def test_compute_inner_product_arrays(self):
        """Test computation of array of inner products."""
        rtol = 1e-10
        atol = 1e-12

        num_row_vecs_list = [
            1,
            int(round(self.total_num_vecs_in_mem / 2.)),
            self.total_num_vecs_in_mem,
            self.total_num_vecs_in_mem * 2,
            parallel.get_num_procs() + 1]
        num_col_vecs_list = num_row_vecs_list
        num_states = 6

        row_vec_path = join(self.test_dir, 'row_vec_%03d.pkl')
        col_vec_path = join(self.test_dir, 'col_vec_%03d.pkl')

        for num_row_vecs in num_row_vecs_list:
            for num_col_vecs in num_col_vecs_list:

                # Generate vecs
                parallel.barrier()
                row_vec_array = (
                    parallel.call_and_bcast(
                        np.random.random, (num_states, num_row_vecs))
                    + 1j * parallel.call_and_bcast(
                        np.random.random, (num_states, num_row_vecs)))
                col_vec_array = (
                    parallel.call_and_bcast(
                        np.random.random, (num_states, num_col_vecs))
                    + 1j * parallel.call_and_bcast(
                        np.random.random, (num_states, num_col_vecs)))
                row_vec_handles = [
                    VecHandlePickle(row_vec_path % i)
                    for i in range(num_row_vecs)]
                col_vec_handles = [
                    VecHandlePickle(col_vec_path % i)
                    for i in range(num_col_vecs)]

                # Save vecs
                if parallel.is_rank_zero():
                    for i, h in enumerate(row_vec_handles):
                        h.put(row_vec_array[:, i])
                    for i, h in enumerate(col_vec_handles):
                        h.put(col_vec_array[:, i])
                parallel.barrier()

                # If number of rows/cols is 1, check case of passing a handle
                if len(row_vec_handles) == 1:
                    row_vec_handles = row_vec_handles[0]
                if len(col_vec_handles) == 1:
                    col_vec_handles = col_vec_handles[0]

                # Test ip computation.
                product_true = np.dot(row_vec_array.conj().T, col_vec_array)
                product_computed = self.vec_space.compute_inner_product_array(
                    row_vec_handles, col_vec_handles)
                np.testing.assert_allclose(
                    product_computed, product_true, rtol=rtol, atol=atol)

                # Test symm ip computation
                product_true = np.dot(row_vec_array.conj().T, row_vec_array)
                product_computed =\
                    self.vec_space.compute_symm_inner_product_array(
                        row_vec_handles)
                np.testing.assert_allclose(
                    product_computed, product_true, rtol=rtol, atol=atol)
Example #32
0
    def test_OKID(self):
        rtol = 1e-8
        atol = 1e-10

        for case in ['SISO', 'SIMO', 'MISO', 'MIMO']:
            inputs = util.load_array_text(
                join(join(self.test_dir, case), 'inputs.txt'))
            outputs = util.load_array_text(
                join(join(self.test_dir, case), 'outputs.txt'))
            (num_inputs, nt) = inputs.shape
            (num_outputs, nt2) = outputs.shape

            assert(nt2 == nt)

            Markovs_true = np.zeros((nt, num_outputs, num_inputs))

            tmp = util.load_array_text(
                join(join(self.test_dir, case), 'Markovs_Matlab_output1.txt'))
            tmp = tmp.reshape((num_inputs, -1))
            num_Markovs_OKID = tmp.shape[1]
            Markovs_Matlab = np.zeros(
                (num_Markovs_OKID, num_outputs, num_inputs))

            for i_out in range(num_outputs):
                data = util.load_array_text(
                    join(join( self.test_dir, case),
                    'Markovs_Matlab_output%d.txt' % (i_out + 1)))
                if num_inputs > 1:
                    data = np.swapaxes(data, 0, 1)
                Markovs_Matlab[:, i_out, :] = data
                data = util.load_array_text(join(
                    join(self.test_dir, case),
                    'Markovs_true_output%d.txt' % (i_out + 1)))
                if num_inputs > 1:
                    data = np.swapaxes(data, 0, 1)
                Markovs_true[:,i_out,:] = data

            Markovs_python = OKID(inputs, outputs, num_Markovs_OKID)

            if plot:
                plt.figure(figsize=(14,10))
                for output_num in range(num_outputs):
                    for input_num in range(num_inputs):
                        plt.subplot(num_outputs, num_inputs,
                            output_num*(num_inputs) + input_num + 1)
                        plt.hold(True)
                        plt.plot(Markovs_true[:,output_num,input_num],'k*-')
                        plt.plot(Markovs_Matlab[:,output_num,input_num],'b--')
                        plt.plot(Markovs_python[:,output_num,input_num],'r.')
                        plt.legend(['True', 'Matlab OKID', 'Python OKID'])
                        plt.title('Input %d to output %d'%(input_num+1,
                            output_num+1))
                plt.show()

            np.testing.assert_allclose(
                Markovs_python.squeeze(), Markovs_Matlab.squeeze(),
                rtol=rtol, atol=atol)
            np.testing.assert_allclose(
                Markovs_python.squeeze(),
                Markovs_true[:num_Markovs_OKID].squeeze(),
                rtol=rtol, atol=atol)
Example #33
0
    def test_all(self):
        # Set test tolerances.  Separate, more relaxed tolerances are required
        # for testing the BPOD modes, since that test requires "squaring" the
        # gramians and thus involves more ill-conditioned arrays.
        rtol = 1e-8
        atol = 1e-10
        rtol_sqr = 1e-8
        atol_sqr = 1e-8

        # Set tolerances for SVD step of BPOD.  This is necessary to avoid
        # dealing with very uncontrollable/unobservable states, which can cause
        # the tests to fail.
        rtol_svd = 1e-6
        atol_svd = 1e-12

        # Generate weights to test different inner products.  Keep most of the
        # weights close to one, to avoid overly weighting certain states over
        # others.  This can dramatically affect the rate at which the tests
        # pass.
        weights_1D = np.random.random(self.num_states)
        weights_2D = np.identity(self.num_states, dtype=np.complex)
        weights_2D[0, 0] = 2.
        weights_2D[2, 1] = 0.3j
        weights_2D[1, 2] = weights_2D[2, 1].conj()
        weights_list = [None, weights_1D, weights_2D]
        weights_array_list = [
            np.identity(self.num_states),
            np.diag(weights_1D), weights_2D
        ]

        # Check different system sizes.  Make sure to test a single input/output
        # in addition to multiple inputs/outputs.  Also allow for the number of
        # inputs/outputs to exceed the number of states.
        for num_inputs in [1, np.random.randint(2, high=self.num_states + 2)]:

            for num_outputs in [
                    1, np.random.randint(2, high=self.num_states + 2)
            ]:

                # Get state space system
                A, B, C = get_system_arrays(self.num_states, num_inputs,
                                            num_outputs)

                # Compute direct impulse response
                direct_vecs_array = get_direct_impulse_response_array(
                    A, B, self.num_steps)

                # Loop through different inner product weights
                for weights, weights_array in zip(weights_list,
                                                  weights_array_list):

                    # Define inner product based on weights
                    IP = VectorSpaceArrays(
                        weights=weights).compute_inner_product_array

                    # Compute adjoint impulse response
                    adjoint_vecs_array = get_adjoint_impulse_response_array(
                        A, C, self.num_steps, weights_array)

                    # Compute BPOD using modred.  Use absolute tolerance to
                    # avoid Hankel singular values that approach numerical
                    # precision.  Use relative tolerance to avoid Hankel
                    # singular values which may correspond to very
                    # uncontrollable/unobservable states.  It is ok to use a
                    # more relaxed tolerance here than in the actual test/assert
                    # statements, as here we are saying it is ok to ignore
                    # highly uncontrollable/unobservable states, rather than
                    # allowing loose tolerances in the comparison of two
                    # numbers.  Furthermore, it is likely that in actual use,
                    # users would want to ignore relatively small Hankel
                    # singular values anyway, as that is the point of doing a
                    # balancing transformation.
                    BPOD_res = bpod.compute_BPOD_arrays(
                        direct_vecs_array,
                        adjoint_vecs_array,
                        num_inputs=num_inputs,
                        num_outputs=num_outputs,
                        inner_product_weights=weights,
                        rtol=rtol_svd,
                        atol=atol_svd)

                    # Check Hankel array values.  These are computed fast
                    # internally by only computing the first column and last row
                    # of chunks.  Here, simply take all the inner products.
                    Hankel_array_slow = IP(adjoint_vecs_array,
                                           direct_vecs_array)
                    np.testing.assert_allclose(BPOD_res.Hankel_array,
                                               Hankel_array_slow,
                                               rtol=rtol,
                                               atol=atol)

                    # Check properties of SVD of Hankel array.  Since the SVD
                    # may be truncated, instead of checking orthogonality and
                    # reconstruction of the Hankel array, check that the left
                    # and right singular vectors satisfy eigendecomposition
                    # properties with respect to the Hankel array.  Since this
                    # involves "squaring" the Hankel array, it requires more
                    # relaxed test tolerances.
                    np.testing.assert_allclose(
                        BPOD_res.Hankel_array.dot(
                            BPOD_res.Hankel_array.conj().T.dot(
                                BPOD_res.L_sing_vecs)),
                        BPOD_res.L_sing_vecs.dot(
                            np.diag(BPOD_res.sing_vals**2.)),
                        rtol=rtol_sqr,
                        atol=atol_sqr)
                    np.testing.assert_allclose(
                        BPOD_res.Hankel_array.conj().T.dot(
                            BPOD_res.Hankel_array.dot(BPOD_res.R_sing_vecs)),
                        BPOD_res.R_sing_vecs.dot(
                            np.diag(BPOD_res.sing_vals**2.)),
                        rtol=rtol_sqr,
                        atol=atol_sqr)

                    # Check that the modes diagonalize the gramians.  This test
                    # requires looser tolerances than the other tests, likely
                    # due to the "squaring" of the arrays in computing the
                    # gramians.
                    np.testing.assert_allclose(IP(
                        BPOD_res.adjoint_modes, direct_vecs_array).dot(
                            IP(direct_vecs_array, BPOD_res.adjoint_modes)),
                                               np.diag(BPOD_res.sing_vals),
                                               rtol=rtol_sqr,
                                               atol=atol_sqr)
                    np.testing.assert_allclose(IP(
                        BPOD_res.direct_modes, adjoint_vecs_array).dot(
                            IP(adjoint_vecs_array, BPOD_res.direct_modes)),
                                               np.diag(BPOD_res.sing_vals),
                                               rtol=rtol_sqr,
                                               atol=atol_sqr)

                    # Check the value of the projection coefficients against a
                    # projection onto the adjoint and direct modes,
                    # respectively.
                    np.testing.assert_allclose(BPOD_res.direct_proj_coeffs,
                                               IP(BPOD_res.adjoint_modes,
                                                  direct_vecs_array),
                                               rtol=rtol,
                                               atol=atol)
                    np.testing.assert_allclose(BPOD_res.adjoint_proj_coeffs,
                                               IP(BPOD_res.direct_modes,
                                                  adjoint_vecs_array),
                                               rtol=rtol,
                                               atol=atol)

                    # Check that if mode indices are passed in, the correct
                    # modes are returned.  Test both an explicit selection of
                    # mode indices and a None argument.
                    mode_indices_trunc = np.unique(
                        np.random.randint(0,
                                          high=BPOD_res.sing_vals.size,
                                          size=(BPOD_res.sing_vals.size // 2)))
                    for mode_indices_arg, mode_indices_vals in zip(
                        [None, mode_indices_trunc],
                        [range(BPOD_res.sing_vals.size), mode_indices_trunc]):
                        BPOD_res_sliced = bpod.compute_BPOD_arrays(
                            direct_vecs_array,
                            adjoint_vecs_array,
                            direct_mode_indices=mode_indices_arg,
                            adjoint_mode_indices=mode_indices_arg,
                            num_inputs=num_inputs,
                            num_outputs=num_outputs,
                            inner_product_weights=weights,
                            rtol=rtol_svd,
                            atol=atol_svd)
                        np.testing.assert_allclose(
                            BPOD_res_sliced.direct_modes,
                            BPOD_res.direct_modes[:, mode_indices_vals],
                            rtol=rtol,
                            atol=atol)
                        np.testing.assert_allclose(
                            BPOD_res_sliced.adjoint_modes,
                            BPOD_res.adjoint_modes[:, mode_indices_vals],
                            rtol=rtol,
                            atol=atol)
Example #34
0
    def test_compute_proj_coeffs(self):
        # Set test tolerances.  Use a slightly more relaxed absolute tolerance
        # here because the projection test uses modes that may correspond to
        # smaller Hankel singular values (i.e., less controllable/unobservable
        # states).  Those mode pairs are not as close to biorthogonal, so a more
        # relaxed tolerance is required.
        rtol = 1e-8
        atol = 1e-8

        # Test a single input/output as well as multiple inputs/outputs.  Allow
        # for more inputs/outputs than states.  (This is determined in setUp()).
        for num_inputs in self.num_inputs_list:
            for num_outputs in self.num_outputs_list:

                # Get impulse response data
                direct_vec_handles, adjoint_vec_handles =\
                self._helper_get_impulse_response_handles(
                    num_inputs, num_outputs)

                # Create BPOD object and compute decomposition, modes.  (The
                # properties defining a projection onto BPOD modes require
                # manipulations involving the correct decomposition and modes,
                # so we cannot isolate the projection step from those
                # computations.)  Use relative tolerance to avoid Hankel
                # singular values which may correspond to very
                # uncontrollable/unobservable states.  It is ok to use a
                # more relaxed tolerance here than in the actual test/assert
                # statements, as here we are saying it is ok to ignore
                # highly uncontrollable/unobservable states, rather than
                # allowing loose tolerances in the comparison of two
                # numbers.  Furthermore, it is likely that in actual use,
                # users would want to ignore relatively small Hankel
                # singular values anyway, as that is the point of doing a
                # balancing transformation.
                BPOD = bpod.BPODHandles(inner_product=np.vdot, verbosity=0)
                BPOD.compute_decomp(direct_vec_handles,
                                    adjoint_vec_handles,
                                    num_inputs=num_inputs,
                                    num_outputs=num_outputs,
                                    rtol=1e-6,
                                    atol=1e-12)
                mode_idxs = range(BPOD.sing_vals.size)
                direct_mode_handles = [
                    VecHandlePickle(self.direct_mode_path % i)
                    for i in mode_idxs
                ]
                adjoint_mode_handles = [
                    VecHandlePickle(self.adjoint_mode_path % i)
                    for i in mode_idxs
                ]
                BPOD.compute_direct_modes(
                    mode_idxs,
                    direct_mode_handles,
                    direct_vec_handles=direct_vec_handles)
                BPOD.compute_adjoint_modes(
                    mode_idxs,
                    adjoint_mode_handles,
                    adjoint_vec_handles=adjoint_vec_handles)

                # Compute true projection coefficients by computing the inner
                # products between modes and snapshots.
                direct_proj_coeffs_true =\
                BPOD.vec_space.compute_inner_product_array(
                    adjoint_mode_handles, direct_vec_handles)
                adjoint_proj_coeffs_true =\
                BPOD.vec_space.compute_inner_product_array(
                    direct_mode_handles, adjoint_vec_handles)

                # Compute projection coefficients using BPOD object, which
                # avoids actually manipulating handles and computing inner
                # products, instead using elements of the decomposition for a
                # more efficient computation.
                direct_proj_coeffs = BPOD.compute_direct_proj_coeffs()
                adjoint_proj_coeffs = BPOD.compute_adjoint_proj_coeffs()

                # Test values
                np.testing.assert_allclose(direct_proj_coeffs,
                                           direct_proj_coeffs_true,
                                           rtol=rtol,
                                           atol=atol)
                np.testing.assert_allclose(adjoint_proj_coeffs,
                                           adjoint_proj_coeffs_true,
                                           rtol=rtol,
                                           atol=atol)
Example #35
0
    def test_assemble_Hankel(self):
        """ Tests Hankel arrays are symmetric and accurate given Markov params
        ``[CB CAB CA**P CA**(P+1)B ...]``."""
        rtol = 1e-10
        atol = 1e-12
        for num_inputs in [1, 3]:
            for num_outputs in [1, 2, 4]:
                for sample_interval in [1]:
                    num_time_steps = 50
                    num_states = 8
                    # A, B, C = util.drss(num_states, num_inputs, num_outputs)
                    time_steps = make_time_steps(
                        num_time_steps, sample_interval)
                    A = util.load_array_text(
                        join(self.data_dir, 'A_in%d_out%d.txt') % (
                            num_inputs, num_outputs))
                    B = util.load_array_text(
                        join(self.data_dir, 'B_in%d_out%d.txt') % (
                            num_inputs, num_outputs))
                    C = util.load_array_text(
                        join(self.data_dir, 'C_in%d_out%d.txt') % (
                            num_inputs, num_outputs))
                    impulse_response = util.impulse(A, B, C, time_steps[-1] + 1)
                    Markovs = impulse_response[time_steps]

                    if sample_interval == 2:
                        time_steps, Markovs = era.make_sampled_format(
                            time_steps, Markovs)

                    my_ERA = era.ERA(verbosity=0)
                    my_ERA._set_Markovs(Markovs)
                    my_ERA._assemble_Hankel()
                    H = my_ERA.Hankel_array
                    Hp = my_ERA.Hankel_array2

                    for row in range(my_ERA.mc):
                        for col in range(my_ERA.mo):
                            # Test values in H are accurate using that, roughly,
                            # H[r,c] = C * A^(r+c) * B.
                            np.testing.assert_allclose(
                                H[row * num_outputs:(row + 1) * num_outputs,
                                col * num_inputs:(col + 1) * num_inputs],
                                C.dot(
                                    np.linalg.matrix_power(
                                        A, time_steps[(row + col) * 2]).dot(
                                        B)),
                                rtol=rtol, atol=atol)

                            # Test values in H are accurate using that, roughly,
                            # Hp[r,c] = C * A^(r+c+1) * B.
                            np.testing.assert_allclose(
                                Hp[row * num_outputs:(row + 1) * num_outputs,
                                   col * num_inputs:(col + 1) * num_inputs],
                                C.dot(
                                    np.linalg.matrix_power(
                                        A, time_steps[(row + col) * 2 + 1]).dot(
                                            B)),
                                rtol=rtol, atol=atol)

                            # Test H is block symmetric
                            np.testing.assert_equal(
                                H[row * num_outputs:(row + 1) * num_outputs,
                                  col * num_inputs:(col + 1) * num_inputs],
                                H[col * num_outputs:(col + 1) * num_outputs,
                                  row * num_inputs:(row + 1) * num_inputs])

                            # Test Hp is block symmetric
                            np.testing.assert_equal(
                                Hp[row * num_outputs:(row + 1) * num_outputs,
                                   col * num_inputs:(col + 1) * num_inputs],
                                Hp[col * num_outputs:(col + 1) * num_outputs,
                                   row * num_inputs:(row + 1) * num_inputs])
Example #36
0
    def generate_data_set(self, num_basis_vecs, num_adjoint_basis_vecs,
        num_states, num_inputs, num_outputs):
        """Generates random data, saves, and computes true reduced A,B,C."""
        self.basis_vec_handles = [
            VecHandlePickle(self.basis_vec_path % i)
            for i in range(self.num_basis_vecs)]
        self.adjoint_basis_vec_handles = [
            VecHandlePickle(self.adjoint_basis_vec_path % i)
            for i in range(self.num_adjoint_basis_vecs)]
        self.A_on_basis_vec_handles = [
            VecHandlePickle(self.A_on_basis_vec_path % i)
            for i in range(self.num_basis_vecs)]
        self.B_on_standard_basis_handles = [
            VecHandlePickle(self.B_on_basis_path % i)
            for i in range(self.num_inputs)]
        self.C_on_basis_vec_handles = [
            VecHandlePickle(self.C_on_basis_vec_path % i)
            for i in range(self.num_basis_vecs)]

        self.basis_vec_array = (
            parallel.call_and_bcast(
                np.random.random, (num_states, num_basis_vecs)) +
            1j * parallel.call_and_bcast(
                np.random.random, (num_states, num_basis_vecs)))
        self.adjoint_basis_vec_array = (
            parallel.call_and_bcast(
                np.random.random, (num_states, num_adjoint_basis_vecs)) +
            1j * parallel.call_and_bcast(
                np.random.random, (num_states, num_adjoint_basis_vecs)))
        self.A_array = (
            parallel.call_and_bcast(
                np.random.random, (num_states, num_states)) +
            1j * parallel.call_and_bcast(
                np.random.random, (num_states, num_states)))
        self.B_array = (
            parallel.call_and_bcast(
                np.random.random, (num_states, num_inputs)) +
            1j * parallel.call_and_bcast(
                np.random.random, (num_states, num_inputs)))
        self.C_array = (
            parallel.call_and_bcast(
                np.random.random, (num_outputs, num_states)) +
            1j * parallel.call_and_bcast(
                np.random.random, (num_outputs, num_states)))

        self.basis_vecs = [
            self.basis_vec_array[:, i].squeeze() for i in range(num_basis_vecs)]
        self.adjoint_basis_vecs = [
            self.adjoint_basis_vec_array[:, i].squeeze()
            for i in range(num_adjoint_basis_vecs)]
        self.A_on_basis_vecs = [
            self.A_array.dot(basis_vec).squeeze()
            for basis_vec in self.basis_vecs]
        self.B_on_basis = [
            self.B_array[:, i].squeeze() for i in range(self.num_inputs)]
        self.C_on_basis_vecs = [
            np.array(self.C_array.dot(basis_vec).squeeze(), ndmin=1)
            for basis_vec in self.basis_vecs]

        if parallel.is_rank_zero():
            for handle,vec in zip(self.basis_vec_handles, self.basis_vecs):
                handle.put(vec)
            for handle,vec in zip(
                self.adjoint_basis_vec_handles, self.adjoint_basis_vecs):
                handle.put(vec)
            for handle,vec in zip(
                self.A_on_basis_vec_handles, self.A_on_basis_vecs):
                handle.put(vec)
            for handle,vec in zip(
                self.B_on_standard_basis_handles, self.B_on_basis):
                handle.put(vec)
            for handle,vec in zip(
                self.C_on_basis_vec_handles, self.C_on_basis_vecs):
                handle.put(vec)
        parallel.barrier()

        self.A_true = self.adjoint_basis_vec_array.conj().T.dot(
            self.A_array.dot(self.basis_vec_array))
        self.B_true = self.adjoint_basis_vec_array.conj().T.dot(self.B_array)
        self.C_true = self.C_array.dot(self.basis_vec_array)
        self.proj_array = np.linalg.inv(
            self.adjoint_basis_vec_array.conj().T.dot(self.basis_vec_array))
        self.A_true_non_orth = self.proj_array.dot(self.A_true)
        self.B_true_non_orth = self.proj_array.dot(self.B_true)
    def test_lin_combine(self):
        # Set test tolerances
        rtol = 1e-10
        atol = 1e-12

        # Setup
        mode_path = join(self.test_dir, 'mode_%03d.pkl')
        vec_path = join(self.test_dir, 'vec_%03d.pkl')

        # Test cases where number of modes:
        #   less, equal, more than num_states
        #   less, equal, more than num_vecs
        #   less, equal, more than total_num_vecs_in_mem
        # Also check the case of passing a None value to the mode_indices
        # argument.
        num_states = 20
        num_vecs_list = [1, 15, 40]
        num_modes_list = [
            None, 1, 8, 10, 20, 25, 45,
            int(np.ceil(self.total_num_vecs_in_mem / 2.)),
            self.total_num_vecs_in_mem, self.total_num_vecs_in_mem * 2]

        # Check for correct computations
        for num_vecs in num_vecs_list:
            for num_modes in num_modes_list:
                for squeeze in [True, False]:

                    # Generate data and then broadcast to all procs
                    vec_handles = [
                        VecHandlePickle(vec_path % i)
                        for i in range(num_vecs)]
                    vec_array, coeff_array, true_modes =\
                        parallel.call_and_bcast(
                            self.generate_vecs_modes, num_states, num_vecs,
                            num_modes=num_modes, squeeze=squeeze)
                    if parallel.is_rank_zero():
                        for vec_index, vec_handle in enumerate(vec_handles):
                            vec_handle.put(vec_array[:, vec_index])
                    parallel.barrier()

                    # Choose which modes to compute
                    if num_modes is None:
                        mode_idxs_arg = None
                        mode_idxs_vals = range(true_modes.shape[1])
                    elif num_modes == 1:
                        mode_idxs_arg = 0
                        mode_idxs_vals = [0]
                    else:
                        mode_idxs_arg = np.unique(
                            parallel.call_and_bcast(
                                np.random.randint, 0, high=num_modes,
                                size=num_modes // 2))
                        mode_idxs_vals = mode_idxs_arg
                    mode_handles = [
                        VecHandlePickle(mode_path % mode_num)
                        for mode_num in mode_idxs_vals]

                    # Saves modes to files
                    self.vec_space.lin_combine(
                        mode_handles, vec_handles, coeff_array,
                        coeff_array_col_indices=mode_idxs_arg)

                    # Test modes one by one
                    for mode_idx in mode_idxs_vals:
                        computed_mode = VecHandlePickle(
                            mode_path % mode_idx).get()
                        np.testing.assert_allclose(
                            computed_mode, true_modes[:, mode_idx],
                            rtol=rtol, atol=atol)
                    parallel.barrier()

                parallel.barrier()

            parallel.barrier()

        # Test that errors are caught for mismatched dimensions
        mode_handles = [
            VecHandlePickle(mode_path % i) for i in range(10)]
        vec_handles = [
            VecHandlePickle(vec_path % i) for i in range(15)]
        coeffs_array_too_short = np.zeros(
            (len(vec_handles) - 1, len(mode_handles)))
        coeffs_array_too_fat = np.zeros(
            (len(vec_handles), len(mode_handles) + 1))
        index_list_too_long = range(len(mode_handles) + 1)
        self.assertRaises(
            ValueError, self.vec_space.lin_combine, mode_handles, vec_handles,
            coeffs_array_too_short)
        self.assertRaises(
            ValueError, self.vec_space.lin_combine, mode_handles, vec_handles,
            coeffs_array_too_fat)
Example #38
0
    def generate_data_set(self, num_basis_vecs, num_adjoint_basis_vecs,
                          num_states, num_inputs, num_outputs):
        """Generates random data, saves, and computes true reduced A,B,C."""
        self.basis_vec_handles = [
            VecHandlePickle(self.basis_vec_path % i)
            for i in range(self.num_basis_vecs)
        ]
        self.adjoint_basis_vec_handles = [
            VecHandlePickle(self.adjoint_basis_vec_path % i)
            for i in range(self.num_adjoint_basis_vecs)
        ]
        self.A_on_basis_vec_handles = [
            VecHandlePickle(self.A_on_basis_vec_path % i)
            for i in range(self.num_basis_vecs)
        ]
        self.B_on_standard_basis_handles = [
            VecHandlePickle(self.B_on_basis_path % i)
            for i in range(self.num_inputs)
        ]
        self.C_on_basis_vec_handles = [
            VecHandlePickle(self.C_on_basis_vec_path % i)
            for i in range(self.num_basis_vecs)
        ]

        self.basis_vec_array = (
            parallel.call_and_bcast(np.random.random,
                                    (num_states, num_basis_vecs)) +
            1j * parallel.call_and_bcast(np.random.random,
                                         (num_states, num_basis_vecs)))
        self.adjoint_basis_vec_array = (
            parallel.call_and_bcast(np.random.random,
                                    (num_states, num_adjoint_basis_vecs)) +
            1j * parallel.call_and_bcast(np.random.random,
                                         (num_states, num_adjoint_basis_vecs)))
        self.A_array = (parallel.call_and_bcast(np.random.random,
                                                (num_states, num_states)) +
                        1j * parallel.call_and_bcast(np.random.random,
                                                     (num_states, num_states)))
        self.B_array = (parallel.call_and_bcast(np.random.random,
                                                (num_states, num_inputs)) +
                        1j * parallel.call_and_bcast(np.random.random,
                                                     (num_states, num_inputs)))
        self.C_array = (
            parallel.call_and_bcast(np.random.random,
                                    (num_outputs, num_states)) +
            1j * parallel.call_and_bcast(np.random.random,
                                         (num_outputs, num_states)))

        self.basis_vecs = [
            self.basis_vec_array[:, i].squeeze() for i in range(num_basis_vecs)
        ]
        self.adjoint_basis_vecs = [
            self.adjoint_basis_vec_array[:, i].squeeze()
            for i in range(num_adjoint_basis_vecs)
        ]
        self.A_on_basis_vecs = [
            self.A_array.dot(basis_vec).squeeze()
            for basis_vec in self.basis_vecs
        ]
        self.B_on_basis = [
            self.B_array[:, i].squeeze() for i in range(self.num_inputs)
        ]
        self.C_on_basis_vecs = [
            np.array(self.C_array.dot(basis_vec).squeeze(), ndmin=1)
            for basis_vec in self.basis_vecs
        ]

        if parallel.is_rank_zero():
            for handle, vec in zip(self.basis_vec_handles, self.basis_vecs):
                handle.put(vec)
            for handle, vec in zip(self.adjoint_basis_vec_handles,
                                   self.adjoint_basis_vecs):
                handle.put(vec)
            for handle, vec in zip(self.A_on_basis_vec_handles,
                                   self.A_on_basis_vecs):
                handle.put(vec)
            for handle, vec in zip(self.B_on_standard_basis_handles,
                                   self.B_on_basis):
                handle.put(vec)
            for handle, vec in zip(self.C_on_basis_vec_handles,
                                   self.C_on_basis_vecs):
                handle.put(vec)
        parallel.barrier()

        self.A_true = self.adjoint_basis_vec_array.conj().T.dot(
            self.A_array.dot(self.basis_vec_array))
        self.B_true = self.adjoint_basis_vec_array.conj().T.dot(self.B_array)
        self.C_true = self.C_array.dot(self.basis_vec_array)
        self.proj_array = np.linalg.inv(
            self.adjoint_basis_vec_array.conj().T.dot(self.basis_vec_array))
        self.A_true_non_orth = self.proj_array.dot(self.A_true)
        self.B_true_non_orth = self.proj_array.dot(self.B_true)
    def test_compute_inner_product_arrays(self):
        """Test computation of array of inner products."""
        rtol = 1e-10
        atol = 1e-12

        num_row_vecs_list = [
            1,
            int(round(self.total_num_vecs_in_mem / 2.)),
            self.total_num_vecs_in_mem,
            self.total_num_vecs_in_mem * 2,
            parallel.get_num_procs() + 1]
        num_col_vecs_list = num_row_vecs_list
        num_states = 6

        row_vec_path = join(self.test_dir, 'row_vec_%03d.pkl')
        col_vec_path = join(self.test_dir, 'col_vec_%03d.pkl')

        for num_row_vecs in num_row_vecs_list:
            for num_col_vecs in num_col_vecs_list:

                # Generate vecs
                parallel.barrier()
                row_vec_array = (
                    parallel.call_and_bcast(
                        np.random.random, (num_states, num_row_vecs))
                    + 1j * parallel.call_and_bcast(
                        np.random.random, (num_states, num_row_vecs)))
                col_vec_array = (
                    parallel.call_and_bcast(
                        np.random.random, (num_states, num_col_vecs))
                    + 1j * parallel.call_and_bcast(
                        np.random.random, (num_states, num_col_vecs)))
                row_vec_handles = [
                    VecHandlePickle(row_vec_path % i)
                    for i in range(num_row_vecs)]
                col_vec_handles = [
                    VecHandlePickle(col_vec_path % i)
                    for i in range(num_col_vecs)]

                # Save vecs
                if parallel.is_rank_zero():
                    for i, h in enumerate(row_vec_handles):
                        h.put(row_vec_array[:, i])
                    for i, h in enumerate(col_vec_handles):
                        h.put(col_vec_array[:, i])
                parallel.barrier()

                # If number of rows/cols is 1, check case of passing a handle
                if len(row_vec_handles) == 1:
                    row_vec_handles = row_vec_handles[0]
                if len(col_vec_handles) == 1:
                    col_vec_handles = col_vec_handles[0]

                # Test ip computation.
                product_true = np.dot(row_vec_array.conj().T, col_vec_array)
                product_computed = self.vec_space.compute_inner_product_array(
                    row_vec_handles, col_vec_handles)
                np.testing.assert_allclose(
                    product_computed, product_true, rtol=rtol, atol=atol)

                # Test symm ip computation
                product_true = np.dot(row_vec_array.conj().T, row_vec_array)
                product_computed =\
                    self.vec_space.compute_symm_inner_product_array(
                        row_vec_handles)
                np.testing.assert_allclose(
                    product_computed, product_true, rtol=rtol, atol=atol)
Example #40
0
    def test_compute_modes(self):
        rtol = 1e-10
        atol = 1e-12

        # Generate weights to test different inner products.
        weights_1D = np.random.random(self.num_states)
        weights_2D = np.identity(self.num_states, dtype=np.complex)
        weights_2D[0, 0] = 2.
        weights_2D[2, 1] = 0.3j
        weights_2D[1, 2] = weights_2D[2, 1].conj()

        # Generate random snapshot data
        vecs_array = (np.random.random(
            (self.num_states, self.num_vecs)) + 1j * np.random.random(
                (self.num_states, self.num_vecs)))

        # Test both method of snapshots and direct method
        for method in ['snaps', 'direct']:
            if method == 'snaps':
                compute_POD = pod.compute_POD_arrays_snaps_method
            elif method == 'direct':
                compute_POD = pod.compute_POD_arrays_direct_method
            else:
                raise ValueError('Invalid method choice.')

            # Loop through different inner product weights
            for weights in [None, weights_1D, weights_2D]:
                IP = VectorSpaceArrays(
                    weights=weights).compute_inner_product_array

                # Compute POD
                POD_res = compute_POD(vecs_array,
                                      inner_product_weights=weights)

                # For method of snapshots, test correlation array values
                if method == 'snaps':
                    np.testing.assert_allclose(IP(vecs_array, vecs_array),
                                               POD_res.correlation_array,
                                               rtol=rtol,
                                               atol=atol)

                # Check POD eigenvalues and eigenvectors
                np.testing.assert_allclose(IP(vecs_array,
                                              vecs_array).dot(POD_res.eigvecs),
                                           POD_res.eigvecs.dot(
                                               np.diag(POD_res.eigvals)),
                                           rtol=rtol,
                                           atol=atol)

                # Check POD modes
                np.testing.assert_allclose(
                    vecs_array.dot(IP(vecs_array, POD_res.modes)),
                    POD_res.modes.dot(np.diag(POD_res.eigvals)),
                    rtol=rtol,
                    atol=atol)

                # Check projection coefficients
                np.testing.assert_allclose(POD_res.proj_coeffs,
                                           IP(POD_res.modes, vecs_array),
                                           rtol=rtol,
                                           atol=atol)

                # Choose a random subset of modes to compute, for testing mode
                # indices argument. Test both an explicit selection of mode
                # indices and a None argument.
                mode_indices_trunc = np.unique(
                    np.random.randint(0,
                                      high=np.linalg.matrix_rank(vecs_array),
                                      size=np.linalg.matrix_rank(vecs_array) //
                                      2))
                for mode_idxs_arg, mode_idxs_vals in zip(
                    [None, mode_indices_trunc],
                    [range(POD_res.eigvals.size), mode_indices_trunc]):

                    # Compute POD
                    POD_res_sliced = compute_POD(vecs_array,
                                                 mode_indices=mode_idxs_arg,
                                                 inner_product_weights=weights)

                    # Check that if mode indices are passed in, the correct
                    # modes are returned.
                    np.testing.assert_allclose(POD_res_sliced.modes,
                                               POD_res.modes[:,
                                                             mode_idxs_vals],
                                               rtol=rtol,
                                               atol=atol)
Example #41
0
    def test_compute_modes(self):
        rtol = 1e-10
        atol = 1e-12

        # Generate weights to test different inner products.
        weights_1D = np.random.random(self.num_states)
        weights_2D = np.identity(self.num_states, dtype=np.complex)
        weights_2D[0, 0] = 2.
        weights_2D[2, 1] = 0.3j
        weights_2D[1, 2] = weights_2D[2, 1].conj()

        # Generate random snapshot data
        vecs_array = (
            np.random.random((self.num_states, self.num_vecs)) +
            1j * np.random.random((self.num_states, self.num_vecs)))

        # Test both method of snapshots and direct method
        for method in ['snaps', 'direct']:
            if method == 'snaps':
                compute_POD = pod.compute_POD_arrays_snaps_method
            elif method == 'direct':
                compute_POD = pod.compute_POD_arrays_direct_method
            else:
                raise ValueError('Invalid method choice.')

            # Loop through different inner product weights
            for weights in [None, weights_1D, weights_2D]:
                IP = VectorSpaceArrays(
                    weights=weights).compute_inner_product_array

                # Compute POD
                POD_res = compute_POD(vecs_array, inner_product_weights=weights)

                # For method of snapshots, test correlation array values
                if method == 'snaps':
                    np.testing.assert_allclose(
                        IP(vecs_array, vecs_array), POD_res.correlation_array,
                        rtol=rtol, atol=atol)

                # Check POD eigenvalues and eigenvectors
                np.testing.assert_allclose(
                    IP(vecs_array, vecs_array).dot(POD_res.eigvecs),
                    POD_res.eigvecs.dot(np.diag(POD_res.eigvals)),
                    rtol=rtol, atol=atol)

                # Check POD modes
                np.testing.assert_allclose(
                    vecs_array.dot(IP(vecs_array, POD_res.modes)),
                    POD_res.modes.dot(np.diag(POD_res.eigvals)),
                    rtol=rtol, atol=atol)

                # Check projection coefficients
                np.testing.assert_allclose(
                    POD_res.proj_coeffs, IP(POD_res.modes, vecs_array),
                    rtol=rtol, atol=atol)

                # Choose a random subset of modes to compute, for testing mode
                # indices argument. Test both an explicit selection of mode
                # indices and a None argument.
                mode_indices_trunc = np.unique(np.random.randint(
                    0, high=np.linalg.matrix_rank(vecs_array),
                    size=np.linalg.matrix_rank(vecs_array) // 2))
                for mode_idxs_arg, mode_idxs_vals in zip(
                    [None, mode_indices_trunc],
                    [range(POD_res.eigvals.size), mode_indices_trunc]):

                    # Compute POD
                    POD_res_sliced = compute_POD(
                        vecs_array, mode_indices=mode_idxs_arg,
                        inner_product_weights=weights)

                    # Check that if mode indices are passed in, the correct
                    # modes are returned.
                    np.testing.assert_allclose(
                        POD_res_sliced.modes,
                        POD_res.modes[:, mode_idxs_vals],
                        rtol=rtol, atol=atol)