def phase_lagrange_matrices(self, given_set_name, eval_set_name, sparse=False): """ Compute the matrices mapping values at some nodes to values and derivatives at new nodes. Parameters ---------- given_set_name : str Name of the set of nodes with which to perform the interpolation. eval_set_name : str Name of the set of nodes at which to evaluate the values and derivatives. sparse : bool If True, the returned matrix will be in scipy CSR sparse format. Otherwise, it is returned as a dense numpy.array. Returns ------- ndarray[num_eval_set, num_given_set] Matrix containing the values at the new nodes. ndarray[num_eval_set, num_given_set] Matrix containing the time derivatives at the new nodes. Notes ----- The values are mapped using the equation: .. math:: x_{eval} = \\left[ L \\right] x_{given} And the derivatives are mapped with the equation: .. math:: \\dot{x}_{eval} = \\left[ D \\right] x_{given} \\frac{d \\tau}{dt} """ L_blocks = [] D_blocks = [] for iseg in range(self.num_segments): i1, i2 = self.subset_segment_indices[given_set_name][iseg, :] indices = self.subset_node_indices[given_set_name][i1:i2] nodes_given = self.node_stau[indices] i1, i2 = self.subset_segment_indices[eval_set_name][iseg, :] indices = self.subset_node_indices[eval_set_name][i1:i2] nodes_eval = self.node_stau[indices] L_block, D_block = lagrange_matrices(nodes_given, nodes_eval) L_blocks.append(L_block) D_blocks.append(D_block) L = block_diag(*L_blocks) D = block_diag(*D_blocks) if sparse: L = sp.csr_matrix(L) D = sp.csr_matrix(D) return L, D
def setup(self): """ Define the independent variables as output variables. """ igd = self.options['input_grid_data'] ogd = self.options['output_grid_data'] output_subset = self.options['output_subset'] if ogd is None: ogd = igd self.input_num_nodes = igd.num_nodes self.output_num_nodes = ogd.subset_num_nodes[output_subset] # Build the interpolation matrix which maps from the input grid to the output grid. # Rather than a single phase-wide interpolating polynomial, map each segment. # To do this, find the nodes in the output grid which fall in each segment of the input # grid. Then build a Lagrange interpolating polynomial for that segment L_blocks = [] output_nodes_ptau = ogd.node_ptau[ ogd.subset_node_indices[output_subset]].tolist() for iseg in range(igd.num_segments): i1, i2 = igd.segment_indices[iseg] iptau_segi = igd.node_ptau[i1:i2] istau_segi = igd.node_stau[i1:i2] # The indices of the output grid that fall within this segment of the input grid if ogd is igd: optau_segi = iptau_segi else: ptau_hi = igd.segment_ends[iseg + 1] if iseg < igd.num_segments - 1: idxs_in_iseg = np.where(output_nodes_ptau <= ptau_hi)[0] else: idxs_in_iseg = np.arange(len(output_nodes_ptau)) optau_segi = np.asarray(output_nodes_ptau)[idxs_in_iseg] # Remove the captured nodes so we don't accidentally include them again output_nodes_ptau = output_nodes_ptau[len(idxs_in_iseg):] # # Now get the output nodes which fall in iseg in iseg's segment tau space. ostau_segi = 2.0 * (optau_segi - iptau_segi[0]) / ( iptau_segi[-1] - iptau_segi[0]) - 1 # Create the interpolation matrix and add it to the blocks L, _ = lagrange_matrices(istau_segi, ostau_segi) L_blocks.append(L) self.interpolation_matrix = block_diag(*L_blocks) for (name, kwargs) in self._timeseries_outputs: units = kwargs['units'] desc = kwargs['units'] shape = kwargs['shape'] self._add_output_configure(name, units, shape, desc)
def phase_lagrange_matrices(self, given_set_name, eval_set_name): """ Compute the matrices mapping values at some nodes to values and derivatives at new nodes. Parameters ---------- given_set_name : str Name of the set of nodes with which to perform the interpolation. eval_set_name : str Name of the set of nodes at which to evaluate the values and derivatives. Returns ------- ndarray[num_eval_set, num_given_set] Matrix that yields the values at the new nodes. ndarray[num_eval_set, num_given_set] Matrix that yields the time derivatives at the new nodes. Notes ----- The values are mapped using the equation: .. math:: x_{eval} = \\left[ L \\right] x_{given} And the derivatives are mapped with the equation: .. math:: \\dot{x}_{eval} = \\left[ D \\right] x_{given} \\frac{d \\tau}{dt} """ L_blocks = [] D_blocks = [] for iseg in range(self.num_segments): i1, i2 = self.subset_segment_indices[given_set_name][iseg, :] indices = self.subset_node_indices[given_set_name][i1:i2] nodes_given = self.node_stau[indices] i1, i2 = self.subset_segment_indices[eval_set_name][iseg, :] indices = self.subset_node_indices[eval_set_name][i1:i2] nodes_eval = self.node_stau[indices] L_block, D_block = lagrange_matrices(nodes_given, nodes_eval) L_blocks.append(L_block) D_blocks.append(D_block) L = block_diag(*L_blocks) D = block_diag(*D_blocks) return L, D
axes[0], color='b', scale=.25) plot_tangent(time[state_disc_idxs], vy[state_disc_idxs], vydot[state_disc_idxs], axes[1], color='b', scale=.25) if i == 0: plt.savefig('lgr_animation_1.png') # Plot the interpolating polynomials t_dense = np.linspace(time[0], time[-1], 100) L, D = lagrange_matrices(time[state_disc_idxs], t_dense) y_dense = L.dot(y[state_disc_idxs]) vy_dense = L.dot(vy[state_disc_idxs]) axes[0].plot(t_dense, y_dense, ms=None, ls=':') axes[1].plot(t_dense, vy_dense, ms=None, ls=':') if i == 0: plt.savefig('lgr_animation_2.png') # # Plot the values and rates at the collocation nodes # tau_s, _ = lgr(3, include_endpoint=True) # tau_disc = tau_s # tau_col = tau_s[:-1] # L, D = lagrange_matrices(tau_disc, tau_col) #
def setup(self): """ Define the independent variables as output variables. """ igd = self.options['input_grid_data'] ogd = self.options['output_grid_data'] output_subset = self.options['output_subset'] if ogd is None: ogd = igd input_num_nodes = igd.num_nodes output_num_nodes = ogd.subset_num_nodes[output_subset] # Build the interpolation matrix which maps from the input grid to the output grid. # Rather than a single phase-wide interpolating polynomial, map each segment. # To do this, find the nodes in the output grid which fall in each segment of the input # grid. Then build a Lagrange interpolating polynomial for that segment L_blocks = [] output_nodes_ptau = ogd.node_ptau[ogd.subset_node_indices[output_subset]].tolist() for iseg in range(igd.num_segments): i1, i2 = igd.segment_indices[iseg] iptau_segi = igd.node_ptau[i1:i2] istau_segi = igd.node_stau[i1:i2] # The indices of the output grid that fall within this segment of the input grid if ogd is igd: optau_segi = iptau_segi else: ptau_hi = igd.segment_ends[iseg+1] if iseg < igd.num_segments - 1: idxs_in_iseg = np.where(output_nodes_ptau <= ptau_hi)[0] else: idxs_in_iseg = np.arange(len(output_nodes_ptau)) optau_segi = np.asarray(output_nodes_ptau)[idxs_in_iseg] # Remove the captured nodes so we don't accidentally include them again output_nodes_ptau = output_nodes_ptau[len(idxs_in_iseg):] # # Now get the output nodes which fall in iseg in iseg's segment tau space. ostau_segi = 2.0 * (optau_segi - iptau_segi[0]) / (iptau_segi[-1] - iptau_segi[0]) - 1 # Create the interpolation matrix and add it to the blocks L, _ = lagrange_matrices(istau_segi, ostau_segi) L_blocks.append(L) self.interpolation_matrix = block_diag(*L_blocks) for (name, kwargs) in self._timeseries_outputs: input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} input_name = 'input_values:{0}'.format(name) shape = kwargs['shape'] self.add_input(input_name, shape=(input_num_nodes,) + shape, **input_kwargs) output_name = name output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} output_kwargs['shape'] = (output_num_nodes,) + kwargs['shape'] self.add_output(output_name, **output_kwargs) self._vars.append((input_name, output_name, shape)) size = np.prod(shape) val_jac = np.zeros((output_num_nodes, size, input_num_nodes, size)) for i in range(size): val_jac[:, i, :, i] = self.interpolation_matrix val_jac = val_jac.reshape((output_num_nodes * size, input_num_nodes * size), order='C') val_jac_rows, val_jac_cols = np.where(val_jac != 0) rs, cs = val_jac_rows, val_jac_cols self.declare_partials(of=output_name, wrt=input_name, rows=rs, cols=cs, val=val_jac[rs, cs])