def __matmul__(self, other): """ Multiplication of two TT-matrices """ diff = len(self.n) - len(other.m) L = self if diff >= 0 else _tools.kron(self, matrix(_tools.ones(1, abs(diff)))) R = other if diff <= 0 else _tools.kron(other, matrix(_tools.ones(1, abs(diff)))) c = matrix() c.n = L.n.copy() c.m = R.m.copy() res = _vector.vector() res.d = L.tt.d res.n = c.n * c.m if L.is_complex or R.is_complex: res.r = _core_f90.core.zmat_mat( L.n, L.m, R.m, _np.array( L.tt.core, dtype=_np.complex), _np.array( R.tt.core, dtype=_np.complex), L.tt.r, R.tt.r) res.core = _core_f90.core.zresult_core.copy() else: res.r = _core_f90.core.dmat_mat( L.n, L.m, R.m, _np.real( L.tt.core), _np.real( R.tt.core), L.tt.r, R.tt.r) res.core = _core_f90.core.result_core.copy() _core_f90.core.dealloc() res.get_ps() c.tt = res return c
def __kron__(self, other): """ Kronecker product of two TT-matrices """ if other is None: return self a = self b = other c = matrix() c.n = _np.concatenate((a.n, b.n)) c.m = _np.concatenate((a.m, b.m)) c.tt = _tools.kron(a.tt, b.tt) return c
def evaluate_mode(self, l, m, *args, **kwargs): """ evaluate (l,m) mode and return FieldOut input: spectral coefficients: dataT, dataP, physical grid: r, theta, phi0 kron: 'meridional' or 'equatorial' outpu: FieldOut e.g: evaluate_mode(l, m, FieldOut, dataT[i, :], dataP[i, :], r, theta, kron='meridional', phi0=p) """ #print(l, m) # raise exception if wrong geometry if not (self.geometry == 'shell' or self.geometry == 'sphere'): raise NotImplementedError('makeMeridionalSlice is not implemented for the geometry: '+self.geometry) # prepare the input data #Evaluated fields Field_r = args[0][0] Field_theta = args[0][1] Field_phi = args[0][2] #spectral coefficients modeT = args[1] modeP = args[2] #grid points r = args[3] theta = args[4] phi = args[5] phi0 = kwargs['phi0'] # define factor factor = 1. if m==0 else 2. if kwargs['kron'] == 'isogrid' or kwargs['kron'] == 'points': x = kwargs['x'] if self.geometry == 'shell': # assume that the mode is weighted like Philippe sets it modeP[1:] *= 2. modeT[1:] *= 2. # prepare the q_part modeP_r = cheb.chebval(x, modeP)/r q_part = modeP_r * l*(l+1) # prepare the s_part dP = np.zeros_like(modeP) d_temp = cheb.chebder(modeP) dP[:len(d_temp)] = d_temp s_part = modeP_r + cheb.chebval(x, dP)/self.a # prepare the t_part t_part = cheb.chebval(x, modeT) elif self.geometry == 'sphere': #TODO: Leo q_part = None s_part = None t_part = None else: # hence either meridional or equatorial if self.geometry == 'shell': # prepare the q_part # q = l*(l+1) * Poloidal / r # idct: inverse discrete cosine transform # type = 2: type of transform # q = Field_radial # prepare the q_part # idct = \sum c_n * T_n(xj) modeP_r = idct(modeP, type = 2)/r q_part = modeP_r * l*(l+1) # prepare the s_part # s_part = orthogonal to Field_radial and Field_Toroidal # s_part = (Poloidal)/r + d(Poloidal)/dr = 1/r d(Poloidal)/dr dP = np.zeros_like(modeP) d_temp = cheb.chebder(modeP) dP[:len(d_temp)] = d_temp s_part = modeP_r + idct(dP, type = 2)/self.a # prepare the t_part # t_part = Field_Toroidal t_part = idct(modeT, type = 2) elif self.geometry == 'sphere': #TODO: Leo, Where do you get this??? #print('modeP:', modeP.shape, modeP) #32 #print('modeT:', modeT.shape, modeT) #32 #print('r:',r.shape, r) # 64 #print('specRes:',self.specRes) modeP_r = np.zeros_like(r) dP = np.zeros_like(r) t_part = np.zeros_like(r) for n in range(self.specRes.N): modeP_r=modeP_r+modeP[n]*wor.W(n, l, r)/r dP = dP+modeP[n]*wor.diffW(n, l, r) t_part = t_part + modeT[n]*wor.W(n,l,r) q_part = modeP_r*l*(l+1)#same stuff s_part = modeP_r + dP # depending on the kron type it changes how 2d data are formed # Mapping from qst to r,theta, phi # phi0: azimuthal angle of meridional plane. It's also the phase shift of the flow with respect to the mantle frame, if kwargs['kron'] == 'meridional': eimp = np.exp(1j * m * phi0) idx_ = self.idx[l, m] Field_r += np.real(tools.kron(q_part, self.Plm[idx_, :]) * eimp) * factor Field_theta += np.real(tools.kron(s_part, self.dPlm[idx_, :]) * eimp) * 2 Field_theta += np.real(tools.kron(t_part, self.Plm_sin[idx_, :]) * eimp * 1j * m) * 2#factor Field_phi += np.real(tools.kron(s_part, self.Plm_sin[idx_, :]) * eimp * 1j * m) * 2#factor Field_phi -= np.real(tools.kron(t_part, self.dPlm[idx_, :]) * eimp) * 2 elif kwargs['kron'] == 'points': eimp = np.exp(1j * m * phi) idx_ = self.idx[l, m] Field_r += np.real(q_part * self.Plm[idx_, :] * eimp) * factor Field_theta += np.real(s_part * self.dPlm[idx_, :] * eimp) * 2 Field_theta += np.real(t_part * self.Plm_sin[idx_, :] * eimp * 1j * m) * 2#factor Field_phi += np.real(s_part * self.Plm_sin[idx_, :] * eimp * 1j * m) * 2#factor Field_phi -= np.real(t_part * self.dPlm[idx_, :] * eimp) * 2 elif kwargs['kron'] == 'equatorial': """ eimp = np.exp(1j * m * (phi0 + phi)) idx_ = self.idx[l, m] Field_r += np.real(tools.kron(q_part, eimp) * self.Plm[idx_, :][0]) * factor Field_theta += np.real(tools.kron(s_part, eimp)) * self.dPlm[idx_, :][0] * 2 Field_theta += np.real(tools.kron(t_part, eimp) * 1j * m) * self.Plm_sin[idx_, :][0] * 2#factor Field_phi += np.real(tools.kron(s_part, eimp) * 1j * m) * self.Plm_sin[idx_, :][0] * 2#factor Field_phi -= np.real(tools.kron(t_part, eimp)) * self.dPlm[idx_, :][0] * 2 """ idx_ = self.idx[l, m] #Field_r += np.real(tools.kron(self.Plm[idx_, :], eimp) * q_part) * factor Field_r[:, m] += self.Plm[idx_, :] * q_part #Field_theta += np.real(tools.kron(self.dPlm[idx_, :], eimp) * s_part) * 2 Field_theta[:, m] += self.dPlm[idx_, :] * s_part #Field_theta += np.real(tools.kron(self.Plm_sin[idx_, :], eimp * 1j * m) * t_part) * 2#factor Field_theta[:, m] += self.Plm_sin[idx_, :] * 1j * m * t_part #Field_phi += np.real(tools.kron(self.Plm_sin[idx_, :], eimp * 1j * m) * s_part) * 2#factor Field_phi[:, m] += self.Plm_sin[idx_, :]* 1j * m * s_part #Field_phi -= np.real(tools.kron(self.dPlm[idx_, :], eimp) * t_part) * 2 Field_phi[:, m] -= self.dPlm[idx_, :] * t_part elif kwargs['kron'] == 'isogrid': #eimp = np.exp(1j * m * (phi0 + phi)) idx_ = self.idx[l, m] #Field_r += np.real(tools.kron(self.Plm[idx_, :], eimp) * q_part) * factor Field_r[:, m] += self.Plm[idx_, :] * q_part #Field_theta += np.real(tools.kron(self.dPlm[idx_, :], eimp) * s_part) * 2 Field_theta[:, m] += self.dPlm[idx_, :] * s_part #Field_theta += np.real(tools.kron(self.Plm_sin[idx_, :], eimp * 1j * m) * t_part) * 2#factor Field_theta[:, m] += self.Plm_sin[idx_, :] * 1j * m * t_part #Field_phi += np.real(tools.kron(self.Plm_sin[idx_, :], eimp * 1j * m) * s_part) * 2#factor Field_phi[:, m] += self.Plm_sin[idx_, :]* 1j * m * s_part #Field_phi -= np.real(tools.kron(self.dPlm[idx_, :], eimp) * t_part) * 2 Field_phi[:, m] -= self.dPlm[idx_, :] * t_part else: raise ValueError('Kron type not understood: '+kwargs['kron']) pass