def glq_nodes_weights(glq_degrees): """ Calculate GLQ unscaled nodes, weights and total number of nodes Parameters ---------- glq_degrees : list List of GLQ degrees for each direction: ``longitude``, ``latitude``, ``radius``. Returns ------- n_nodes : int Total number of nodes computed as the product of the GLQ degrees. glq_nodes : list Unscaled GLQ nodes for each direction: ``longitude``, ``latitude``, ``radius``. glq_weights : list GLQ weights for each node on each direction: ``longitude``, ``latitude``, ``radius``. """ # Unpack GLQ degrees lon_degree, lat_degree, rad_degree = glq_degrees[:] # Get number of point masses n_nodes = np.prod(glq_degrees) # Get nodes coordinates and weights lon_node, lon_weights = leggauss(lon_degree) lat_node, lat_weights = leggauss(lat_degree) rad_node, rad_weights = leggauss(rad_degree) # Reorder nodes and weights glq_nodes = (lon_node, lat_node, rad_node) glq_weights = (lon_weights, lat_weights, rad_weights) return n_nodes, glq_nodes, glq_weights
def glq_nodes_weights(glq_degrees): """ Calculate GLQ unscaled nodes and weights Parameters ---------- glq_degrees : list List of GLQ degrees for each direction: ``longitude``, ``latitude``, ``radius``. Returns ------- glq_nodes : list Unscaled GLQ nodes for each direction: ``longitude``, ``latitude``, ``radius``. glq_weights : list GLQ weights for each node on each direction: ``longitude``, ``latitude``, ``radius``. """ # Unpack GLQ degrees lon_degree, lat_degree, rad_degree = glq_degrees[:] # Get nodes coordinates and weights lon_node, lon_weights = leggauss(lon_degree) lat_node, lat_weights = leggauss(lat_degree) rad_node, rad_weights = leggauss(rad_degree) # Reorder nodes and weights glq_nodes = (lon_node, lat_node, rad_node) glq_weights = (lon_weights, lat_weights, rad_weights) return glq_nodes, glq_weights
def GLeg_pts(Ninteg, xl,xu ): # # Ninteg = [5, 5] # xl = [-1, -1] # xu = [1, 1] if np.size(xl) ==1: ND = np.size(xl) xl=np.squeeze(xl) xu=np.squeeze(xu) xinteg = np.zeros([Ninteg[0], ND]) winteg = np.zeros([Ninteg[0], ND]) for ct in range(ND): [xint, wint] = leg.leggauss(Ninteg[ct]) ## a=-1 , b=1 integrate from -1, 1 ### Linear map from[-1,1] to [a,b] xint = (xl*(1-xint)+ xu*(1+xint))/2 wint = wint*(xu - xl)/2 xinteg[:, ct] = xint winteg[:, ct] = wint del xint, wint [xint, wint] = P.Pcomb(ND, Ninteg, xinteg, winteg) wint = wint / sum(wint) else: ND = np.size(xl) xl=np.squeeze(xl) xu=np.squeeze(xu) xinteg = np.zeros([Ninteg[0], ND]) winteg = np.zeros([Ninteg[0], ND]) for ct in range(ND): [xint, wint] = leg.leggauss(Ninteg[ct]) ## a=-1 , b=1 integrate from -1, 1 ### Linear map from[-1,1] to [a,b] xint = (xl[ct]*(1-xint)+ xu[ct]*(1+xint))/2 wint = wint*(xu[ct] - xl[ct])/2 xinteg[:, ct] = xint winteg[:, ct] = wint del xint, wint [xint, wint] = P.Pcomb(ND, Ninteg, xinteg, winteg) wint = wint / sum(wint) return(xint, wint)
def linspace(b, convention='Driscoll-Healy'): if convention == 'Driscoll-Healy': theta = np.arange(2 * b) * np.pi / (2. * b) phi = np.arange(2 * b) * np.pi / b elif convention == 'SOFT': theta = np.pi * (2 * np.arange(2 * b) + 1) / (4. * b) phi = np.arange(2 * b) * np.pi / b elif convention == 'Clenshaw-Curtis': # theta = np.arange(2 * b + 1) * np.pi / (2 * b) # =phi = np.arange(2 * b + 2) * np.pi / (b + 1) # Must use np.linspace to prevent numerical errors that cause theta > pi theta = np.linspace(0, np.pi, 2 * b + 1) phi = np.linspace(0, 2 * np.pi, 2 * b + 2, endpoint=False) elif convention == 'Gauss-Legendre': # For details, see: # "A Fast Algorithm for Spherical Grid Rotations and its Application to Singular Quadrature" # Zydrunas Gimbutas, Shravan Veerapaneni x, _ = leggauss(b + 1) theta = np.arccos(x) phi = np.arange(2 * b + 2) * np.pi / (b + 1) elif convention == 'HEALPix': # TODO: implement this here so that we don't need the dependency on healpy / healpix_compat from healpix_compat import healpy_sphere_meshgrid return healpy_sphere_meshgrid(b) elif convention == 'equidistribution': raise NotImplementedError('Not implemented yet; see Fast evaluation of quadrature formulae on the sphere.') else: raise ValueError('Unknown convention:' + convention) return theta, phi
def ref_nodes(self): """Return reference nodes for a single element. Signature: ->(n,) """ nodes, _ = leg.leggauss(self.nnodes) return nodes
def calcMagneticModel(self): self.x_herm, self.w_herm = hermgauss(int(self.params['orderHermite'])) self.x_leg, self.w_leg = leggauss(int(self.params['orderLegendre'])) self.I = self.params['i0'] * cube.magnetic_formfactor( self.q, self.params['a'], self.params['sldCore'], self.params['sldSolvent'], self.params['sigA'], self.params['magSldCore'], self.params['magSldSolvent'], self.params['xi'], self.params['sin2alpha'], self.params['polarization'], self.x_herm, self.w_herm, self.x_leg, self.w_leg ) + self.params['bg'] self.r, self.sld = cube.sld( self.params['a'], self.params['sldCore'], self.params['sldSolvent'] ) self.rMag, self.sldMag = cube.sld( self.params['a'], self.params['magSldCore'], self.params['magSldSolvent'] )
def __init__(self, log_mesh, jmx=7, ngl=96, lbdmx=14): """ Expansion of the products of two atomic orbitals placed at given locations and around a center between these locations [1] Talman JD. Multipole Expansions for Numerical Orbital Products, Int. J. Quant. Chem. 107, 1578--1584 (2007) ngl : order of Gauss-Legendre quadrature log_mesh : instance of log_mesh_c defining the logarithmic mesh (rr and pp arrays) jmx : maximal angular momentum quantum number of each atomic orbital in a product lbdmx : maximal angular momentum quantum number used for the expansion of the product phia*phib """ from numpy.polynomial.legendre import leggauss from pyscf.nao.m_log_interp import log_interp_c from pyscf.nao.m_csphar_talman_libnao import csphar_talman_libnao as csphar_jt assert ngl > 2 assert jmx > -1 assert hasattr(log_mesh, 'rr') assert hasattr(log_mesh, 'pp') self.ngl = ngl self.lbdmx = lbdmx self.xx, self.ww = leggauss(ngl) log_mesh_c.__init__(self) self.init_log_mesh(log_mesh.rr, log_mesh.pp) self.plval = np.zeros([2 * (self.lbdmx + jmx + 1), ngl]) self.plval[0, :] = 1.0 self.plval[1, :] = self.xx for kappa in range(1, 2 * (self.lbdmx + jmx) + 1): self.plval[kappa + 1, :] = ( (2 * kappa + 1) * self.xx * self.plval[kappa, :] - kappa * self.plval[kappa - 1, :]) / (kappa + 1) self.log_interp = log_interp_c(self.rr) self.ylm_cr = csphar_jt([0.0, 0.0, 1.0], self.lbdmx + 2 * jmx) return
def stiffness_element_matrices(nu): ''' Quadratic and cubic components of the elastic energy. Example: Q, C = element_matrix(0.3) # Poisson ratio UE_times_2 = dot(dot(Q, U), U) + dot(dot(dot(C, U), U), U) where U=[u00 v00 u10 v10 u11 v11 u01 v01] There is a quatic component but not computed here. ''' n = 4 xg, wg = legendre.leggauss(n) xg, yg = meshgrid(xg, xg) wg = outer(wg, wg) Q0 = zeros([2 * n, 2 * n]) Q1 = zeros([2 * n, 2 * n]) for i in range(n): for j in range(n): axx = _Axx(xg[i, j], yg[i, j]) ayy = _Ayy(xg[i, j], yg[i, j]) axy = _Axy(xg[i, j], yg[i, j]) Q0 += wg[i, j] * (outer(axx, axx) + outer(ayy, ayy) + 1 / 2 * outer(axy, axy)) Q1 += wg[i, j] * (outer(axx, ayy) + outer(ayy, axx) - 1 / 2 * outer(axy, axy)) premul = 1 / (1 - nu**2) return premul * (Q0 + nu * Q1)
def __init__(self, order, method='legendre'): """ Straightforward gaussian integration using Chebyshev polynomials with mapping of the bounds into [-1,1]. Most useful for a bounded interval. Parameters ---------- order : int Order of basis expansion. method : str,'legendre' lobatto : bool,False If True, use Lobatto collocation points. Only works for Chebyshev polynomials. """ from numpy.polynomial.chebyshev import chebval, chebgauss self.order = order self.N = order if method == 'legendre': from numpy.polynomial.legendre import legval self.basis = [ lambda x, i=i: legval(x, [0] * i + [1]) for i in range(self.N + 1) ] self.coX, self.weights = leggauss(self.N + 1, x0=-1.) self.basisCox = [b(self.coX) for b in self.basis] self.W = np.ones_like(self.coX) else: raise Exception("Invalid basis choice.") # Map bounds to given bounds or from given bounds to [-1,1]. self.map_to_bounds = lambda x, x0, x1: (x + 1) / 2 * (x1 - x0) + x0 self.map_from_bounds = lambda x, x0, x1: (x - x0) / (x1 - x0) * 2. - 1.
def lgwt(n, a, b): """ Get n leggauss points in interval [a, b] Parameters ---------- n : int Number of points. a : float Interval starting point. b : float Interval end point. Returns ------- x : numpy.ndarray Sample points. w : numpy.ndarray Weights. """ x1, w = leggauss(n) m = (b - a) / 2 c = (a + b) / 2 x = m * x1 + c w = m * w x = np.flipud(x) return x, w
def __init__(self, npoints): self.npoints = npoints A = self.A = 1.e-3 B = self.B = 2.e-3 self.ref_nodes, self.ref_weights = lge.leggauss(npoints) self.curve_nodes = 0.5 * ((B - A) * self.ref_nodes + (B + A)) self.curve_weights = (B - A) * self.ref_weights
def m_matrix(self): """ compute the m matrix of the element Returns ------- m_e : ndarray stiffness matrix of the element """ degree = self.degree num_dofs = degree + 1 x1, x2 = self.coords m_e = np.zeros((num_dofs, num_dofs)) num_gps = math.ceil(degree + 1) xg, wg = leggauss(num_gps) for i in range(len(xg)): xi = xg[i] weight = wg[i] N = hsf.shape_functions_1d(xi, degree) Le = x2 - x1 m_e += np.outer(N, N) * Le / 2 * weight return m_e
def elemLoadNeumann(p, n, g): # vertices of the interval P0 = p[0,:] P1 = p[1,:] # length of interval L = la.norm(P0-P1) # read quadrature points and weights from numpy.polynomial.legendre import leggauss x, w = leggauss(n) x = (x + 1.0)/2.0 # transform quadrature points to interval [0,1] w = w/2.0 # scale weights according to transformation # numerical integration gK = np.zeros((2)) for i in range(n): # transform quadrature points to interval [P0,P1] y = P0 + x[i]*(P1-P0) # add weight w(i) multiplied with function g at y multiplied with # element shape function multiplied with length L of interval gK[0] += L * w[i] * g(y[0],y[1]) * (1-x[i]) gK[1] += L * w[i] * g(y[0],y[1]) * x[i] # return gK return gK
def leggauss_ab(n=96, a=-1.0, b=1.0): assert (n > 0) from numpy.polynomial.legendre import leggauss x, w = leggauss(n) x = (b - a) * 0.5 * x + (b + a) * 0.5 w = w * (b - a) * 0.5 return x, w
def g(self, i): x, w = leggauss(self.gauss) # Translate x values from the interval [-1, 1] to [a, b] t = 0.5 * (x + 1) * (b - a) + a gauss = sum(w * f(t)) * 0.5 * (b - a) return 1
def __init__(self, order): print("Generating the basis functions.") # polynomial order self.p = order # number of coefficients in solution self.N_s = order + 1 # Get the Gaussian nodes and weights. We want to integrate # exactly at most \int phi^(p) phi^(p) dx which is a # polynomial of degree 2p. So we want a Gaussian quadrature # rule of p+1 (to integrate exactly a polynomial of 2p+2 and # less). self.x, self.w = leg.leggauss(self.p + 1) self.N_G = len(self.x) # Construct useful basis matrices self.phi, self.dphi_w = self.evaluate_basis_gauss() # Construct the matrix to evaluate a solution at the cell edges self.psi = self.evaluate_basis_edges() # Construct the (unscaled) mass matrix and its inverse self.m, self.minv = self.mass_matrix()
def compute_integration_terms(self, tau, num_points): """compute u between 0, tau_i""" if tau == self.tau_cache and num_points == self.integration_num_cache: return else: self.tau_cache = tau self.integration_num_cache = num_points points_weights = legendre.leggauss(num_points) self.y = points_weights[0] self.w = points_weights[1] self.shared_Bu = [None] * len(self.y) self.shared_u = [None] * len(self.y) X = self.B_at_zero() # this transformation significantly reduces the number of iterations H = np.square(np.log(np.array(self.shared_B) / X)) cheby_interp = intrp.ChebyshevInterpolation(H, self.to_cheby_point, self.tau_min, self.tau_max) self.shared_u = tau - tau * np.square(1 + self.y) / 4.0 Bu_intrp = cheby_interp.value(self.shared_u) # note sqrt(H) can be positive or negative depending on B > X or B < X if self.option_type == qd.OptionType.Put: Bu_intrp = np.exp(-np.sqrt(np.maximum(0.0, Bu_intrp))) * X else: Bu_intrp = np.exp(np.sqrt(np.maximum(0.0, Bu_intrp))) * X self.shared_Bu = Bu_intrp
def csbox_Iq(q, a, b, c, da, db, dc, slda, sldb, sldc, sld_core): z, w = leggauss(76) sld_solvent = 0 overlapping = False dr0 = sld_core - sld_solvent drA, drB, drC = slda - sld_solvent, sldb - sld_solvent, sldc - sld_solvent tA, tB, tC = a + 2 * da, b + 2 * db, c + 2 * dc outer_sum = np.zeros_like(q) for cos_alpha, outer_w in zip((z + 1) / 2, w): sin_alpha = sqrt(1.0 - cos_alpha * cos_alpha) qc = q * cos_alpha siC = c * j0(c * qc / 2) siCt = tC * j0(tC * qc / 2) inner_sum = np.zeros_like(q) for beta, inner_w in zip((z + 1) * pi / 4, w): qa, qb = q * sin_alpha * sin(beta), q * sin_alpha * cos(beta) siA = a * j0(a * qa / 2) siB = b * j0(b * qb / 2) siAt = tA * j0(tA * qa / 2) siBt = tB * j0(tB * qb / 2) if overlapping: Fq = (dr0 * siA * siB * siC + drA * (siAt - siA) * siB * siC + drB * siAt * (siBt - siB) * siC + drC * siAt * siBt * (siCt - siC)) else: Fq = (dr0 * siA * siB * siC + drA * (siAt - siA) * siB * siC + drB * siA * (siBt - siB) * siC + drC * siA * siB * (siCt - siC)) inner_sum += inner_w * Fq**2 outer_sum += outer_w * inner_sum Iq = outer_sum / 4 # = outer*um*zm*8.0/(4.0*M_PI) return Iq / Iq[0]
def quadrature(func, a, b, n): """ Calcula a integral definida usando quadratura gaussiana. Integra a funcao de 'a' para 'b' usando quadratura gaussiana Parametros ---------- func: funcao Uma funcao a ser integrada a: Decimal Limite inferior da integracao b: Decimal Limite superior da integracao n: int Ordem da quadratura gaussiana Retornos -------- val: Decimal Aproximacao da quadratura gaussiana à integral """ #obtem as raizes e pesos para ordem 'n' xi, wi = leg.leggauss(n) val = 0 for i in range(n): x = _func_T(a, b, Decimal(xi[i])) val += func(x) * Decimal(wi[i]) val *= _func_dt(a, b) return val
def __init__(self, degree: int, spline: BSplines, eta_grid: list, constants): # Calculate the number of points required for the Gauss-Legendre # quadrature n = degree // 2 + 1 # Calculate the points and weights required for the Gauss-Legendre # quadrature points, weights = leggauss(n) # Calculate the values used for the Gauss-Legendre quadrature # over the required domain breaks = spline.breaks starts = (breaks[:-1] + breaks[1:]) / 2 self._multFact = (breaks[1] - breaks[0]) / 2 self._points = np.repeat(starts, n) + np.tile(self._multFact * points, len(starts)) self._weights = np.tile(weights, len(starts)) # Create the tools required for the interpolation self._interpolator = SplineInterpolator1D(spline) self._spline = Spline1D(spline) self._splineMem = np.empty_like(self._points) self._fEq = np.empty([eta_grid[0].size, self._points.size]) MOD_IF.feq_vector(modFunc_init(self._fEq), eta_grid[0], self._points, constants.CN0, constants.kN0, constants.deltaRN0, constants.rp, constants.CTi, constants.kTi, constants.deltaRTi)
def f_vector(self, force_global_function, time_value): """ compute the f vector of the element Parameters ---------- force_global_function : callabe the function of force applied on the model Returns ------- f_e : ndarray force vector of the element """ degree = self.degree num_dofs = degree + 1 x1, x2 = self.coords Le = x2 - x1 f_e = np.zeros(num_dofs) num_gps = math.ceil(degree + 1) xg, wg = leggauss(num_gps) for i in range(len(xg)): xi = xg[i] weight = wg[i] N = hsf.shape_functions_1d(xi, degree) x = x1 + 0.5*(xi + 1)*(x2 - x1) f = force_global_function(x, time_value) f_e += f * N * Le / 2 * weight return f_e
def ref_weights(self): """Return reference quadrature weights for a single element. Signature: ->(n,) """ _, weights = leg.leggauss(self.nnodes) return weights
def __init__(self, radius, degree): # Make constant function if is_number(radius): assert radius > 0 self.radius = lambda x0, r=radius: r # Then this must map points on centerline to radius else: self.radius = radius # NOTE: Let s by the arch length coordinate of the centerline of the # cylinder. A tangent to 1d mesh at s is a normal to the plane in which # we draw a circle C(n, r) with radius r. For reduction of 3d we compute # # |2*pi*R(s)|^-1\int_{C(n, r)} u dl = # # |2*pi*R(s)|^-1\int_{-pi}^{pi} u(s + t1*R(s)*cos(theta) + t2*R(s)*sin(theta))R*d(theta) = # # |2*pi*R(s)|^-1\int_{-1}^{1} u(s + t1*R(s)*cos(pi*t) + t2*R(s)*sin(pi*t))*pi*R*dt = # # 1/2*sum_q u(s + t1*R(s)*cos(pi*x_q) + t2*R(s)*sin(pi*x_q)) xq, wq = leggauss(degree) self.__weights__ = wq * 0.5 # Scale down by 0.5 # Precompute trigonometric part (only shift by tangents t1, t2) self.cos_xq = np.cos(np.pi * xq).reshape((-1, 1)) self.sin_xq = np.sin(np.pi * xq).reshape((-1, 1))
def quadrature_weights(b, convention='Gauss-Legendre'): """ Compute quadrature weights for a given grid-type. The function S2.meshgrid generates the points that correspond to the weights generated by this function. if convention == 'Gauss-Legendre': The quadrature formula is exact for polynomials up to degree M less than or equal to 2b + 1, so that we can compute exact Fourier coefficients for f a polynomial of degree at most b. if convention == 'Clenshaw-Curtis': The quadrature formula is exact for polynomials up to degree M less than or equal to 2b, so that we can compute exact Fourier coefficients for f a polynomial of degree at most b. :param b: the grid resolution. See S2.meshgrid :param convention: 'Gauss-Legendre' or 'Clenshaw-Curtis' :return: """ if convention == 'Clenshaw-Curtis': # Use the fast fft based method to compute these weights # see "Fast evaluation of quadrature formulae on the sphere" w = _clenshaw_curtis_weights(n=2 * b) W = np.empty((2 * b + 2, 2 * b + 1)) W[:] = w[None, :] elif convention == 'Gauss-Legendre': # We found this formula in: # "A Fast Algorithm for Spherical Grid Rotations and its Application to Singular Quadrature" # eq. 10 _, w = leggauss(b + 1) W = w[None, :] * (2 * np.pi / (2 * b + 2) * np.ones(2 * b + 2)[:, None]) else: raise ValueError('Unknown convention:' + str(convention)) return W
def ellipsoid_theta(q, radius_polar, radius_equatorial, sld, sld_solvent, volfraction=0, radius_effective=None): #creates values z and corresponding probabilities w from legendre-gauss quadrature volume = ellipsoid_volume(radius_polar, radius_equatorial) z, w = leggauss(76) F1 = np.zeros_like(q) F2 = np.zeros_like(q) #use a u subsition(u=cos) and then u=(z+1)/2 to change integration from #0->2pi with respect to alpha to -1->1 with respect to z, allowing us to use #legendre-gauss quadrature for k, qk in enumerate(q): r = sqrt(radius_equatorial**2*(1-((z+1)/2)**2)+radius_polar**2*((z+1)/2)**2) form = (sld-sld_solvent)*volume*sas_3j1x_x(qk*r) F2[k] = np.sum(w*form**2) F1[k] = np.sum(w*form) #the 1/2 comes from the change of variables mentioned above F2 = F2/2.0 F1 = F1/2.0 if radius_effective is None: radius_effective = ER_ellipsoid(radius_polar,radius_equatorial) SQ = hardsphere_simple(q, radius_effective, volfraction) SQ_EFF = 1 + F1**2/F2*(SQ - 1) IQM = 1e-4*F2/volume IQSM = volfraction*IQM*SQ IQBM = volfraction*IQM*SQ_EFF return Theory(Q=q, F1=F1, F2=F2, P=IQM, S=SQ, I=IQSM, Seff=SQ_EFF, Ibeta=IQBM)
def spectrum_analysis(self): # calculate FCFs GLquad = leggauss(self.quadrature_points) all_data = [] for k in range(self.n_0+1): E0 = self.H2_energy(k) for l in range(self.n_p+1): Ep = self.H2p_energy(l) overlap = 0 for p in range(self.quadrature_points): new_point = 0.5*(self.R_max - self.R_min)*GLquad[0][p] + 0.5*(self.R_max + self.R_min) new_weight = 0.5*(self.R_max - self.R_min)*GLquad[1][p] overlap += self.H2_psi(new_point, k) * self.H2p_psi(new_point, l) * new_weight FCF = overlap**2. # n_0 n_p FCF data = np.zeros(3) if (k==0 and l==0): reference = FCF FCF /= reference data[0] = k data[1] = l data[2] = FCF all_data.append(data) return np.array(all_data)
def calcMagneticModel(self): self.x_herm, self.w_herm = hermgauss(int(self.params['orderHermite'])) self.x_leg, self.w_leg = leggauss(int(self.params['orderLegendre'])) self.I = self.params['i0'] * superball_css_coupled2.magnetic_formfactor( self.q, self.params['particleSize'], self.params['dShell'], self. params['dSurfactant'], self.params['pVal'], self.params['sldCore'], self.params['sldShell'], self.params['sldSurfactant'], self.params['sldSolvent'], self.params['sigParticleSize'], self.params['sigD'], self.params['magSldCore'], self.params['magSldShell'], self.params['magSldSurfactant'], self.params['magSldSolvent'], self.params['xi'], self.params['sin2alpha'], self.params['polarization'], self.x_herm, self.w_herm, self.x_leg, self.w_leg) + self.params['bg'] self.r, self.sld = superball_css_coupled2.sld( self.params['particleSize'], self.params['dShell'], self.params['dSurfactant'], self.params['sldCore'], self.params['sldShell'], self.params['sldSurfactant'], self.params['sldSolvent']) self.rMag, self.sldMag = superball_css_coupled2.sld( self.params['particleSize'], self.params['dShell'], self.params['dSurfactant'], self.params['magSldCore'], self.params['magSldShell'], self.params['magSldSurfactant'], self.params['magSldSolvent'], )
def __init__(self, log_mesh, jmx=7, ngl=96, lbdmx=14): """ Expansion of the products of two atomic orbitals placed at given locations and around a center between these locations [1] Talman JD. Multipole Expansions for Numerical Orbital Products, Int. J. Quant. Chem. 107, 1578--1584 (2007) ngl : order of Gauss-Legendre quadrature log_mesh : instance of log_mesh_c defining the logarithmic mesh (rr and pp arrays) jmx : maximal angular momentum quantum number of each atomic orbital in a product lbdmx : maximal angular momentum quantum number used for the expansion of the product phia*phib """ from numpy.polynomial.legendre import leggauss from pyscf.nao.m_log_interp import log_interp_c from pyscf.nao.m_csphar_talman_libnao import csphar_talman_libnao as csphar_jt assert ngl>2 assert jmx>-1 assert hasattr(log_mesh, 'rr') assert hasattr(log_mesh, 'pp') self.ngl = ngl self.lbdmx = lbdmx self.xx,self.ww = leggauss(ngl) log_mesh_c.__init__(self) self.init_log_mesh(log_mesh.rr, log_mesh.pp) self.plval=np.zeros([2*(self.lbdmx+jmx+1), ngl]) self.plval[0,:] = 1.0 self.plval[1,:] = self.xx for kappa in range(1,2*(self.lbdmx+jmx)+1): self.plval[kappa+1, :]= ((2*kappa+1)*self.xx*self.plval[kappa, :]-kappa*self.plval[kappa-1, :])/(kappa+1) self.log_interp = log_interp_c(self.rr) self.ylm_cr = csphar_jt([0.0,0.0,1.0], self.lbdmx+2*jmx) return
def gauss(f, a, b, N): s = 0 xs, As = legendre.leggauss(N) for x, A in zip(xs, As): xm = x * (b - a) / 2 + (a + b) / 2 s += A * f(xm) return s * (b - a) / 2
def calcModel(self): self.x_herm, self.w_herm = hermgauss(int(self.params['orderHermite'])) self.x_leg, self.w_leg = leggauss(int(self.params['orderLegendre'])) self.I = self.params['i0'] * superball_css_coupledvms.formfactor( self.q, self.params['particleSize'], self.params['dShell'], self.params['dSurfactant'], self.params['pVal'], self.params['sldCore'], self.params['sldShell'], self.params['sldSurfactant'], self.params['sldSolvent'], self.params['sigParticleSize'], self.x_herm, self.w_herm, self.x_leg, self.w_leg ) + self.params['bg'] self.r, self.sld = superball_css_coupledvms.sld( self.params['particleSize'], self.params['dShell'], self.params['dSurfactant'], self.params['sldCore'], self.params['sldShell'], self.params['sldSurfactant'], self.params['sldSolvent'] )
def __init__(self, order, knots): """ Constructor for B-Spline set. order: Int knots: (Int)->[(Double,Int)] or [(Double,Int)] """ self.knots = knots if type(knots) == list else knots(order) self.order = order intervals = make_intervals(self.knots) (xs_quad, ws_quad) = leggauss(order) xs = np.array( [(b-a)*x/2.0+(b+a)/2.0 for (a, b) in intervals for x in xs_quad]) ws = np.array( [w*(b-a)/2.0 for (a, b) in intervals for w in ws_quad]) ts = make_ts(self.knots) def one_basis(i): non0 = non0_q_list(order, self.knots, i) val = calc_bspline_xs(order, ts, i, xs) deriv = calc_deriv_bspline_xs(order, ts, i, xs) return BSpline(i, non0, val, deriv) self.xs = xs self.ws = ws self.ts = ts self.basis = [one_basis(i) for i in range(1, num_bspline(self.order, self.knots)-1)]
def composite_gauss(n, L, q, f, bounds): # gauss points x_i, alpha_i = leggauss(n) # create intervals intervals = [] intervals.append((bounds[0], bounds[1]*q**(L-1))) for i in range(1,L): intervals.append((bounds[1]*q**(L-i), bounds[1]*q**(L-i-1))) #print("intervals: ", intervals) f_i = [] # integration for interval in intervals: a = interval[0] b = interval[1] # transform [a,b] to [-1,1] x_i_ = (b+a)/2 + x_i*(b-a)/2 #print("transformed points: ",x_i_) # evaluate function f_i.append((b-a)/2 * sum(f(x_i_)*alpha_i)) y = sum(f_i) return y
def __init__(self, num_quadrature, width, partition, equation, activation_name, init_para): self.partition = partition self.lower_bound = partition[0] self.upper_bound = partition[-1] self.num_elements = len(partition) - 1 # if self.num_elements > 1: # raise NotImplementedError("Only support one element now.") self.solution, self.loss_term, *jacob, (self.x0, self.y0) = equation self.jacobian = jacob[0] self.width = width self.num_quadrature = num_quadrature self.xi, self.q_weights = leg.leggauss(num_quadrature) self.q_weights = self.q_weights.reshape((1, -1, 1)) # shape: (1, Q, 1) # self.x_input = self.multi_linear_map() # shape: (M, Q, 1) self.x_input = self.uniform_x(num_quadrature) # self.x_input = self.rand_x(num_quadrature) # need transposing to re-index! self.key_bd = np.array([partition[:-1], partition[1:]]).T.reshape( (self.num_elements, 2, 1)) aa = self.key_bd[:, 0:1, 0:1] bb = self.key_bd[:, 1:2, 0:1] self.element_c = 0.5 * (bb - aa) # shape: (M, 1, 1) self.element_inv_c = 2 / (bb - aa) # shape: (M, 1, 1) self.xi_c = -(aa + bb) / (bb - aa) assert self.xi_c.shape == (self.num_elements, 1, 1) self.weights, self.biases = initialize_nn(self.num_elements, self.width, init_para) self.act_wrapper = activation(activation_name)
def lgwt(ndeg, a, b, dtype=np.float32): """ Compute Legendre-Gauss quadrature Generates the Legendre-Gauss nodes and weights on an interval [a, b] with truncation order of ndeg for computing definite integrals using Legendre-Gauss quadrature. Suppose you have a continuous function f(x) which is defined on [a, b] which you can evaluate at any x in [a, b]. Simply evaluate it at all of the values contained in the x vector to obtain a vector f, then compute the definite integral using sum(f.*w); This is a 2rapper for numpy.polynomial leggauss which outputs only in the range of (-1, 1). :param ndeg: truncation order, that is, the number of nodes. :param a, b: The endpoints of the interval over which the quadrature is defined. :return x, w: The quadrature nodes and weights. """ x, w = leggauss(ndeg) scale_factor = (b - a) / 2 shift = (a + b) / 2 x = scale_factor * x + shift w = scale_factor * w return x.astype(dtype), w.astype(dtype)
def gaussIntegral(f, a, b, e): print("Gauss method begins.") n = 0 e1 = 1 print("Finding out correct number of intervals.") while e1 >= e: n += 1 f0 = f for i in range(0, 2 * n): f0 = f0.diff(x) e1 = ((factorial(n)**4 * (b - a)**(2 * n + 1) * maxVal(f0, a, b)) / ((2 * n + 1) * (factorial(2 * n))**3)) print(e1, "<", e) print("So we found n =", n) t = Symbol('t') f1 = f.subs(x, (b + a) / 2 + t * (b - a) / 2) f1 = lambdify(t, f1, modules="sympy") print("Substituting new variable.") multip = (b - a) / 2 print("Finding Legendre roots and coefficients.") x_arr, A_arr = leg.leggauss(n) f_arr = [f1(x_arr[i]) for i in range(len(x_arr))] summ = 0 print("Calculating the result.") for i in range(len(f_arr)): summ += A_arr[i] * f_arr[i] return summ * multip
def k_matrix(self): """ compute the k matrix of the element Returns ------- k_e : ndarray stiffness matrix of the element """ degree = self.degree num_dofs = degree + 1 x1, x2 = self.coords k_e = np.zeros((num_dofs, num_dofs)) num_gps = math.ceil(degree + 1) xg, wg = leggauss(num_gps) for i in range(len(xg)): xi = xg[i] weight = wg[i] dN = hsf.shape_functions_derivatives_1d(xi, degree) B = dN Le = x2 - x1 k_e += np.outer(B, B) * 2 / Le * weight return k_e
def mass_matrix(basis): deg = len(basis) + 1 xq, wq = leggauss(deg) Ujq = np.array([uj(xq) for uj in basis]) Viq = np.array([ui(xq) for ui in basis]) M = (Viq*wq).dot(Ujq.T) return M
def gausslegendre(f, a, b, n=20): ans = 0 # Edit here to implement your code x,w=npl.leggauss(n) # weight and nodes computed for the integral from limit [-1,1] x_new=(b-a)/2*x + ((a+b)/2 )#transform into general interval summation=sum(w*f(x_new)) ans=((b-a)/2)*summation return ans
def gausslegendre(f, a, b, n=20): ans = 0 #Default interval for leggauss is [-1, 1] x, w = legendre.leggauss(n) #Translate the x value to new interval [a, b] t = 0.5 * (x * (b - a) + (b + a)) ans = sum(w * f(t)) * 0.5 * (b - a) return ans
def quadrature_assamble_matrix(V, poly_matrix): '''It is what it is.''' # Local stuff finite_element = V.element fe_dim = finite_element.dim poly_degree = fe_dim - 1 # Assume here that this is mass matrix 2*p is max needed p+1 xq, wq = leggauss(poly_degree+1) quad_degree = len(xq) assert quad_degree == poly_degree + 1 if poly_matrix == 'mass': def element_matrix(finite_element, cell): # Map the points to cell points = cell.map_from_reference(xq) K_matrix = finite_element.eval_basis_all(points, cell) # Remember dx weights = wq/cell.Jac K_matrix = (weights*K_matrix).dot(K_matrix.T) return K_matrix elif poly_matrix == 'stiffness': # Higher degree than necessary def element_matrix(finite_element, cell): # Map the points to cell points = cell.map_from_reference(xq) K_matrix = finite_element.eval_basis_derivative_all(1, points, cell) # Remember dx weights = wq/cell.Jac K_matrix = (weights*K_matrix).dot(K_matrix.T) return K_matrix elif poly_matrix == 'bending': # Higher degree than necessary def element_matrix(finite_element, cell): # Map the points to cell points = cell.map_from_reference(xq) K_matrix = finite_element.eval_basis_derivative_all(2, points, cell) # Remember dx weights = wq/cell.Jac K_matrix = (weights*K_matrix).dot(K_matrix.T) return K_matrix # Global assembly size = V.dim mesh = V.mesh A = lil_matrix((size, size)) dofmap = V.dofmap for cell in Cells(mesh): # Compute element matrix K_matrix = element_matrix(finite_element, cell) global_dofs = dofmap.cell_dofs(cell.index) for i, gi in enumerate(global_dofs): for j, gj in enumerate(global_dofs): A[gi, gj] += K_matrix[i, j] return A
def gauss_legendre_points(deg): """points of GLL quadrature that define polynomial of degree deg.""" if deg == 0: return np.array([0.0]) elif deg == 1: return np.array([-1.0, 1.0]) else: gl = leggauss(deg - 1)[0] return np.r_[-1.0, gl, 1.0]
def stiffness_matrix(basis): deg = len(basis) xq, wq = leggauss(deg) Ujq = np.array([uj(xq) for uj in basis]) Viq = np.array([ui(xq) for ui in basis]) A = (Viq*wq).dot(Ujq.T) return A
def scaling_I(k, j, x): """Returns the Legendre Interpolating Scaling function defined on \in [0, 1]""" weigth = leg.leggauss(k)[1]/2 roots = leg.Legendre.basis(k, domain=[0, 1]).roots() tmp = 0 for i in range(k): tmp = tmp+sqrt(weigth[j])*scaling_L(k, i, roots[j])*scaling_L(k, i, x) return tmp
def gausslegendre(f, a, b, n=20): ans = 0 # Edit here to implement your code [node,weight] = npl.leggauss(n) node_new = (b-a)/2 * node + ((a+b)/2) ans = ((b-a)/2) * sum(weight * f(node_new)) return ans return ans
def integrate_over_domain(domain, basis_1, basis_2, x_degree, y_degree): # Get the gauss-legendre points and weights x, xw = leggauss(x_degree) y, yw = leggauss(y_degree) # Rescale them to our domain interval x = (x + 1.) * domain.extent[0] / 2. y = (y + 1.) * domain.extent[1] / 2. xw *= domain.extent[0] / 2. yw *= domain.extent[1] / 2. # Make the grid on which we will compute the integral xgrid, ygrid = np.meshgrid(x, y) weights = np.outer(yw, xw) # Integrate basis_1*basis_2 over the grid domain_grid = domain.in_subdomain(xgrid, ygrid) fn1 = ma.masked_where(~domain_grid, basis_1(xgrid, ygrid)) fn2 = ma.masked_where(~domain_grid, basis_2(xgrid, ygrid)) value = np.sum(fn1 * fn2 * weights) return value
def gausslegendre(f, a, b, n=20): ans = 0 x, w = npl.leggauss(n) t=0.5*(x+1)*(b-a)+a ans=sum(w*f(t))*0.5*(b-a) return ans
def _gaussianQuadrature(integrand, bounds, Ksample=[20], roundoff=0): """ NAME: _gaussianQuadrature PURPOSE: Numerically take n integrals over a function that returns a float or an array INPUT: integrand - The function you're integrating over. bounds - The bounds of the integral in the form of [[a_0, b_0], [a_1, b_1], ... , [a_n, b_n]] where a_i is the lower bound and b_i is the upper bound Ksample - Number of sample points in the form of [K_0, K_1, ..., K_n] where K_i is the sample point of the ith integral. roundoff - if the integral is less than this value, round it to 0. OUTPUT: The integral of the function integrand HISTORY: 2016-05-24 - Written - Aladdin """ ##Maps the sample point and weights xp = nu.zeros((len(bounds), nu.max(Ksample)), float) wp = nu.zeros((len(bounds), nu.max(Ksample)), float) for i in range(len(bounds)): x,w = leggauss(Ksample[i]) ##Calculates the sample points and weights a,b = bounds[i] xp[i, :Ksample[i]] = .5*(b-a)*x + .5*(b+a) wp[i, :Ksample[i]] = .5*(b - a)*w ##Determines the shape of the integrand s = 0. shape=None s_temp = integrand(*nu.zeros(len(bounds))) if type(s_temp).__name__ == nu.ndarray.__name__ : shape = s_temp.shape s = nu.zeros(shape, float) #gets all combinations of indices from each integrand li = _cartesian(Ksample) ##Performs the actual integration for i in range(li.shape[0]): index = [nu.arange(len(bounds)),li[i]] s+= nu.prod(wp[index])*integrand(*xp[index]) ##Rounds values that are less than roundoff to zero if shape!= None: s[nu.where(nu.fabs(s) < roundoff)] = 0 else: s *= nu.fabs(s) >roundoff return s
def __init__(self, *args, **kws): """ Constructor """ super(GaussLegendreQuadrature, self).__init__(*args, **kws) # init gauss-legendre points for i in xrange(self._n): # get rootsArray in [-1, 1] rootsArray, weights = leggauss(i + 1) # transform rootsArray to [0, 1] rootsArray = (rootsArray + 1) / 2. # zip them self._gaussPoints[i] = zip(rootsArray, weights)
def test_100(self): x, w = leg.leggauss(100) # test orthogonality. Note that the results need to be normalized, # otherwise the huge values that can arise from fast growing # functions like Laguerre can be very confusing. v = leg.legvander(x, 99) vv = np.dot(v.T * w, v) vd = 1/np.sqrt(vv.diagonal()) vv = vd[:,None] * vv * vd assert_almost_equal(vv, np.eye(100)) # check that the integral of 1 is correct tgt = 2.0 assert_almost_equal(w.sum(), tgt)
def compute_legendre_projection(corr, cospsi, lmax, remove_zero=True): # define gaussian quadrature, the points between -1, 1 and the weights xnew, ws = leggauss( cospsi.shape[-1] ) n_q = corr.shape[0] # interpolate cl = np.zeros( ( n_q, lmax + 1) ) for i in range(n_q): signal = corr[i,:].copy() signal_interp = interpolate_corr( cospsi[i,:], xnew, signal) c = leg_proj_legguass( xnew, signal_interp, ws, lmax) cl[i,:] = c if remove_zero: cl[:,0] = 0. return cl
def spherical_harmonic_transform( func, lmax ): coeffs = [] glpoints, glweights = leggauss(lmax) glpoints = np.arccos(glpoints) fpoints = np.linspace(0.,np.pi*2., lmax+1, endpoint=False) for l in range(lmax+1): c = [] for m in range(2*l+1): mp = m-l val = 0. for theta, weight in zip(glpoints, glweights): for phi in fpoints: val += weight*real_spherical_harmonic( theta, phi, l, mp)*func(theta,phi) if val < 1.e-13: val = 0. c.append(val) coeffs.append(c) return coeffs
def knots_and_weights(a,b,deg,method='legendre'): ''' This function returns the nodes and weights used for the Guass quadrature. Parameters: a,b: float The lower and upper limit of the sample interval. deg: integer The number of the sample points and weights. method: string,optional The type of the polynomials. Returns: knots: 1D ndarray The knots. weights: 1D ndarray The weights. ''' if method=='legendre': knots,weights=leggauss(deg) knots=(b-a)/2*knots+(a+b)/2 weights=(b-a)/2*weights return knots,weights
for i in range(m): z=np.cos(np.pi*(i+1-0.25)/(n+0.5)) for c in range(cmx): p1,p2=1.0,0.0 for j in range(1,n+1): p3=p2 p2=p1 p1=((2.0*j-1)*z*p2-(j-1)*p3)/j pp=n*(z*p1-p2)/(z*z-1.0) z1=z z=z1-p1/pp if abs(z-z1)<eps : exit x[ i],x[-i-1] = -z,z w[ i]=w[-i-1] = 2.0/((1.0-z*z)*pp*pp) x = (b-a) * 0.5 * x+(b+a) * 0.5 w = w * (b-a) * 0.5 return x,w if __name__ == '__main__': from pyscf.nao.m_gauleg import gauleg_ab from numpy.polynomial.legendre import leggauss for n in range(1,320): xx1,ww1=leggauss(n) xx2,ww2=gauleg_ab(n) if np.allclose(xx1,xx2) and np.allclose(ww1,ww2): print(n, 'allclose') else: print(n, (xx1-xx2).sum(), (ww1-ww2).sum())
#plt.xlabel('v') #plt.savefig("d1.pdf",format = 'pdf') #plt.show() # Gauss Legendre Quadrature points and weights x, wx = npl.leggauss(500) # Legendre Polynomial l = 0 c = np.zeros(5) c[l] = 1.0 px = npl.legval(x, c) redshift = .55 bias = 2.0 omega0 = 0.274
# Viscosity def eta_v(z): return A_v()**(-1./n)/2.*(dudx_v(z)**2 + dvdy_v(z)**2 + dudx_v(z)*dvdy_v(z) + 0.25*(dudz_v(z)**2 + dvdz_v(z)**2 + (dudy_v(z) + dvdx_v(z))**2) + eps_reg)**((1.-n)/(2*n)) def A_v(): return 300.e3**(-3.) # B = 300 kPa/yr**(1/3), A = B**-3 # Integrals for numerical quadrature in the vertical def gauss_integral(dfdc,z_gauss,w): z = (S-Slp)/2.*z_gauss + (S+Slp)/2. return (S-Slp)/2.*w*eta_v(z)*dfdc(z) # Calculate Gaussian approximants to integral terms k = 7 points,weights = leggauss(int(k)) int_dudx = sum([gauss_integral(dudx_v,z,w) for z,w in zip(points,weights)]) int_dvdx = sum([gauss_integral(dvdx_v,z,w) for z,w in zip(points,weights)]) int_dudy = sum([gauss_integral(dudy_v,z,w) for z,w in zip(points,weights)]) int_dvdy = sum([gauss_integral(dvdy_v,z,w) for z,w in zip(points,weights)]) # Basal sliding parameterization (see van der Veen) Np = H + rho_w / rho * Sl As = 1.0 # sliding constant should be 1.0 p = 1.3 # exponent on effective pressure 1.3 is what Kees is using m = 3. # non-linearity in the sliding law (exponent of velocity) ubmag = sqrt(u_v(Slp)**2+v_v(Slp)**2 + 1e-3) taubx = (mu * As * Np**p * ubmag**(1./m)) * u_v(Slp) / ubmag * grounded_projection tauby = (mu * As * Np**p * ubmag**(1./m)) * v_v(Slp) / ubmag * grounded_projection
for i in range(element.dim)]).reshape(v.shape) assert np.allclose(v, v_) # The matrix by transformation n = len(poly_set) # Exact poly_set matrix M = np.zeros((n, n), dtype=float) for i in range(n): M[i, i] = integrate(poly_set[i]*poly_set[i], (x, -1, 1)) for j in range(i+1, n): M[i, j] = integrate(poly_set[i]*poly_set[j], (x, -1, 1)) M[j, i] = M[i, j] # Nodal basis matrix M_nodal = np.zeros_like(M) points, weights = leggauss(deg=len(poly_set)) for i in range(n): fi_xq = element.eval_basis(i, points) M_nodal[i, i] = np.sum(weights*fi_xq**2) for j in range(i+1, n): fi_xq = element.eval_basis(i, points) fj_xq = element.eval_basis(j, points) M_nodal[i, j] = np.sum(weights*fi_xq*fj_xq) M_nodal[j, i] = M_nodal[i, j] alpha = element.alpha M_nodal_ = alpha.dot(M.dot(alpha.T)) assert np.allclose(M_nodal, M_nodal_) # Check nodality n = element.dim
#integrand = lambda x,y: sin(x)*cos(2*y) integrand = lambda x,y: exp(-x**2 - y**2) # scypy's general purpose integration method for 2D integrals: tic1=time.clock() integral = dblquad(integrand,-1.0,1.0,lambda y:-1.0,lambda y: 1.0) toc1=time.clock() # My own non general purpose integration scheme: # Definition of integration degree for each of the coordinates deg_r = 3 deg_s = 3 # Generation of Gauss-Legendre points using numpy's function: r_i, weights_r = leggauss(deg_r) s_j, weights_s = leggauss(deg_s) # Generation of Gauss-Legendre points using scypys's function: tic2=time.clock() r_i2, weights_r2 = p_roots(deg_r) s_j2, weights_s2 = p_roots(deg_s) # Cycle through each integration node and multiply weights by # function evaluation. integral2 = 0 integral3 = 0 for i in range(deg_r): for j in range(deg_s): integral2 = integral2 + weights_r[i]*weights_s[j]*integrand(r_i[i],s_j[j]) integral3 = integral3 + weights_r2[i]*weights_s2[j]*integrand(r_i2[i],s_j2[j])
if __name__=='__main__': #N=int(raw_input("Enter column value: ")) #K=int(raw_input("Enter sparsity value: ")) N = 200 K = 10 mp.dps = 30 # set high precision to 30 avg_x = np.vectorize(avg_x) avg_x2 = np.vectorize(avg_x2) Leg = leg.leggauss(100) roots_leg = Leg[0] weights_leg = Leg[1] Lag = lag.laggauss(100) roots_lag = Lag[0] weights_lag = Lag[1] mu = 0 sigma2 = .001 # \sigma parameter I vary sigma2 rather than lamda as I found making smaller lambda doesnt lead to a convergent result sigmax02 =1. lamda = 1. #\lambda parameter M = K while(M<=N):
a = -0.5 b = 1.5 # Some exact solution x = Symbol("x") u = (1.0-x**2)**2*cos(np.pi*4*x)*(x-0.25)**3 + b*(1 + x)/2. + a*(1 - x)/2. kx = np.sqrt(5) f = -u.diff(x, 2) + kx**2*u fl = lambdify(x, f, "numpy") ul = lambdify(x, u, "numpy") n = 32 domain = sys.argv[-1] if len(sys.argv) == 2 else "C1" # Chebyshev-Gauss nodes and weights points, w = leg.leggauss(n+1) # Chebyshev Vandermonde matrix V = leg.legvander(points, n) scl=1.0 # First derivative matrix zero padded to (n+1)x(n+1) D1 = np.zeros((n+1,n+1)) D1[:-1,:] = leg.legder(np.eye(n+1), 1, scl=scl) Vx = np.dot(V, D1) # Matrix of trial functions P = np.zeros((n+1,n+1)) P[:,0] = (V[:,0] - V[:,1])/2
def cylinder_average_matrix(V, TV, radius, quad_degree): '''Averaging matrix''' mesh = V.mesh() line_mesh = TV.mesh() # We are going to perform the integration with Gauss quadrature at # the end (PI u)(x): # A cell of mesh (an edge) defines a normal vector. Let P be the plane # that is defined by the normal vector n and some point x on Gamma. Let L # be the circle that is the intersect of P and S. The value of q (in Q) at x # is defined as # # q(x) = (1/|L|)*\int_{L}g(x)*dL # # which simplifies to g(x) = (1/(2*pi*R))*\int_{-pi}^{pi}u(L)*R*d(theta) and # or = (1/2) * \int_{-1}^{1} u (L(pi*s)) * ds # This can be integrated no problemo once we figure out L. To this end, let # t_1 and t_2 be two unit mutually orthogonal vectors that are orthogonal to # n. Then L(pi*s) = p + R*t_1*cos(pi*s) + R*t_2*sin(pi*s) can be seen to be # such that i) |x-p| = R and ii) x.n = 0 [i.e. this the suitable # parametrization] # Clearly we can scale the weights as well as precompute # cos and sin terms. xq, wq = leggauss(quad_degree) wq *= 0.5 cos_xq = np.cos(np.pi*xq).reshape((-1, 1)) sin_xq = np.sin(np.pi*xq).reshape((-1, 1)) if is_number(radius): radius = lambda x, radius=radius: radius mesh_x = TV.mesh().coordinates() # The idea for point evaluation/computing dofs of TV is to minimize # the number of evaluation. I mean a vector dof if done naively would # have to evaluate at same x number of component times. value_size = TV.ufl_element().value_size() # Eval at points will require serch tree = mesh.bounding_box_tree() limit = mesh.num_cells() TV_coordinates = TV.tabulate_dof_coordinates().reshape((TV.dim(), -1)) TV_dm = TV.dofmap() V_dm = V.dofmap() # For non scalar we plan to make compoenents by shift if value_size > 1: TV_dm = TV.sub(0).dofmap() Vel = V.element() basis_values = np.zeros(V.element().space_dimension()*value_size) with petsc_serial_matrix(TV, V) as mat: for line_cell in cells(line_mesh): # Get the tangent => orthogonal tangent vectors v0, v1 = mesh_x[line_cell.entities(0)] n = v0 - v1 t1 = np.array([n[1]-n[2], n[2]-n[0], n[0]-n[1]]) t2 = np.cross(n, t1) t1 /= np.linalg.norm(t1) t2 = t2/np.linalg.norm(t2) # The idea is now to minimize the point evaluation scalar_dofs = TV_dm.cell_dofs(line_cell.index()) scalar_dofs_x = TV_coordinates[scalar_dofs] for scalar_row, avg_point in zip(scalar_dofs, scalar_dofs_x): # Get radius and integration points rad = radius(avg_point) integration_points = avg_point + rad*t1*sin_xq + rad*t2*cos_xq data = {} for index, ip in enumerate(integration_points): c = tree.compute_first_entity_collision(Point(*ip)) if c >= limit: continue Vcell = Cell(mesh, c) vertex_coordinates = Vcell.get_vertex_coordinates() cell_orientation = Vcell.orientation() Vel.evaluate_basis_all(basis_values, ip, vertex_coordinates, cell_orientation) cols_ip = V_dm.cell_dofs(c) values_ip = basis_values*wq[index] # Add for col, value in zip(cols_ip, values_ip.reshape((-1, value_size))): if col in data: data[col] += value else: data[col] = value # The thing now that with data we can assign to several # rows of the matrix column_indices = np.array(data.keys(), dtype='int32') for shift in range(value_size): row = scalar_row + shift column_values = np.array([data[col][shift] for col in column_indices]) mat.setValues([row], column_indices, column_values, PETSc.InsertMode.INSERT_VALUES) # On to next avg point # On to next cell return PETScMatrix(mat)