def __init__(self, points, k, normalization=NORM_NORM_T0_1, force=False): """ calculate k polynomials of degree 0 to k-1 orthogonal on a set of distinct points map points to interval [-1,1] INPUT: points: array of dictinct points where polynomials are orthogonal k: number of polynomials of degree 0 to k-1 force=True creates basis even if orthogonality is not satisfied due to numerical error USES: x: array of points mapped to [-1,1] T_: matrix of values of polynomials calculated at x, shape (k,len(x)) TT_ = T_ * Numeric.transpose(T_) TTinv_ = inverse(TT_) sc_: scaling factors a, b: coefficients for calculating T (2k-4 different from 0, i.e. 6 for k=5) n: number of points = len(points) normalization = {0|1|2} """ self.k = k # number of basis polynomials of order 0 to k-1 self._force = force self.points = Numeric.asarray(points, Numeric.Float) self.pointsMin = min(points) self.pointsMax = max(points) # scaling x to [-1,1] results in smaller a and b, T is not affected; overflow is NOT a problem! self.xMin = -1 self.xMax = 1 self.x = self._map(self.points, self.pointsMin, self.pointsMax, self.xMin, self.xMax) # calculate basis polynomials self.n = len(points) # the number of approximation points t = Numeric.zeros((k,self.n),Numeric.Float) a = Numeric.zeros((k,1),Numeric.Float) b = Numeric.zeros((k,1),Numeric.Float) t[0,:] = Numeric.ones(self.n,Numeric.Float) if k > 1: t[1,:] = self.x - sum(self.x)/self.n for i in range(1,k-1): a[i+1] = Numeric.innerproduct(self.x, t[i,:] * t[i,:]) / Numeric.innerproduct(t[i,:],t[i,:]) b[i] = Numeric.innerproduct(t[i,:], t[i,:]) / Numeric.innerproduct(t[i-1,:],t[i-1,:]) t[i+1,:] = (self.x - a[i+1]) * t[i,:] - b[i] * t[i-1,:] self.a = a self.b = b # prepare for approximation self._T0 = t # orthonormal _TT0 = Numeric.matrixmultiply(self._T0, Numeric.transpose(self._T0)) self.sc1 = Numeric.sqrt(Numeric.reshape(Numeric.diagonal(_TT0),(self.k,1))) # scaling factors = sqrt sum squared self._T0 self._T1 = self._T0 / self.sc1 # orthonormal and T[0] == 1 self.sc2 = Numeric.sqrt(Numeric.reshape(Numeric.diagonal(_TT0),(self.k,1)) / self.n) # scaling factors = sqrt 1/n * sum squared self._T0 self._T2 = self._T0 / self.sc2 # T[:,-1] == 1 self.sc3 = Numeric.take(self._T0, (-1,), 1) # scaling factors = self._T0[:,-1] self._T3 = self._T0 / self.sc3 # set the variables according to the chosen normalization self.setNormalization(normalization)
def dot(self, other): "Returns the contraction with |other|." if isTensor(other): a = self.array b = Numeric.transpose(other.array, range(1, other.rank)+[0]) return Tensor(Numeric.innerproduct(a, b), 1) else: return Tensor(self.array*other, 1)
def __mul__(self, other): if isTensor(other): a = self.array[self.rank*(slice(None),)+(Numeric.NewAxis,)] b = other.array[other.rank*(slice(None),)+(Numeric.NewAxis,)] return Tensor(Numeric.innerproduct(a, b), 1) elif VectorModule.isVector(other): return other.__rmul__(self) else: return Tensor(self.array*other, 1)
def vector_sum(self, d): """ Return the vector sum of the distribution as a tuple (magnitude, avgbinnum). Each bin contributes a vector of length equal to its value, at a direction corresponding to the bin number. Specifically, the total bin number range is mapped into a direction range [0,2pi]. For a cyclic distribution, the avgbinnum will be a continuous measure analogous to the max_value_bin() of the distribution. But this quantity has more precision than max_value_bin() because it is computed from the entire distribution instead of just the peak bin. However, it is likely to be useful only for uniform or very dense sampling; with sparse, non-uniform sampling the estimates will be biased significantly by the particular samples chosen. The avgbinnum is not meaningful when the magnitude is 0, because a zero-length vector has no direction. To find out whether such cases occurred, you can compare the value of undefined_vals before and after a series of calls to this function. """ # vectors are represented in polar form as complex numbers h = d._data r = h.values() theta = d._bins_to_radians(array(h.keys())) v_sum = innerproduct(r, exp(theta * 1j)) magnitude = abs(v_sum) direction = arg(v_sum) if v_sum == 0: d.undefined_vals += 1 direction_radians = d._radians_to_bins(direction) # wrap the direction because arctan2 returns principal values wrapped_direction = wrap(d.axis_bounds[0], d.axis_bounds[1], direction_radians) return (magnitude, wrapped_direction)
def vector_sum(self, d ): """ Return the vector sum of the distribution as a tuple (magnitude, avgbinnum). Each bin contributes a vector of length equal to its value, at a direction corresponding to the bin number. Specifically, the total bin number range is mapped into a direction range [0,2pi]. For a cyclic distribution, the avgbinnum will be a continuous measure analogous to the max_value_bin() of the distribution. But this quantity has more precision than max_value_bin() because it is computed from the entire distribution instead of just the peak bin. However, it is likely to be useful only for uniform or very dense sampling; with sparse, non-uniform sampling the estimates will be biased significantly by the particular samples chosen. The avgbinnum is not meaningful when the magnitude is 0, because a zero-length vector has no direction. To find out whether such cases occurred, you can compare the value of undefined_vals before and after a series of calls to this function. """ # vectors are represented in polar form as complex numbers h = d._data r = h.values() theta = d._bins_to_radians(array( h.keys() )) v_sum = innerproduct(r, exp(theta*1j)) magnitude = abs(v_sum) direction = arg(v_sum) if v_sum == 0: d.undefined_vals += 1 direction_radians = d._radians_to_bins(direction) # wrap the direction because arctan2 returns principal values wrapped_direction = wrap(d.axis_bounds[0], d.axis_bounds[1], direction_radians) return (magnitude, wrapped_direction)
def weighted_sum(self): """Return the sum of each value times its bin.""" return innerproduct(self._data.keys(), self._data.values())
def Add_Nucleic_Bases(g, properties=None): """ Adds Nucleic Bases to g. g is a geometry created in Pmv.secondaryStructureCommands properties is class that holds information about Nucleic Acids colors and size """ path3D = g.SS.exElt.path3D residues = g.SS.residues total_res = len(residues) vertex_count = 0 vertices = [] res_faces = [] materials = [] height_purine = height_pyrimidine = 0.4 if properties: color_A = properties.color_A color_G = properties.color_G color_T = properties.color_T color_C = properties.color_C color_U = properties.color_U scale_purine = properties.scale_purine scale_pyrimidine = properties.scale_pyrimidine height_purine = properties.height_purine height_pyrimidine = properties.height_pyrimidine else: color_A = [1, 0, 0] color_G = [0, 0, 1] color_T = [0, 1, 0] color_C = [1, 1, 0] color_U = [1, 0.5, 0] scale_purine = scale_pyrimidine = 1.3 height_purine = height_pyrimidine = 0.4 for i in range(total_res): faces = [] NA_type = residues[i].type.strip() l_c = g.SS.exElt.getExtrudeProperties( [residues[i]], 'colors', ) #if missing atoms do not do the base if NA_type in ['A', 'G', 'DA', 'DG']: if checkMissingAtoms(residues[i], [ 'N1.*', 'C2.*', 'N9.*', 'N7.*', 'C8.*', 'C4.*', 'C5.*', 'C6.*', 'N3.*' ]): print("missing atoms in", residues[i]) residues[i]._base_faces = [] residues[i]._coil_colors = len(l_c) * [color_A] continue base_vertices, base_faces = make_purine(residues[i], height_purine, scale_purine) pscale = scale_purine if NA_type in ['A', 'DA']: #28 = number of vertices for the base 20 + 8 materials.extend(28 * [color_A]) residues[i]._coil_colors = len(l_c) * [color_A] elif NA_type in ['G', 'DG']: materials.extend(28 * [color_G]) residues[i]._coil_colors = len(l_c) * [color_G] names = [name.split("@")[0] for name in residues[i].atoms.name] idx = names.index('N9') connetct_to_base = Numeric.array(residues[i].atoms[idx].coords) else: if checkMissingAtoms( residues[i], ['N1.*', 'C2.*', 'N3.*', 'C4.*', 'C5.*', 'C6.*']): print("missing atoms in", residues[i]) residues[i]._base_faces = [] residues[i]._coil_colors = len(l_c) * [color_A] continue base_vertices, base_faces = make_pyrimidine( residues[i], height_pyrimidine, scale_pyrimidine) pscale = 0.9 * scale_pyrimidine if NA_type == 'T': #22 = number of vertices for the base 14 + 8 materials.extend(22 * [color_T]) residues[i]._coil_colors = len(l_c) * [color_T] elif NA_type in ['C', 'DC']: materials.extend(22 * [color_C]) residues[i]._coil_colors = len(l_c) * [color_C] elif NA_type == 'U': materials.extend(22 * [color_U]) residues[i]._coil_colors = len(l_c) * [color_U] else: materials.extend(22 * [color_U]) residues[i]._coil_colors = len(l_c) * [color_U] names = [name.split("@")[0] for name in residues[i].atoms.name] idx = names.index('N1') connetct_to_base = Numeric.array(residues[i].atoms[idx].coords) vertices.extend(base_vertices.tolist()) # v5 *-----------*v1 # /| /| # / | / | # / | / | # v6*-----------*v2 | # path-----|-- | | --|--->connetct_to_base # | *-------|---*v0 # | /v4 | / # | / | / # |/ |/ # *-----------* # v7 v3 O4 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'O4').coords) C4 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'C4').coords) C1 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'C1').coords) C3 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'C3').coords) C2 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'C2').coords) #cent is a vector towards which bases are extruded cent = C4 #this was a center of the sugar ring #copy is needed were, otherwise base_vertices will get changed too v_4 = copy(base_vertices[-4]) v_5 = copy(base_vertices[-3]) v_6 = copy(base_vertices[-2]) v_7 = copy(base_vertices[-1]) dist = (v_5 + v_4 + v_6 + v_7) / 4.0 - cent if i == total_res - 1: pathPoint = path3D[4 * i] else: pathPoint = path3D[4 * i + 1] #here we measure distance between backbone and last 4 vertices of bases d_v = v_4 - pathPoint distToV_4 = Numeric.innerproduct(d_v, d_v) d_v = v_5 - pathPoint distToV_5 = Numeric.innerproduct(d_v, d_v) d_v = v_6 - pathPoint distToV_6 = Numeric.innerproduct(d_v, d_v) d_v = v_7 - pathPoint distToV_7 = Numeric.innerproduct(d_v, d_v) distList1 = [distToV_4, distToV_5, distToV_6, distToV_7] distList2 = [distToV_4, distToV_5, distToV_6, distToV_7] distList1.sort() if pscale > 1: pscale *= pscale for enum in enumerate(distList2): if enum[1] == distList1[0]: distList2[enum[0]] = 0.1 * pscale elif enum[1] == distList1[1]: distList2[enum[0]] = 0.1 * pscale elif enum[1] == distList1[2]: distList2[enum[0]] = 0.5 * pscale elif enum[1] == distList1[3]: distList2[enum[0]] = 0.5 * pscale #max_d = max([distToV_4,distToV_5,distToV_6,distToV_7]) #dist needs to be scaled so that connection to the backbone wont be thin v_4 = v_4 - distList2[0] * dist vertices.append(v_4.tolist()) v_5 = v_5 - distList2[1] * dist vertices.append(v_5.tolist()) v_6 = v_6 - distList2[2] * dist vertices.append(v_6.tolist()) v_7 = v_7 - distList2[3] * dist vertices.append(v_7.tolist()) p_1 = copy(v_4) p_2 = copy(v_5) p_3 = copy(v_6) p_4 = copy(v_7) dToBase = (p_1 + p_2 + p_3 + p_4) / 4. - pathPoint p_1 = p_1 - dToBase p_2 = p_2 - dToBase p_3 = p_3 - dToBase p_4 = p_4 - dToBase #base_face are number from 0, we need to add vertex_count here base_faces += vertex_count faces.extend(base_faces.tolist()) #now do the faces len_base_vertices = len(base_vertices) stem_start = vertex_count + len_base_vertices - 4 faces.append([ stem_start + 1, stem_start + 5, stem_start + 4, stem_start, stem_start, stem_start, stem_start ]) faces.append([ stem_start + 1, stem_start + 2, stem_start + 6, stem_start + 5, stem_start + 5, stem_start + 5, stem_start + 5 ]) faces.append([ stem_start, stem_start + 4, stem_start + 7, stem_start + 3, stem_start + 3, stem_start + 3, stem_start + 3 ]) faces.append([ stem_start + 2, stem_start + 3, stem_start + 7, stem_start + 6, stem_start + 6, stem_start + 6, stem_start + 6 ]) faces.append([ stem_start + 7, stem_start + 4, stem_start + 5, stem_start + 6, stem_start + 6, stem_start + 6, stem_start + 6 ]) vertices.append(p_1.tolist()) vertices.append(p_2.tolist()) vertices.append(p_3.tolist()) vertices.append(p_4.tolist()) stem_start += 4 faces.append([ stem_start + 1, stem_start + 5, stem_start + 4, stem_start, stem_start, stem_start, stem_start ]) faces.append([ stem_start + 1, stem_start + 2, stem_start + 6, stem_start + 5, stem_start + 5, stem_start + 5, stem_start + 5 ]) faces.append([ stem_start, stem_start + 4, stem_start + 7, stem_start + 3, stem_start + 3, stem_start + 3, stem_start + 3 ]) faces.append([ stem_start + 2, stem_start + 3, stem_start + 7, stem_start + 6, stem_start + 6, stem_start + 6, stem_start + 6 ]) faces.append([ stem_start + 7, stem_start + 4, stem_start + 5, stem_start + 6, stem_start + 6, stem_start + 6, stem_start + 6 ]) # #1-2-6-5 # faces.append([stem_start + 7, stem_start + 8,stem_start + 12,stem_start+11, # stem_start+11,stem_start+11,stem_start+11]) # #1-4-8-5 # faces.append([stem_start+7, stem_start+10,stem_start + 14,stem_start + 11, # stem_start + 11,stem_start + 11,stem_start + 11]) # #3-4-8-7 # faces.append([stem_start+9, stem_start+10, stem_start + 14, stem_start + 13, # stem_start + 13,stem_start + 13,stem_start + 13]) # #2-3-7-6 # faces.append([stem_start+8, stem_start+9,stem_start + 13,stem_start + 12, # stem_start + 12,stem_start + 12,stem_start + 12]) vertex_count = vertex_count + len_base_vertices + 8 residues[i]._base_faces = faces faces = [] for residue in residues: faces.extend(residue._base_faces) geom_bases = IndexedPolygons( 'Bases', vertices=vertices, faces=faces, inheritShading=False, shading=GL.GL_FLAT, materials=materials, inheritMaterial=False, ) return geom_bases
def Add_Nucleic_Bases(g, properties = None): """ Adds Nucleic Bases to g. g is a geometry created in Pmv.secondaryStructureCommands properties is class that holds information about Nucleic Acids colors and size """ path3D = g.SS.exElt.path3D residues = g.SS.residues total_res = len(residues) vertex_count = 0 vertices = [] res_faces = [] materials = [] height_purine = height_pyrimidine = 0.4 if properties: color_A = properties.color_A color_G = properties.color_G color_T = properties.color_T color_C = properties.color_C color_U = properties.color_U scale_purine = properties.scale_purine scale_pyrimidine = properties.scale_pyrimidine height_purine = properties.height_purine height_pyrimidine = properties.height_pyrimidine else: color_A = [1,0,0] color_G = [0,0,1] color_T = [0,1,0] color_C = [1,1,0] color_U = [1,0.5,0] scale_purine = scale_pyrimidine = 1.3 height_purine = height_pyrimidine = 0.4 for i in range(total_res): faces = [] NA_type = residues[i].type.strip() l_c = g.SS.exElt.getExtrudeProperties([residues[i]], 'colors', ) #if missing atoms do not do the base if NA_type in ['A', 'G', 'DA', 'DG']: if checkMissingAtoms(residues[i],['N1.*','C2.*','N9.*','N7.*','C8.*', 'C4.*','C5.*','C6.*','N3.*' ]) : print ("missing atoms in",residues[i]) residues[i]._base_faces = [] residues[i]._coil_colors = len(l_c)*[color_A] continue base_vertices, base_faces = make_purine(residues[i], height_purine, scale_purine) pscale = scale_purine if NA_type in ['A', 'DA']: #28 = number of vertices for the base 20 + 8 materials.extend(28*[color_A]) residues[i]._coil_colors = len(l_c)*[color_A] elif NA_type in ['G', 'DG']: materials.extend(28*[color_G]) residues[i]._coil_colors = len(l_c)*[color_G] names = [name.split("@")[0] for name in residues[i].atoms.name] idx=names.index('N9') connetct_to_base = Numeric.array(residues[i].atoms[idx].coords) else: if checkMissingAtoms(residues[i],['N1.*','C2.*','N3.*','C4.*', 'C5.*','C6.*']) : print ("missing atoms in",residues[i]) residues[i]._base_faces = [] residues[i]._coil_colors = len(l_c)*[color_A] continue base_vertices, base_faces = make_pyrimidine(residues[i], height_pyrimidine, scale_pyrimidine) pscale = 0.9*scale_pyrimidine if NA_type == 'T': #22 = number of vertices for the base 14 + 8 materials.extend(22*[color_T]) residues[i]._coil_colors = len(l_c)*[color_T] elif NA_type in ['C', 'DC']: materials.extend(22*[color_C]) residues[i]._coil_colors = len(l_c)*[color_C] elif NA_type == 'U': materials.extend(22*[color_U]) residues[i]._coil_colors = len(l_c)*[color_U] else: materials.extend(22*[color_U]) residues[i]._coil_colors = len(l_c)*[color_U] names = [name.split("@")[0] for name in residues[i].atoms.name] idx=names.index('N1') connetct_to_base = Numeric.array(residues[i].atoms[idx].coords) vertices.extend(base_vertices.tolist()) # v5 *-----------*v1 # /| /| # / | / | # / | / | # v6*-----------*v2 | # path-----|-- | | --|--->connetct_to_base # | *-------|---*v0 # | /v4 | / # | / | / # |/ |/ # *-----------* # v7 v3 O4 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'O4').coords) C4 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'C4').coords) C1 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'C1').coords) C3 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'C3').coords) C2 = Numeric.array(returnStarOrQuote(residues[i].atoms, 'C2').coords) #cent is a vector towards which bases are extruded cent = C4 #this was a center of the sugar ring #copy is needed were, otherwise base_vertices will get changed too v_4 = copy(base_vertices[-4]); v_5 = copy(base_vertices[-3]) v_6 = copy(base_vertices[-2]); v_7 = copy(base_vertices[-1]) dist = (v_5+v_4+v_6+v_7)/4.0 - cent if i == total_res - 1: pathPoint = path3D[4*i] else: pathPoint = path3D[4*i+1] #here we measure distance between backbone and last 4 vertices of bases d_v = v_4 - pathPoint distToV_4 = Numeric.innerproduct(d_v,d_v) d_v = v_5 - pathPoint distToV_5 = Numeric.innerproduct(d_v,d_v) d_v = v_6 - pathPoint distToV_6 = Numeric.innerproduct(d_v,d_v) d_v = v_7 - pathPoint distToV_7 = Numeric.innerproduct(d_v,d_v) distList1 = [distToV_4,distToV_5,distToV_6,distToV_7] distList2 = [distToV_4,distToV_5,distToV_6,distToV_7] distList1.sort() if pscale > 1: pscale *= pscale for enum in enumerate(distList2): if enum[1] == distList1[0]: distList2[enum[0]] = 0.1*pscale elif enum[1] == distList1[1]: distList2[enum[0]] = 0.1*pscale elif enum[1] == distList1[2]: distList2[enum[0]] = 0.5*pscale elif enum[1] == distList1[3]: distList2[enum[0]] = 0.5*pscale #max_d = max([distToV_4,distToV_5,distToV_6,distToV_7]) #dist needs to be scaled so that connection to the backbone wont be thin v_4 = v_4 - distList2[0]*dist vertices.append(v_4.tolist()) v_5 = v_5 - distList2[1]*dist vertices.append(v_5.tolist()) v_6 = v_6 - distList2[2]*dist vertices.append(v_6.tolist()) v_7 = v_7 - distList2[3]*dist vertices.append(v_7.tolist()) p_1 = copy(v_4) p_2 = copy(v_5) p_3 = copy(v_6) p_4 = copy(v_7) dToBase = (p_1+p_2+p_3+p_4)/4. - pathPoint p_1 = p_1 - dToBase p_2 = p_2 - dToBase p_3 = p_3 - dToBase p_4 = p_4 - dToBase #base_face are number from 0, we need to add vertex_count here base_faces += vertex_count faces.extend(base_faces.tolist()) #now do the faces len_base_vertices = len(base_vertices) stem_start = vertex_count + len_base_vertices - 4 faces.append([stem_start + 1, stem_start + 5,stem_start + 4,stem_start, stem_start,stem_start,stem_start]) faces.append([stem_start+1, stem_start+2,stem_start + 6,stem_start + 5, stem_start + 5,stem_start + 5,stem_start + 5]) faces.append([stem_start, stem_start+4, stem_start + 7, stem_start + 3, stem_start + 3,stem_start + 3,stem_start + 3]) faces.append([stem_start+2, stem_start+3,stem_start + 7,stem_start + 6, stem_start + 6,stem_start + 6,stem_start + 6]) faces.append([stem_start+7, stem_start+4,stem_start + 5,stem_start + 6, stem_start + 6,stem_start + 6,stem_start + 6]) vertices.append(p_1.tolist()) vertices.append(p_2.tolist()) vertices.append(p_3.tolist()) vertices.append(p_4.tolist()) stem_start += 4 faces.append([stem_start + 1, stem_start + 5,stem_start + 4,stem_start, stem_start,stem_start,stem_start]) faces.append([stem_start+1, stem_start+2,stem_start + 6,stem_start + 5, stem_start + 5,stem_start + 5,stem_start + 5]) faces.append([stem_start, stem_start+4, stem_start + 7, stem_start + 3, stem_start + 3,stem_start + 3,stem_start + 3]) faces.append([stem_start+2, stem_start+3,stem_start + 7,stem_start + 6, stem_start + 6,stem_start + 6,stem_start + 6]) faces.append([stem_start+7, stem_start+4,stem_start + 5,stem_start + 6, stem_start + 6,stem_start + 6,stem_start + 6]) # #1-2-6-5 # faces.append([stem_start + 7, stem_start + 8,stem_start + 12,stem_start+11, # stem_start+11,stem_start+11,stem_start+11]) # #1-4-8-5 # faces.append([stem_start+7, stem_start+10,stem_start + 14,stem_start + 11, # stem_start + 11,stem_start + 11,stem_start + 11]) # #3-4-8-7 # faces.append([stem_start+9, stem_start+10, stem_start + 14, stem_start + 13, # stem_start + 13,stem_start + 13,stem_start + 13]) # #2-3-7-6 # faces.append([stem_start+8, stem_start+9,stem_start + 13,stem_start + 12, # stem_start + 12,stem_start + 12,stem_start + 12]) vertex_count = vertex_count + len_base_vertices + 8 residues[i]._base_faces = faces faces = [] for residue in residues: faces.extend(residue._base_faces) geom_bases = IndexedPolygons('Bases', vertices=vertices, faces=faces, inheritShading = False,shading = GL.GL_FLAT, materials = materials, inheritMaterial = False,) return geom_bases
def __init__(self, points, k, normalization=NORM_NORM_T0_1, force=False): """ calculate k polynomials of degree 0 to k-1 orthogonal on a set of distinct points map points to interval [-1,1] INPUT: points: array of dictinct points where polynomials are orthogonal k: number of polynomials of degree 0 to k-1 force=True creates basis even if orthogonality is not satisfied due to numerical error USES: x: array of points mapped to [-1,1] T_: matrix of values of polynomials calculated at x, shape (k,len(x)) TT_ = T_ * Numeric.transpose(T_) TTinv_ = inverse(TT_) sc_: scaling factors a, b: coefficients for calculating T (2k-4 different from 0, i.e. 6 for k=5) n: number of points = len(points) normalization = {0|1|2} """ self.k = k # number of basis polynomials of order 0 to k-1 self._force = force self.points = Numeric.asarray(points, Numeric.Float) self.pointsMin = min(points) self.pointsMax = max(points) # scaling x to [-1,1] results in smaller a and b, T is not affected; overflow is NOT a problem! self.xMin = -1 self.xMax = 1 self.x = self._map(self.points, self.pointsMin, self.pointsMax, self.xMin, self.xMax) # calculate basis polynomials self.n = len(points) # the number of approximation points t = Numeric.zeros((k, self.n), Numeric.Float) a = Numeric.zeros((k, 1), Numeric.Float) b = Numeric.zeros((k, 1), Numeric.Float) t[0, :] = Numeric.ones(self.n, Numeric.Float) if k > 1: t[1, :] = self.x - sum(self.x) / self.n for i in range(1, k - 1): a[i + 1] = Numeric.innerproduct( self.x, t[i, :] * t[i, :]) / Numeric.innerproduct( t[i, :], t[i, :]) b[i] = Numeric.innerproduct(t[i, :], t[i, :]) / Numeric.innerproduct( t[i - 1, :], t[i - 1, :]) t[i + 1, :] = (self.x - a[i + 1]) * t[i, :] - b[i] * t[i - 1, :] self.a = a self.b = b # prepare for approximation self._T0 = t # orthonormal _TT0 = Numeric.matrixmultiply(self._T0, Numeric.transpose(self._T0)) self.sc1 = Numeric.sqrt( Numeric.reshape( Numeric.diagonal(_TT0), (self.k, 1))) # scaling factors = sqrt sum squared self._T0 self._T1 = self._T0 / self.sc1 # orthonormal and T[0] == 1 self.sc2 = Numeric.sqrt( Numeric.reshape(Numeric.diagonal(_TT0), (self.k, 1)) / self.n) # scaling factors = sqrt 1/n * sum squared self._T0 self._T2 = self._T0 / self.sc2 # T[:,-1] == 1 self.sc3 = Numeric.take(self._T0, (-1, ), 1) # scaling factors = self._T0[:,-1] self._T3 = self._T0 / self.sc3 # set the variables according to the chosen normalization self.setNormalization(normalization)