def __init__(self, nodes, weights, position=None, factor=1, mean=None, cov=None, dirs=None, types=None): """Create a quadrature object Args: nodes: The nodes of the quadrature. weights: The weights of the quadrature, in the basis. Returns: True if successful, False otherwise. Note: Do not include the parameter in the Args section. """ # FIXME: This requires same number of points in each direction self.nodes = np.asarray(nodes, float) self.weights = np.asarray(weights, float) dim = len(self.nodes) self.position = position if position is not None else \ hm.Position(dim=dim, mean=mean, cov=cov, dirs=dirs, types=types) # Factor used for hermite transform, discretize self.factor = hm.Function(factor, dirs=self.position.dirs) self.factor.sym = self.factor.sym.expand() self.do_fourier = [int(t == "fourier") for t in self.position.types]
def discretize_op(self, op, degree, sparse=None, index_set="triangle"): if not isinstance(op, hm.Operator): op = hm.Operator(op, dirs=self.position.dirs) if self.factor != hm.Function(1, dirs=self.position.dirs): op = op.map(self.factor) if not op.dirs == self.position.dirs: raise ValueError("Invalid argument: directions don't match") splitop = op.split() sparse = hm.settings['sparse'] if sparse is None else sparse if splitop == {}: return self.varf(0, degree, sparse=sparse, index_set=index_set) varf_operator = 0 for m, coeff in splitop.items(): enum_dirs = enumerate(self.position.dirs) d_vector = sum([[d] * m[i] for i, d in enum_dirs], []) varf_part = self.varfd(coeff, degree, d_vector, sparse=sparse, index_set=index_set) varf_operator = varf_operator + varf_part return varf_operator
def transform(self, function, degree, index_set="triangle", significant=0, tensorize=None): if not isinstance(function, np.ndarray): function = hm.Function(function, dirs=self.position.dirs) function = self.discretize(function) factor = self.discretize(self.factor) mapped = function / (1e-300 * (factor == 0) + factor) coeffs = core.transform(degree, mapped, self.nodes, self.weights, forward=True, do_fourier=self.do_fourier, index_set=index_set) return hm.Series(coeffs, self.position, factor=self.factor, index_set=index_set, significant=significant)
def tensorize(args): if not len(args) > 0 or \ not isinstance(args[0], Quad): raise ValueError("Invalid argument(s)!") position = hm.Position.tensorize([a.position for a in args]) nodes, weights = [0] * len(position.dirs), [0] * len(position.dirs) factor = sym.Integer(1) for a in args: if not isinstance(a, Quad): raise ValueError("Invalid argument!") factor *= a.factor.sym for i, d in enumerate(a.position.dirs): nodes[position.dirs.index(d)] = a.nodes[i] weights[position.dirs.index(d)] = a.weights[i] factor = hm.Function(factor, dirs=position.dirs) return Quad(nodes, weights, position, factor)
def streamlines(self, fx, fy, factor=None, ax=None, **kwargs): if not self.position.is_diag or \ not isinstance(fx, type(fy)) or \ self.position.dim != 2: raise ValueError("Invalid argument(s)!") show_plt = ax is None if show_plt: import matplotlib.pyplot as plt ax = plt.subplots(1)[1] if isinstance(fx, sym.Basic): fx = hm.Function(fx, dirs=self.position.dirs) fy = hm.Function(fy, dirs=self.position.dirs) if isinstance(fx, hm.Function): if factor is not None: raise ValueError("Invalid argument!") fx, fy = self.discretize(fx), self.discretize(fy) elif isinstance(fx, hm.Series): if factor is None: sx, sy = self.eval(fx), self.eval(fy) elif not isinstance(factor, np.ndarray): factor = hm.Function(factor, dirs=self.position.dirs) factor = self.discretize(factor) sx, sy = self.eval(fx) * factor, self.eval(fy) * factor else: raise TypeError("Unsupported type: " + str(type(fx))) n_nodes = [] r_nodes = [] for i in range(self.position.dim): direction = hm.Function.xyz[self.position.dirs[i]] n_nodes.append(len(self.nodes[i])) r_nodes.append(self.project(i).discretize(direction)) sx, sy = sx.reshape(*n_nodes).T, sy.reshape(*n_nodes).T # magnitude = sx**2 + sy**2 x, y = r_nodes[0], r_nodes[1] # See https://github.com/matplotlib/matplotlib/issues/9269 def calc_psi2d(x, y, fx, fy): # solenoidal flows # psi by integrating dpsi = -fy*dx + fx*dy, psi[0,0]=0 ny, nx = fx.shape psi = np.zeros((ny, nx)) for jx in range(1, nx): psi[0, jx] = psi[0, jx - 1] - fy[0, jx] * (x[jx] - x[jx - 1]) for jy in range(1, ny): psi[jy, :] = psi[jy - 1, :] + fx[jy, :] * (y[jy] - y[jy - 1]) return psi psi = calc_psi2d(x, y, sx, sy) _min, _max, thresh = np.min(psi), np.max(psi), .1 if abs(_min) < thresh * (_max - _min): _min = thresh * (_max - _min) if abs(_max) < thresh * (_max - _min): _max = -thresh * (_max - _min) levels = np.linspace(_min, _max, 10) streams = ax.contour(x, y, psi, levels=levels, **kwargs) # ax.quiver(x, y, sx, sy) # streams = ax.streamplot(r_nodes[0], r_nodes[1], sx, sy, # color=magnitude, density=0.6, cmap='autumn') return plt.show() if show_plt else streams
def plot(self, arg, factor=None, ax=None, contours=0, bounds=False, title=None, **kwargs): if not self.position.is_diag: raise ValueError("Invalid argument: position must be diag!") show_plt = ax is None if show_plt: import matplotlib.pyplot as plt ax = plt.subplots(1)[1] if isinstance(arg, sym.Basic): arg = hm.Function(arg, dirs=self.position.dirs) if isinstance(arg, hm.Function): if factor is not None: raise ValueError("Invalid argument!") solution = self.discretize(arg) elif isinstance(arg, np.ndarray): solution = arg elif isinstance(arg, hm.Series): series = arg # Fix me maybe? if series.coeffs.dtype == np.dtype('complex128'): series.coeffs = np.real(series.coeffs).copy(order='C') if factor is None: solution = self.eval(series) elif not isinstance(factor, np.ndarray): factor = hm.Function(factor, dirs=self.position.dirs) factor = self.discretize(factor) solution = self.eval(series) * factor if bounds: degree_bounds = series.degree bounds, adim_width = [], np.sqrt(2) * np.sqrt( 2 * degree_bounds + 1) for i in range(series.position.dim): mean = series.position.mean[i] cov = series.position.cov[i][i] bounds.append([ mean - adim_width * np.sqrt(cov), mean + adim_width * np.sqrt(cov) ]) if self.position.dim >= 1: ax.axvline(x=bounds[0][0]) ax.axvline(x=bounds[0][1]) if self.position.dim == 2: ax.axhline(y=bounds[1][0]) ax.axhline(y=bounds[1][1]) else: raise TypeError("Unsupported type: " + str(type(arg))) n_nodes = [] r_nodes = [] for i, d in enumerate(self.position.dirs): direction = hm.Function.xyz[d] n_nodes.append(len(self.nodes[i])) r_nodes.append(self.project(d).discretize(direction)) solution = solution.reshape(*n_nodes).T if self.position.dim == 1: plot = ax.plot(*r_nodes, solution, **kwargs) elif self.position.dim == 2: plot = ax.contourf(*r_nodes, solution, 100, **kwargs) for c in plot.collections: c.set_edgecolor("face") if contours > 0: ax.contour(*r_nodes, solution, levels=contours, colors='k') _min, _max = np.min(solution), np.max(solution) if title is None: title = "Min: {:.3f}, Max: {:.3f}".format(_min, _max) ax.set_title(title) if show_plt: if self.position.dim == 2: plt.colorbar(plot, ax=ax) plt.show() else: return plot
def discretize(self, f): if not isinstance(f, hm.Function): f = hm.Function(f, dirs=self.position.dirs) function = core.discretize(f.ccode(), self.nodes, self.position.mean, self.position.factor) return function
def wrapper(*args, **kwargs): tensorize = kwargs['tensorize'] if 'tensorize' in kwargs \ else None do_tensorize = hm.settings['tensorize'] if \ tensorize is None else tensorize # <- Fix bug with integrate(series) if isinstance(args[arg_num], hm.Series): do_tensorize = False # -> if not do_tensorize: return func(*args, **kwargs) quad, function = args[0], args[arg_num] if not quad.position.is_diag or \ isinstance(function, np.ndarray): return func(*args, **kwargs) results = [] if not isinstance(function, hm.Function): function = hm.Function(function, dirs=quad.position.dirs) for add in function.split(legacy=False): multiplicator = add[frozenset()] del add[frozenset()] factor_split = quad.factor.split(legacy=False) if len(factor_split) != 1: raise ValueError("Tensorization not possible!") finest_division = lib.finest_common( set(add), set(factor_split[0])) new_add = { sub: hm.Function('1') for sub in finest_division } for dirs, term in add.items(): for s in new_add: if dirs.issubset(s): f = hm.Function(new_add[s].sym * term.sym, dirs=list(s)) new_add[s] = f func_dirs = {} for dirs, term in new_add.items(): new_args = list(args).copy() new_args[0] = quad.project(list(dirs)) new_args[arg_num] = term func_dirs[dirs] = func(*new_args, **kwargs) if hm.settings['debug']: print("Tensorizing results") kwargs_func = {'sparse': kwargs['sparse']} \ if 'sparse' in kwargs else {} t = type(list(func_dirs.values())[0]) if t is hm.Varf or t is hm.Series: values = list(func_dirs.values()) tensorized = t.tensorize(values, **kwargs_func) else: tensorized = core.tensorize(func_dirs, **kwargs_func) results.append(tensorized * float(multiplicator.sym)) return sum(results[1:], results[0])