def __init__(self, T, P, mezcla): self.T = unidades.Temperature(T) self.P = unidades.Pressure(P, "atm") self.mezcla = mezcla self.componente = mezcla.componente self.fraccion = mezcla.fraccion self.B = self.b * self.P.atm / R_atml / self.T self.Tita = self.tita * self.P.atm / (R_atml * self.T)**2 delta = self.delta * self.P.atm / R_atml / self.T epsilon = self.epsilon * (self.P.atm / R_atml / self.T)**2 eta = self.eta * self.P.atm / R_atml / self.T Z = roots([ 1, delta - self.B - 1, self.Tita + epsilon - delta * (self.B + 1), -epsilon * (self.B + 1) - self.Tita * eta ]) self.Z = r_[Z[0].real, Z[2].real] self.V = self.Z * R_atml * self.T / self.P.atm #mol/l self.x, self.xi, self.yi, self.Ki = self._Flash() self.H_exc = -(self.tita + self.dTitadT) / R_atml / self.T / ( self.delta**2 - 4 * self.epsilon)**0.5 * log( (2 * self.V + self.delta - (self.delta**2 - 4 * self.epsilon)**0.5) / (2 * self.V + self.delta + (self.delta**2 - 4 * self.epsilon)**0.5)) + 1 - self.Z
def dispersion_relation_extraordinary(kx, ky, k, nO, nE, c): """Dispersion relation for the extraordinary wave. NOTE See eq. 16 in Glytsis, "Three-dimensional (vector) rigorous coupled-wave analysis of anisotropic grating diffraction", JOSA A, 7(8), 1990 Always give positive real or negative imaginary. """ if kx.shape != ky.shape or c.size != 3: raise ValueError('kx and ky must have the same length and c must have 3 components') kz = S.empty_like(kx) for ii in xrange(0, kx.size): alpha = nE**2 - nO**2 beta = kx[ii]/k * c[0] + ky[ii]/k * c[1] # coeffs C = S.array([nO**2 + c[2]**2 * alpha, \ 2. * c[2] * beta * alpha, \ nO**2 * (kx[ii]**2 + ky[ii]**2) / k**2 + alpha * beta**2 - nO**2 * nE**2]) # two solutions of type +x or -x, purely real or purely imag tmp_kz = k * S.roots(C) # get the negative imaginary part or the positive real one if S.any(S.isreal(tmp_kz)): kz[ii] = S.absolute(tmp_kz[0]) else: kz[ii] = -1j * S.absolute(tmp_kz[0]) return kz
def __init__(self, T, P, mezcla): P_atm = P/101325 self.T = unidades.Temperature(T) self.P = unidades.Pressure(P) self.mezcla = mezcla self.componente = mezcla.componente self.zi = mezcla.fraccion self.B = self.b*P/R/T self.Tita = self.tita*P/(R*T)**2 delta = self.delta*P/R/T epsilon = self.epsilon*(P/R/T)**2 # δ1, δ2 calculated from polynomial factorization self.delta1 = ((self.delta**2-4*self.epsilon)**0.5-self.delta)/2/self.b self.delta2 = ((self.delta**2-4*self.epsilon)**0.5+self.delta)/2/self.b # Eq 4-6.3 in [1]_ coeff = [1, delta-self.B-1, self.Tita+epsilon-delta*(self.B+1), -epsilon*(self.B+1)-self.Tita*self.B] Z = roots(coeff) # print("Z", Z) # TODO: use the anallycal solution, Span, pag 50 # Set the minimum and maximum root values as liquid and gas Z values self.Z = r_[Z[0].real, Z[2].real] self.Zl = min(Z).real self.Zg = max(Z).real self.V = self.Z*R_atml*T/P_atm # l/mol self.rho = 1/self.V self.Vl = unidades.MolarVolume(self.Zl*R*T/P, "m3mol") # l/mol self.Vg = unidades.MolarVolume(self.Zg*R*T/P, "m3mol") # l/mol
def npred(cev): rts = sp.roots([p[3] / 4., p[2] / 3., p[1] / 2., p[0] + cev, -C]) nmax = max([sp.real(i) for i in rts if sp.isreal(i)]) cbar = p[0] + p[1] * nmax / 2. + p[2] * (nmax**2) / 3. + p[3] * ( nmax**3) / 4. return nmax, cbar
def vanderwaals(phase, P, T, Pc, Tc, MW, **kwargs): r""" Uses Van der Waals equation of state to calculate the density of a real gas Parameters ---------- P, T, Pc, Tc, MW: float, array_like P pressure of the gas in [Pa] T temperature of the gas in [K] Pc critical pressure of the gas in [Pa] T critical temperature of the gas in [K] MW molecular weight of the gas in [kg/mol] Returns ------- rho, the density in [mol/m3] """ P = phase['pore.pressure'] T = phase['pore.temperature'] Pc = phase['pore.criticalpressure'] Tc = phase['pore.criticaltemperature'] R = 8.314 a = 27 * (R**2) * (Tc**2) / (64 * Pc) b = R * Tc / (8 * Pc) a0 = 1 a1 = -1 / b a2 = (R * T + b * P) / (a * b) a3 = -P / (a * b) density = sp.roots([a0, a1, a2, a3]) value = sp.real(density[2]) return value
def _lib(self, cmp, T): if cmp.id in dat: # Use the compound specific parameters values xic, f = dat[cmp.id] else: # Use the generalization correlations, Eq 20-21 f = 0.452413 + 1.30982 * cmp.f_acent - 0.295937 * cmp.f_acent**2 xic = 0.329032 - 0.076799 * cmp.f_acent + 0.0211947 * cmp.f_acent**2 # Eq 8 c = (1 - 3 * xic) * R * cmp.Tc / cmp.Pc # Eq 10 b = roots([1, 2 - 3 * xic, 3 * xic**2, -xic**3]) Bpositivos = [] for i in b: if i > 0: Bpositivos.append(i) Omegab = min(Bpositivos) b = Omegab * R * cmp.Tc / cmp.Pc # Eq 9 Omegaa = 3 * xic**2 + 3 * (1 - 2 * xic) * Omegab + Omegab**2 + 1 - 3 * xic if cmp.id in PT2: # Using improved alpha correlation from [2]_ c1, c2, c3, n = PT2[cmp.id] alfa = 1 + c1*(T/cmp.Tc-1) + c2*((T/cmp.Tc)**0.5-1) + \ c3*((T/cmp.Tc)**n-1) else: alfa = (1 + f * (1 - (T / cmp.Tc)**0.5))**2 a = Omegaa * alfa * R**2 * cmp.Tc**2 / cmp.Pc return a, b, c
def quadfit(lowerLimit, upperLimit, x,y): import scipy from scipy.optimize import leastsq y = y[lowerLimit:upperLimit] x = x[lowerLimit:upperLimit] maxY = max(y) p0 = array([-276025.,1051.,1.]) plsq = leastsq(quadresiduals, p0, args=(y, x), maxfev=2000) rplsq = [] i=1 while i <= len(plsq[0]): rplsq.append(plsq[0][-i]) i = i+1 diff = scipy.polyder(rplsq,1) roots = scipy.roots(diff) peak = 0 for root in roots: if root < x[-1] and root > x[0]: peak = root fit = [] for i in x: fit.append((i,quadfunction(i,plsq[0]))) return float(real(peak))
def polyint(lowerLimit, upperLimit, x, y): import scipy from scipy.optimize import leastsq y = y[lowerLimit:upperLimit] x = x[lowerLimit:upperLimit] maxY = max(y) p0 = array([-276025,1051,-1,1,100]) plsq = leastsq(polyresiduals, p0, args=(y, x), maxfev=2000) rplsq = [] i=1 while i <= len(plsq[0]): rplsq.append(plsq[0][-i]) i = i+1 diff = scipy.polyder(rplsq,1) roots = scipy.roots(diff) peak = 0 for root in roots: if root < x[-1] and root > x[0]: peak = root peakIntensity = polyfunction(peak,plsq[0]) return float(real(peakIntensity))
def test_roots(self): polinomio = [1.3, 4, .6, -1] # polinomio = 1.3 x^3 + 4 x^2 + 0.6 x - 1 x = sp.arange(-4, 1, .05) y = sp.polyval(polinomio, x) raices = sp.roots(polinomio) self.assertEqual(raices[0], -2.816023020827658) self.assertEqual(raices[1], -0.6691329703979497) self.assertEqual(raices[2], 0.4082329143025312)
def getOmegas(self, typeeos, OmegaB=False): acc = self.acc if typeeos in ['srk']: OmegaC = 0.0 onethird = 1.0 / 3.0 OmegaB = onethird * (2**onethird - 1) OmegaD = OmegaB + 0.0 OmegaA = onethird**2 / (2**onethird - 1) elif typeeos == 'pr': OmegaB = 0.077796 OmegaA = 0.457235 OmegaC = OmegaB + 0.0 OmegaD = OmegaB + 0.0 elif typeeos == 'pt': Zc = 0.3272 - 0.0537 * acc - 0.0147 * acc**2 #Note: NOT experimental Zc! A = 1.0 B = 2 - 3 * Zc C = 3 * Zc**2 D = -Zc**3 rts = scipy.roots([A, B, C, D]) OmegaB = min([ r.real for r in rts if (r.real > 0.0) and (abs(r.imag) < 1e-9) ]) OmegaD = OmegaB + 0.0 OmegaC = 1 - 3 * Zc OmegaA = 3 * Zc**2 + OmegaB * OmegaC + OmegaC * OmegaD + OmegaB * OmegaD + OmegaC + OmegaD elif typeeos in ['hkm2']: Zc = 0.3175 - 0.0364 * acc - 0.0245 * acc**2 #Note: NOT experimental Zc! A = 1.0 B = 1.25 - 3 * Zc C = 3 * Zc**2 - 1.5 * Zc + 0.5 D = -Zc**3 rts = scipy.roots([A, B, C, D]) OmegaB = min([ r.real for r in rts if (r.real > 0.0) and (abs(r.imag) < 1e-9) ]) OmegaE = 6 * Zc - 3 * OmegaB - 2 OmegaA = 3 * Zc**2 - 0.5 * OmegaB**2 - 0.75 * OmegaB * OmegaE - 0.5 * ( OmegaB + OmegaE) n = -0.5 m = -0.5 nbplusme = n * OmegaB + m * OmegaE nbme = n * OmegaB * m * OmegaE OmegaD = 0.5 * (nbplusme - scipy.sqrt(nbplusme**2 + 4 * nbme)) OmegaC = -nbme / OmegaD return OmegaA, OmegaB, OmegaC, OmegaD
def solve_composition(a, potentials, P=1., T=500., verbose=False): """ Calculate the equilibrium composition and free energy of a homonuclear gas mixture Arguments a: iterable of number of atoms in homonuclear molecule e.g. [2,8] if only considering S2, S8 potentials: chemical potentials at reference pressure and given T of species studied, in J mol-1 P: Pressure in units of reference pressure e.g. P=0.001 if study pressure is 1 mbar and reference pressure for potentials is 1 bar T: Temperature in K. This temperature must also be used when generating input potentials. verbose: Boolean flag. Print intermediate values. Returns n, mu_S: n: Amount of component in gas mixture, in units of mol molecule / mole atoms. To obtain units of atom%, n_atom_pc = [100 * a[i] * n_i for i, n_i in enumerate(n)] mu_S: Chemical potential of gas mixture in J mol-1 """ def vprint(*args): if verbose: for arg in args: print arg, else: pass from scipy.constants import R a = np.array(a) vprint("mu values: ", potentials, "J mol-1\n") vprint("RT = {0} J mol-1\n".format(R*T)) vprint("mu / RT: ", np.array(potentials)/(R*T), '\n') # Form empty polynomial poly = [0]*(max(a)+1) poly[0] = -P for i, ai in enumerate(a): poly[ai] += np.exp((-potentials[i])/(R*T)) poly.reverse() vprint("terms of polynomial: " + str(poly) + '\n') roots = scipy.roots(poly) good_root = False for root in roots: if root == root.real and root >= 0 : good_root = root # Root = exp(lambda/RT) lam = np.log(good_root.real) * R * T vprint("Lagrange multiplier = free energy/atom = {0}\n".format(lam)) mu_S = lam # Now to recover n values vprint("P=", P, "T=", T, "a=",a, '\n') phi = np.exp((a*lam - potentials)/(R*T)) vprint(phi) b = 1. # 1 mole of S atoms basis n = b * phi / (sum(a*phi)) return n, mu_S
def S_eq(self,T,P): c0,c1,c2 = self.c_factors(T) coeff = [c2, c1, c0-np.log(P)] S = np.real(sp.roots(coeff)) S_temp = S[S>=0.0] S_out = S_temp[S_temp<200] if len(S_out)==0: S_out = 0.0 return S_out/self.S_multiply[self.S_unit]
def R_of_l(V, l): ''' radius of a spherocylinder with segment length l, such that total volume is V. ''' R = scipy.roots([(4.0 / 3.0) * np.pi, np.pi * l, 0.0, -V]) R_phys = np.real(R[np.logical_and(np.isreal(R), R > 0.0)]) if len(R_phys) != 1: raise Exception('More or less than one physical radius found') return R_phys[0]
def calculate_time_to_collision_single(self, other_particle): """ Find the time until this particle will intersect with other_particle using linear extrapolation. This is done by analytically solving the equation (s_1 - s_2) ** 2 = (r_1 +- r_2) ** 2, which is the point where both circles make contact. The - in the right hand side of the equation is there for the case where one of the circles is currently inside the other. Arguments: other_particle: another Particle object. Returns: a float representing the time until these objects intersect, or NaN if these particles are not on a (future) collision trajectory. """ # Calculate all of the coefficients. velocity_diff = self._velocity - other_particle.get_current_velocity() position_diff = self._position - other_particle.get_current_position() dt_sq_coefficient = sp.dot(velocity_diff, velocity_diff) dt_coefficient = 2 * sp.dot(position_diff, velocity_diff) constant_coefficient_lhs = sp.dot(position_diff, position_diff) # (R1 +- R2) ** 2 if self.intersects(other_particle): rhs = (self._radius - other_particle._radius)**2 else: rhs = (self._radius + other_particle._radius)**2 constant_coefficient = constant_coefficient_lhs - rhs discriminant = dt_coefficient ** 2 \ - (4 * dt_sq_coefficient * constant_coefficient) if discriminant < 0: return sp.nan #sqrt_discriminant = sp.sqrt(discriminant) roots = sp.roots( [dt_sq_coefficient, dt_coefficient, constant_coefficient]) if sp.any(roots > Particle.tol): # We're only interested in the first collision, that has a dt which # is greater than zero, so return the smallest positive root: return min(root for root in roots if root > Particle.tol) return sp.nan
def vanderwaals( phase, pore_P="pore.pressure", pore_T="pore.temperature", pore_Pc="pore.critical_pressure", pore_Tc="pore.critical_temperature", **kwargs ): r""" Uses Van der Waals equation of state to calculate the density of a real gas Parameters ---------- pore_P : string The dictionary key containing the pressure values in Pascals (Pa) pore_T : string The dictionary key containing the temperature values in Kelvin (K) pore_Pc : string The dictionary key containing the critical pressure values in Pascals (Pa) pore_Tc : string The dictionary key containing the critical temperature values in Kelvin (K) Returns ------- rho, the density in [mol/m3] Notes ----- This equation and its constant coefficients are taken [1]_ which uses the cgs units system. All input parameters are expected in SI, then converted in the method. """ P = phase[pore_P] / 100000 T = phase[pore_T] Pc = phase[pore_Pc] / 100000 # convert to bars Tc = phase[pore_Tc] R = 83.1447 a = 27 * (R ** 2) * (Tc ** 2) / (64 * Pc) b = R * Tc / (8 * Pc) a1 = -1 / b a2 = (R * T + b * P) / (a * b) a3 = -P / (a * b) a0 = sp.ones(sp.shape(a1)) coeffs = sp.vstack((a0, a1, a2, a3)).T density = sp.array([sp.roots(C) for C in coeffs]) value = sp.real(density[:, 2]) * 1e6 # Convert it to mol/m3 return value
def Z(self,t,p): # we pass p because in this case the pressure is the independent variable hence we don't use self.p #Z3+AZ2+BZ+C=0 eps = self.typeeos.epsilon sig = self.typeeos.sigma pb = (p*self.b)/(self.r*t) ap = (p*self.a*self.alpha(t))/((self.r*t)**2) A = (eps+sig-1)*pb -1 B= sig*eps*(pb**2)-(sig+eps)*(pb**2)-(sig+eps)*pb+ap C= -sig*eps*pb**3-sig*eps*pb**2-ap*pb roots = scipy.roots([1.0,A,B,C]) # gives all roots, even complex ones roots = [x.real for x in roots if abs(x.imag) < 1e-16] #.real and .imag are keywords coded in python return roots
def complex_basins(func, dfunc, coeffs, interval, npoints): """Plot func over the complex interval and the basins of attraction with npoints resolution""" seeds = sp.zeros((2, npoints, npoints), dtype='complex128') seeds[0:,:,] = sp.ones((npoints, 1))*sp.linspace(interval[0], interval[1], npoints) seeds[0:,:,] = seeds[0:,:,] + 1j*seeds[0:,:,] colors = pyplot.cm.colors.cnames.keys() colors.remove('black') clen = len(colors) for i in xrange(npoints): for j in xrange(npoints): seeds[1,i,j] = newton(func, dfunc, seeds[0,i,j]) #return seeds #find the unique roots of seed values roots, indices = sp.unique(seeds[1]) #for each root, associate a color col = sp.zeros_like(roots.shape) for i in range(len(roots)): col[i] = colors.pop(sp.random.randint(clen)) #seeds[1] = newtonv(func, ) #set the color for each #tol = 1e-7 #valcol = [[]] #for valx in range(npoints): #for valy in range(npoints): #if valx and valy == 0: #valcol.append(colors[0]) #continue #if not(abs(seeds[1,valx,valy]-seeds[1,valx,valy-1]) <= tol): #valcol.append(colors.pop(sp.random.randint(1,len(colors)))) #else: #valcol.append(valcol[0][0]) #for col in range(npoints): #for col1 in range(npoints): #pyplot.plot(seeds[0,col,col1], seeds[1,col,col1], marker=',', color=valcol[col][col1]) tol = 1e-07 roots = sp.roots(coeffs) pyplot.hold(True) #for i in range(len(roots)): #pyplot.plot(seeds[abs(seeds[1:,:,]-roots[i])<tol], color=colors.pop(sp.random.randint(len(colors))), linestyle='None', marker='.') pyplot.pcolor(seeds[0], seeds[1]) pyplot.hold(False) pyplot.show()
def calculo(self): entrada = self.kwargs["entrada"] self.rendimientoCalculado = Dimensionless(self.kwargs["rendimiento"]) if self.kwargs["Pout"]: DeltaP = Pressure(self.kwargs["Pout"] - entrada.P) elif self.kwargs["deltaP"]: DeltaP = Pressure(self.kwargs["deltaP"]) elif self.kwargs["Carga"]: DeltaP = Pressure(self.kwargs["Carga"] * entrada.Liquido.rho * g) else: DeltaP = Pressure(0) if self.kwargs["usarCurva"]: b1 = self.kwargs["diametro"] != self.kwargs["curvaCaracteristica"][ 0] # noqa b2 = self.kwargs["velocidad"] != self.kwargs[ "curvaCaracteristica"][1] # noqa if b1 or b2: self.curvaActual = self.calcularCurvaActual() else: self.curvaActual = self.kwargs["curvaCaracteristica"] self.Ajustar_Curvas_Caracteristicas() if not self.kwargs["usarCurva"]: head = Length(DeltaP / g / entrada.Liquido.rho) power = Power(head * g * entrada.Liquido.rho * entrada.Q / self.rendimientoCalculado) P_freno = Power(power * self.rendimientoCalculado) elif not self.kwargs["incognita"]: head = Length(polyval(self.CurvaHQ, entrada.Q)) DeltaP = Pressure(head * g * entrada.Liquido.rho) power = Power(entrada.Q * DeltaP) P_freno = Power(polyval(self.CurvaPotQ, entrada.Q)) self.rendimientoCalculado = Dimensionless(power / P_freno) else: head = Length(self.DeltaP / g / entrada.Liquido.rho) poli = [self.CurvaHQ[0], self.CurvaHQ[1], self.CurvaHQ[2] - head] Q = roots(poli)[0] power = Power(Q * self.DeltaP) entrada = entrada.clone(split=Q / entrada.Q) P_freno = Power(polyval(self.CurvaPotQ, Q)) self.rendimientoCalculado = Dimensionless(power / P_freno) self.deltaP = DeltaP self.headCalculada = head self.power = power self.P_freno = P_freno self.salida = [entrada.clone(P=entrada.P + DeltaP)] self.Pin = entrada.P self.PoutCalculada = self.salida[0].P self.volflow = entrada.Q self.cp_cv = entrada.Liquido.cp_cv
def getOmegas(self, typeeos, OmegaB = False): acc = self.acc if typeeos in ['srk']: OmegaC = 0.0 onethird = 1.0/3.0 OmegaB = onethird*(2**onethird-1) OmegaD = OmegaB + 0.0 OmegaA = onethird**2/(2**onethird-1) elif typeeos == 'pr': OmegaB = 0.077796 OmegaA = 0.457235 OmegaC = OmegaB + 0.0 OmegaD = OmegaB + 0.0 elif typeeos == 'pt': Zc = 0.3272 - 0.0537*acc - 0.0147*acc**2 #Note: NOT experimental Zc! A = 1.0 B = 2 - 3*Zc C = 3*Zc**2 D = -Zc**3 rts = scipy.roots([A, B, C, D]) OmegaB = min([r.real for r in rts if (r.real > 0.0) and (abs(r.imag) < 1e-9)]) OmegaD = OmegaB + 0.0 OmegaC = 1 - 3*Zc OmegaA = 3*Zc**2 + OmegaB*OmegaC + OmegaC*OmegaD + OmegaB*OmegaD + OmegaC + OmegaD elif typeeos in ['hkm2']: Zc = 0.3175 - 0.0364*acc -0.0245*acc**2 #Note: NOT experimental Zc! A = 1.0 B = 1.25 - 3*Zc C = 3*Zc**2 - 1.5*Zc + 0.5 D = -Zc**3 rts = scipy.roots([A, B, C, D]) OmegaB = min([r.real for r in rts if (r.real > 0.0) and (abs(r.imag) < 1e-9)]) OmegaE = 6*Zc - 3*OmegaB - 2 OmegaA = 3*Zc**2 - 0.5*OmegaB**2 - 0.75*OmegaB*OmegaE - 0.5*(OmegaB+OmegaE) n = -0.5; m = -0.5 nbplusme = n*OmegaB + m*OmegaE nbme = n*OmegaB*m*OmegaE OmegaD = 0.5*(nbplusme - scipy.sqrt(nbplusme**2+4*nbme)) OmegaC = -nbme/OmegaD return OmegaA, OmegaB, OmegaC, OmegaD
def vanderwaals(phase, pore_P='pore.pressure', pore_T='pore.temperature', pore_Pc='pore.critical_pressure', pore_Tc='pore.critical_temperature', **kwargs): r""" Uses Van der Waals equation of state to calculate the density of a real gas Parameters ---------- pore_P : string The dictionary key containing the pressure values in Pascals (Pa) pore_T : string The dictionary key containing the temperature values in Kelvin (K) pore_Pc : string The dictionary key containing the critical pressure values in Pascals (Pa) pore_Tc : string The dictionary key containing the critical temperature values in Kelvin (K) Returns ------- rho, the density in [mol/m3] Notes ----- This equation and its constant coefficients are taken [1]_ which uses the cgs units system. All input parameters are expected in SI, then converted in the method. """ P = phase[pore_P] / 100000 T = phase[pore_T] Pc = phase[pore_Pc] / 100000 # convert to bars Tc = phase[pore_Tc] R = 83.1447 a = 27 * (R**2) * (Tc**2) / (64 * Pc) b = R * Tc / (8 * Pc) a1 = -1 / b a2 = (R * T + b * P) / (a * b) a3 = -P / (a * b) a0 = sp.ones(sp.shape(a1)) coeffs = sp.vstack((a0, a1, a2, a3)).T density = sp.array([sp.roots(C) for C in coeffs]) value = sp.real(density[:, 2]) * 1e6 # Convert it to mol/m3 return value
def complex_basins(func, dfunc, coeffs, interval, npoints): """Plot func over the complex interval and the basins of attraction with npoints resolution""" seeds = sp.zeros((2, npoints, npoints), dtype='complex128') seeds[0:, :, ] = sp.ones( (npoints, 1)) * sp.linspace(interval[0], interval[1], npoints) seeds[0:, :, ] = seeds[0:, :, ] + 1j * seeds[0:, :, ] colors = pyplot.cm.colors.cnames.keys() colors.remove('black') clen = len(colors) for i in xrange(npoints): for j in xrange(npoints): seeds[1, i, j] = newton(func, dfunc, seeds[0, i, j]) #return seeds #find the unique roots of seed values roots, indices = sp.unique(seeds[1]) #for each root, associate a color col = sp.zeros_like(roots.shape) for i in range(len(roots)): col[i] = colors.pop(sp.random.randint(clen)) #seeds[1] = newtonv(func, ) #set the color for each #tol = 1e-7 #valcol = [[]] #for valx in range(npoints): #for valy in range(npoints): #if valx and valy == 0: #valcol.append(colors[0]) #continue #if not(abs(seeds[1,valx,valy]-seeds[1,valx,valy-1]) <= tol): #valcol.append(colors.pop(sp.random.randint(1,len(colors)))) #else: #valcol.append(valcol[0][0]) #for col in range(npoints): #for col1 in range(npoints): #pyplot.plot(seeds[0,col,col1], seeds[1,col,col1], marker=',', color=valcol[col][col1]) tol = 1e-07 roots = sp.roots(coeffs) pyplot.hold(True) #for i in range(len(roots)): #pyplot.plot(seeds[abs(seeds[1:,:,]-roots[i])<tol], color=colors.pop(sp.random.randint(len(colors))), linestyle='None', marker='.') pyplot.pcolor(seeds[0], seeds[1]) pyplot.hold(False) pyplot.show()
def vanderwaals(target, pressure='pore.pressure', temperature='pore.temperature', critical_pressure='pore.critical_pressure', critical_temperature='pore.critical_temperature'): r""" Uses Van der Waals equation of state to calculate the density of a real gas Parameters ---------- target : OpenPNM Object The object for which these values are being calculated. This controls the length of the calculated array, and also provides access to other necessary thermofluid properties. pressure : string The dictionary key containing the pressure values in Pascals (Pa) temperature : string The dictionary key containing the temperature values in Kelvin (K) critical_pressure : string The dictionary key containing the critical pressure values in Pascals (Pa) critical_temperature : string The dictionary key containing the critical temperature values in Kelvin (K) Returns ------- value : NumPy ndarray Array containing molar density values [mol/m3] """ P = target[pressure] / 100000 T = target[temperature] Pc = target[critical_pressure] / 100000 # convert to bars Tc = target[critical_temperature] R = 83.1447 a = 27 * (R**2) * (Tc**2) / (64 * Pc) b = R * Tc / (8 * Pc) a1 = -1 / b a2 = (R * T + b * P) / (a * b) a3 = -P / (a * b) a0 = sp.ones(sp.shape(a1)) coeffs = sp.vstack((a0, a1, a2, a3)).T density = sp.array([sp.roots(C) for C in coeffs]) value = sp.real(density[:, 2]) * 1e6 # Convert it to mol/m3 return value
def calculo(self): entrada = self.kwargs["entrada"] self.rendimientoCalculado = Dimensionless(self.kwargs["rendimiento"]) if self.kwargs["Pout"]: DeltaP = Pressure(self.kwargs["Pout"]-entrada.P) elif self.kwargs["deltaP"]: DeltaP = Pressure(self.kwargs["deltaP"]) elif self.kwargs["Carga"]: DeltaP = Pressure(self.kwargs["Carga"]*entrada.Liquido.rho*g) else: DeltaP = Pressure(0) if self.kwargs["usarCurva"]: b1 = self.kwargs["diametro"] != self.kwargs["curvaCaracteristica"][0] # noqa b2 = self.kwargs["velocidad"] != self.kwargs["curvaCaracteristica"][1] # noqa if b1 or b2: self.curvaActual = self.calcularCurvaActual() else: self.curvaActual = self.kwargs["curvaCaracteristica"] self.Ajustar_Curvas_Caracteristicas() if not self.kwargs["usarCurva"]: head = Length(DeltaP/g/entrada.Liquido.rho) power = Power(head*g*entrada.Liquido.rho*entrada.Q / self.rendimientoCalculado) P_freno = Power(power*self.rendimientoCalculado) elif not self.kwargs["incognita"]: head = Length(polyval(self.CurvaHQ, entrada.Q)) DeltaP = Pressure(head*g*entrada.Liquido.rho) power = Power(entrada.Q*DeltaP) P_freno = Power(polyval(self.CurvaPotQ, entrada.Q)) self.rendimientoCalculado = Dimensionless(power/P_freno) else: head = Length(self.DeltaP/g/entrada.Liquido.rho) poli = [self.CurvaHQ[0], self.CurvaHQ[1], self.CurvaHQ[2]-head] Q = roots(poli)[0] power = Power(Q*self.DeltaP) entrada = entrada.clone(split=Q/entrada.Q) P_freno = Power(polyval(self.CurvaPotQ, Q)) self.rendimientoCalculado = Dimensionless(power/P_freno) self.deltaP = DeltaP self.headCalculada = head self.power = power self.P_freno = P_freno self.salida = [entrada.clone(P=entrada.P+DeltaP)] self.Pin = entrada.P self.PoutCalculada = self.salida[0].P self.volflow = entrada.Q self.cp_cv = entrada.Liquido.cp_cv
def getPborder(self,t): # this is used to get V where the dP/dv = 0. the input equation is the differentiated equation e = self.typeeos.epsilon s= self.typeeos.sigma A= -self.r*t*(self.b*self.typeeos.epsilon-self.typeeos.sigma) B = self.a*self.alpha(t) b = self.b C = -1 a5 =A*b**4*e**2*s**2 + B*b**4*e**2 + C*b**4*s**2 a1 = (A + B + C) a2 = 2*A*b*e + 2*A*b*s + 2*B*b*e - 2*B*b + 2*C*b*s - 2*C*b a3 = A*b**2*e**2 + 4*A*b**2*e*s + A*b**2*s**2 + B*b**2*e**2 - 4*B*b**2*e + B*b**2 + C*b**2*s**2 - 4*C*b**2*s + C*b**2 a4 = (2*A*b**3*e**2*s + 2*A*b**3*e*s**2 - 2*B*b**3*e**2 + 2*B*b**3*e - 2*C*b**3*s**2 + 2*C*b**3*s) vsol = scipy.roots([a1,a2,a3,a4,a5]) return vsol
def LGR(self,figura): """ Função para traçado do Lugar Geométrico das Raízes kvect: Vetor dos ganhos; figura: referência a uma figura do Matplotlib. O LGR é traçado sempre com ganho K = 1. """ num = self.polyDnum den = self.polyDden # Criando vetor de ganhos (sem os pontos críticos). # Kmin, Kmax e numero de pontos são atributos desta classe. delta_k = (self.Kmax-self.Kmin) / self.Kpontos kvect = numpy.arange(self.Kmin,self.Kmax,delta_k) # Geracao dos pontos de separacao # Fazendo d(-1/G(s))/ds = 0 deriv = scipy.polyder(den)*num - scipy.polyder(num)*den cpss = scipy.roots(deriv) # candidatos a ponto de separacao # Verificacao de quais os candidatos pertinentes for raiz in cpss: aux = num(raiz) if aux != 0: Kc = -den(raiz) / num(raiz) if (numpy.isreal(Kc)) and (Kc <= self.Kmax) and (Kc >= self.Kmin): kvect = numpy.append(kvect,Kc) # Reordena o kvect: kvect = numpy.sort(kvect); # Calculate the roots: root_vector = MyRootLocus(num,den,kvect) # Ploting: figura.clf() ax = figura.add_subplot(111) # Open loop poles: poles = numpy.array(den.r) ax.plot(numpy.real(poles), numpy.imag(poles), 'x') # Open loop zeros: zeros = numpy.array(num.r) if zeros.any(): ax.plot(numpy.real(zeros), numpy.imag(zeros), 'o') for col in root_vector.T: # Ploting the root locus. ax.plot(numpy.real(col), numpy.imag(col), '-') return root_vector
def vanderwaals(target, pressure='pore.pressure', temperature='pore.temperature', critical_pressure='pore.critical_pressure', critical_temperature='pore.critical_temperature'): r""" Uses Van der Waals equation of state to calculate the density of a real gas Parameters ---------- target : OpenPNM Object The object for which these values are being calculated. This controls the length of the calculated array, and also provides access to other necessary thermofluid properties. pressure : string The dictionary key containing the pressure values in Pascals (Pa) temperature : string The dictionary key containing the temperature values in Kelvin (K) critical_pressure : string The dictionary key containing the critical pressure values in Pascals (Pa) critical_temperature : string The dictionary key containing the critical temperature values in Kelvin (K) Returns ------- value : NumPy ndarray Array containing molar density values [mol/m3] """ P = target[pressure]/100000 T = target[temperature] Pc = target[critical_pressure]/100000 # convert to bars Tc = target[critical_temperature] R = 83.1447 a = 27*(R**2)*(Tc**2)/(64*Pc) b = R*Tc/(8*Pc) a1 = -1/b a2 = (R*T+b*P)/(a*b) a3 = -P/(a*b) a0 = sp.ones(sp.shape(a1)) coeffs = sp.vstack((a0, a1, a2, a3)).T density = sp.array([sp.roots(C) for C in coeffs]) value = sp.real(density[:, 2])*1e6 # Convert it to mol/m3 return value
def low_accuracy_recompute_alpha_varying_fields( sph_start, sph_end, t_start, t_end, mag_params): """ Compute effective damping from change in magnetisation and change in applied field. From Nonlinear magnetization dynamics in nanosystems eqn (2.15). See notes 30/7/13. Derivatives are estimated using BDF1 finite differences. """ # Only for normalised problems! assert(mag_params.Ms == 1) # Get some values dt = t_end - t_start m_cart_end = utils.sph2cart(sph_end) h_eff_end = heff(mag_params, t_end, m_cart_end) mxh = sp.cross(m_cart_end, h_eff_end) # Finite difference derivatives dhadt = (mag_params.Hvec(t_start) - mag_params.Hvec(t_end))/dt assert(all(dhadt == 0)) # no field for now dedt = (llg_state_energy(sph_end, mag_params, t_end) - llg_state_energy(sph_start, mag_params, t_start) )/dt sigma = sp.dot(mxh, mxh) / (dedt + sp.dot(m_cart_end, dhadt)) possible_alphas = sp.roots([1, sigma, 1]) a = (-sigma + sqrt(sigma**2 - 4))/2 b = (-sigma - sqrt(sigma**2 - 4))/2 possible_alphas2 = [a, b] utils.assert_list_almost_equal(possible_alphas, possible_alphas2) print(sigma, possible_alphas) def real_and_positive(x): return sp.isreal(x) and x > 0 alphas = filter(real_and_positive, possible_alphas) assert(len(alphas) == 1) return sp.real(alphas[0])
def getvborder(self, T, alpha = False): if not alpha: alpha = self.alpha(T) RT = self.R*T a, b, c, d = self.a*alpha, self.b, self.c, self.d a4 = -1.0 a3 = -2*(c+d) + 2*a/RT a2 = -c**2 - d**2 - 4*a*b/RT + a*c/RT + a*d/RT a1 = 2*c**2*d + 2*c*d**2 + 2*a*b**2/RT - 2*a*b*c/RT - 2*a*b*d/RT a0 = -c**2*d**2 + a*b**2*c/RT + a*b**2*d/RT roots = scipy.roots([a4.real, a3.real, a2.real, a1.real, a0.real]) roots = [x.real for x in roots if abs(x.imag) < 1e-16 and x.real > b] if len(roots) == 2: vborder = [roots[0], roots[1]] return True, min(vborder), max(vborder) else: return False, None, None
def Z(self, T, P, alpha = False): P = 1e-20 if P == 0.0 else P if not alpha: alpha = self.alpha(T) PRT = P/(self.R*T) a, b, c, d = self.a*alpha, self.b, self.c, self.d A = PRT*(c + d - b) - 1 B = PRT**2*(a/P - b*c - c*d - d*b) - PRT*(c+d) C = PRT**3*(b*c*d+c*d/PRT-a*b/P) roots = scipy.roots([1, A.real, B.real, C.real]) roots = [x.real for x in roots if abs(x.imag) < 1e-16] if len(roots) == 3: return [min(roots), max(roots)] elif len(roots) == 1: return [roots[0]] else: return []
def Z(self, T, P, alpha=False): P = 1e-20 if P == 0.0 else P if not alpha: alpha = self.alpha(T) PRT = P / (self.R * T) a, b, c, d = self.a * alpha, self.b, self.c, self.d A = PRT * (c + d - b) - 1 B = PRT**2 * (a / P - b * c - c * d - d * b) - PRT * (c + d) C = PRT**3 * (b * c * d + c * d / PRT - a * b / P) roots = scipy.roots([1, A.real, B.real, C.real]) roots = [x.real for x in roots if abs(x.imag) < 1e-16] if len(roots) == 3: return [min(roots), max(roots)] elif len(roots) == 1: return [roots[0]] else: return []
def getvborder(self, T, alpha=False): if not alpha: alpha = self.alpha(T) RT = self.R * T a, b, c, d = self.a * alpha, self.b, self.c, self.d a4 = -1.0 a3 = -2 * (c + d) + 2 * a / RT a2 = -c**2 - d**2 - 4 * a * b / RT + a * c / RT + a * d / RT a1 = 2 * c**2 * d + 2 * c * d**2 + 2 * a * b**2 / RT - 2 * a * b * c / RT - 2 * a * b * d / RT a0 = -c**2 * d**2 + a * b**2 * c / RT + a * b**2 * d / RT roots = scipy.roots([a4.real, a3.real, a2.real, a1.real, a0.real]) roots = [x.real for x in roots if abs(x.imag) < 1e-16 and x.real > b] if len(roots) == 2: vborder = [roots[0], roots[1]] return True, min(vborder), max(vborder) else: return False, None, None
def __lib(self, cmp, T): Tr = T / cmp.Tc if cmp.id in dat: Xc, m, p, d = dat[cmp.id] else: Zc = cmp.Pc.kPa * cmp.Vc * cmp.M / R / cmp.Tc d = cmp.Vc.ccg * cmp.M / 3 # Eq 11 Xc = 1.063 * Zc # Eq 12 # Eq 13 m = 0.662 + 3.12 * cmp.f_acent - 0.854 * cmp.f_acent**2 + 9.3 * ( Zc - 0.3) if cmp.M <= 128: p = 0.475 + 2 * cmp.f_acent # Eq 14a else: p = 0.613 + 0.62 * cmp.f_acent + 4.06 * cmp.f_acent**2 # Eq 14b alfa = 1 + m * (1 - Tr**0.5) + p * (0.7**0.5 - Tr**0.5) * (1 - Tr**0.5) # From here common functionality of original TB EoS # Convert d from cc/mol to m3/mol d /= 1e6 Cc = 1 - 3 * Xc # Eq 6 Dc = d * cmp.Pc / R / cmp.Tc # Eq 12 # Bc calculated ad the smallest positive root of Eq 8 B = roots([1, 2 - 3 * Xc, 3 * Xc**2, -Dc**2 - Xc**3]) Bpositivos = [] for Bi in B: if Bi > 0: Bpositivos.append(Bi) Bc = min(Bpositivos) Ac = 3 * Xc**2 + 2 * Bc * Cc + Bc + Cc + Bc**2 + Dc**2 # Eq 7 ac = Ac * R**2 * cmp.Tc**2 / cmp.Pc a = ac * alfa # Eq 23 b = Bc * R * cmp.Tc / cmp.Pc c = R * cmp.Tc / cmp.Pc * (1 - 3 * Xc) # Eq 10 return a, b, c, d
def tmin(self, r, z, trace=False): """Calculates and returns the s value along the norm vector which minimizes the distance from the ray to a circle defined by input (r,z). Args: r: value, iterable or scipy.array, radius in meters z: value, iterable or scipy.array, z value in meters Kwargs: trace: bool if set true, the ray is assumed to be traced within a tokamak. A further evaluation reduces the value to one within the bounds of the vacuum vessel/limiter. Returns: numpy array of s values in meters """ r = scipy.atleast_1d(r) z = scipy.atleast_1d(z) params = _beam.lineCirc(self(0).x(), self.norm.unit, r, z) sout = scipy.zeros(r.shape) for i in xrange(len(params)): temp = scipy.roots(params[i]) # only positive real solutions are taken temp = temp[scipy.imag(temp) == 0] temp = scipy.real(temp[temp > 0]) test = self(temp).r() # must decide between local and global minima sout[i] = temp[((test[0]-r[i])**2 + (test[2] - z[i])**2).argmin()] if trace and ((sout[i] > self.norm.s[-1]) or (sout[i] < self.norm.s[-2])): #need to implement this such that it searches only in area of interest sout[i] = None return sout
def tmin(self, r, z, trace=False): """Calculates and returns the s value along the norm vector which minimizes the distance from the ray to a circle defined by input (r,z). Args: r: value, iterable or scipy.array, radius in meters z: value, iterable or scipy.array, z value in meters Kwargs: trace: bool if set true, the ray is assumed to be traced within a tokamak. A further evaluation reduces the value to one within the bounds of the vacuum vessel/limiter. Returns: numpy array of s values in meters """ r = scipy.atleast_1d(r) z = scipy.atleast_1d(z) params = _beam.lineCirc(self(0).x(), self.norm.unit, r, z) sout = scipy.zeros(r.shape) for i in range(len(params)): temp = scipy.roots(params[i]) # only positive real solutions are taken temp = temp[scipy.imag(temp) == 0] temp = scipy.real(temp[temp > 0]) test = self(temp).r() # must decide between local and global minima sout[i] = temp[((test[0] - r[i])**2 + (test[2] - z[i])**2).argmin()] if trace and ((sout[i] > self.norm.s[-1]) or (sout[i] < self.norm.s[-2])): #need to implement this such that it searches only in area of interest sout[i] = None return sout
def Z(self, T, P): R = self.R; a = self.a; b = self.b sigma = self.typeEOS.sigma; epsilon = self.typeEOS.epsilon alpha = self.alpha(T) p_p = P*b/R/T; a_p = P*a*alpha/R**2/T**2 a3 = 1.0 a2 = epsilon*p_p + p_p*sigma - p_p - 1.0 a1 = a_p + epsilon*p_p**2*sigma - epsilon*p_p**2 - epsilon*p_p - p_p**2*sigma - p_p*sigma a0 = -a_p*p_p - epsilon*p_p**3*sigma - epsilon*p_p**2*sigma roots = scipy.roots([a3, a2, a1, a0]) roots = [rt.real for rt in roots if abs(rt.imag) < 1e-16] if len(roots) == 3: return scipy.array([min(roots), max(roots)]) elif len(roots) == 1: return scipy.array(roots) else: return []
def getPborder(self, T): a = self.a; b = self.b alpha = self.alpha(T) R = self.R; s = self.typeEOS.sigma; e = self.typeEOS.epsilon A = a*alpha/(s-e)/b/R/T a4 = 1.0 a3 = 2*A*b*e - 2*A*b*s + 2*b*e + 2*b*s a2 = A*b**2*e**2 - 4*A*b**2*e - A*b**2*s**2 + 4*A*b**2*s + b**2*e**2 + 4*b**2*e*s + b**2*s**2 a1 = -2*A*b**3*e**2 + 2*A*b**3*e + 2*A*b**3*s**2 - 2*A*b**3*s + 2*b**3*e**2*s + 2*b**3*e*s**2 a0 = A*b**4*e**2 - A*b**4*s**2 + b**4*e**2*s**2 roots = scipy.roots([a4, a3, a2, a1, a0]) roots = [x.real for x in roots if abs(x.imag) < 1e-16 and x.real > b] if len(roots) == 2: PP = [self.P(T, roots[0]), self.P(T, roots[1])] return True, min(PP), max(PP) else: return False, None, None
def dispersion_relation_extraordinary(kx, ky, k, nO, nE, c): """Dispersion relation for the extraordinary wave. NOTE See eq. 16 in Glytsis, "Three-dimensional (vector) rigorous coupled-wave analysis of anisotropic grating diffraction", JOSA A, 7(8), 1990 Always give positive real or negative imaginary. """ if kx.shape != ky.shape or c.size != 3: raise ValueError( "kx and ky must have the same length and c must have 3 components" ) kz = S.empty_like(kx) for ii in range(0, kx.size): alpha = nE ** 2 - nO ** 2 beta = kx[ii] / k * c[0] + ky[ii] / k * c[1] # coeffs C = S.array( [ nO ** 2 + c[2] ** 2 * alpha, 2.0 * c[2] * beta * alpha, nO ** 2 * (kx[ii] ** 2 + ky[ii] ** 2) / k ** 2 + alpha * beta ** 2 - nO ** 2 * nE ** 2, ] ) # two solutions of type +x or -x, purely real or purely imag tmp_kz = k * S.roots(C) # get the negative imaginary part or the positive real one if S.any(S.isreal(tmp_kz)): kz[ii] = S.absolute(tmp_kz[0]) else: kz[ii] = -1j * S.absolute(tmp_kz[0]) return kz
def __init__(self, T, P, mezcla): self.T=unidades.Temperature(T) self.P=unidades.Pressure(P, "atm") self.mezcla=mezcla self.componente=mezcla.componente self.fraccion=mezcla.fraccion self.B=self.b*self.P.atm/R_atml/self.T self.Tita=self.tita*self.P.atm/(R_atml*self.T)**2 delta=self.delta*self.P.atm/R_atml/self.T epsilon=self.epsilon*(self.P.atm/R_atml/self.T)**2 eta=self.eta*self.P.atm/R_atml/self.T Z=roots([1, delta-self.B-1, self.Tita+epsilon-delta*(self.B+1), -epsilon*(self.B+1)-self.Tita*eta]) self.Z=r_[Z[0].real, Z[2].real] self.V=self.Z*R_atml*self.T/self.P.atm #mol/l self.x, self.xi, self.yi, self.Ki=self._Flash() self.H_exc=-(self.tita+self.dTitadT)/R_atml/self.T/(self.delta**2-4*self.epsilon)**0.5*log((2*self.V+self.delta-(self.delta**2-4*self.epsilon)**0.5)/(2*self.V+self.delta+(self.delta**2-4*self.epsilon)**0.5))+1-self.Z
def PTC_lib(compuesto, T): """Librería de cálculo de la ecuación de estado de Patel-Teja-Crause""" if compuesto.Tc!=0 and compuesto.Pc!=0 and compuesto.vc!=0: Zc=compuesto.Pc.atm*compuesto.vc*compuesto.peso_molecular/R_atml/compuesto.Tc else: Zc=0.253168556+0.09253329*exp(-0.0048018*compuesto.peso_molecular) c=(1-3*Zc)*R_atml*compuesto.Tc/compuesto.Pc.atm omega=roots([1, 2-3*Zc, 3*Zc**2, -Zc**3]) Bpositivos=[] for i in omega: if i>0: Bpositivos.append(i) omegab=min(Bpositivos) b=omegab*R_atml*compuesto.Tc/compuesto.Pc.atm f=0.002519*compuesto.peso_molecular+0.70647 alfa=(1+f*(1-sqrt(T/compuesto.Tc)))**2 omegaa=3*Zc**2+3*(1-2*Zc)*omegab+omegab**2+1-3*Zc a=omegaa*R_atml**2*compuesto.Tc**2/compuesto.Pc.atm**2*alfa return a, b, c
def PT_lib(compuesto, T): """Librería de cálculo de la ecuación de estado de Patel-Teja""" if compuesto.Tc != 0 and compuesto.Pc != 0 and compuesto.vc != 0: Zc = compuesto.Pc.atm * compuesto.vc * compuesto.peso_molecular / R_atml / compuesto.Tc else: Zc = 0.329032 + 0.076799 * compuesto.f_acent - 0.0211947 * compuesto.f_acent**2 c = (1 - 3 * Zc) * R_atml * compuesto.Tc / compuesto.Pc.atm omega = roots([1, 2 - 3 * Zc, 3 * Zc**2, -Zc**3]) Bpositivos = [] for i in omega: if i > 0: Bpositivos.append(i) omegab = min(Bpositivos) b = omegab * R_atml * compuesto.Tc / compuesto.Pc.atm f = 0.452413 + 1.30982 * compuesto.f_acent - 0.295937 * compuesto.f_acent**2 alfa = (1 + f * (1 - sqrt(T / compuesto.Tc)))**2 omegaa = 3 * Zc**2 + 3 * (1 - 2 * Zc) * omegab + omegab**2 + 1 - 3 * Zc a = omegaa * R_atml**2 * compuesto.Tc**2 / compuesto.Pc.atm**2 * alfa return a, b, c
def PT_lib(compuesto, T): """Librería de cálculo de la ecuación de estado de Patel-Teja""" if compuesto.Tc!=0 and compuesto.Pc!=0 and compuesto.vc!=0: Zc=compuesto.Pc.atm*compuesto.vc*compuesto.peso_molecular/R_atml/compuesto.Tc else: Zc=0.329032+0.076799*compuesto.f_acent-0.0211947*compuesto.f_acent**2 c=(1-3*Zc)*R_atml*compuesto.Tc/compuesto.Pc.atm omega=roots([1, 2-3*Zc, 3*Zc**2, -Zc**3]) Bpositivos=[] for i in omega: if i>0: Bpositivos.append(i) omegab=min(Bpositivos) b=omegab*R_atml*compuesto.Tc/compuesto.Pc.atm f=0.452413+1.30982*compuesto.f_acent-0.295937*compuesto.f_acent**2 alfa=(1+f*(1-sqrt(T/compuesto.Tc)))**2 omegaa=3*Zc**2+3*(1-2*Zc)*omegab+omegab**2+1-3*Zc a=omegaa*R_atml**2*compuesto.Tc**2/compuesto.Pc.atm**2*alfa return a, b, c
def AproxBessel(Retardo, Wrg, Tol, N=0, Nmin=0, Nmax=15): s = sympy.Symbol('s') if N == 0: #Trato de obtener la funcion de bessel que cumpla con lo pedido N = 1 #Si tengo un valor de Nmin voy a empezar desde ahi if Nmin != 0: N = Nmin while (N < Nmax) and (Nmin <= N): Polinomio = PoliBessel(N) Tranferencia = Polinomio.subs(s, 0) / Polinomio.subs(s, 1j * Wrg) Temp = ((Wrg**(2 * N)) * (abs(Tranferencia)**2)) / (Polinomio.subs(s, 0)**2) if (Temp < Tol): break else: N += 1 #Chequeo para ver si estoy en el Nmax if N == Nmax: Polinomio = PoliBessel(N) print("Se alcanzo el limite") elif N == Nmin: print("Se alconzo el minimo") else: Polinomio = PoliBessel(N) #obtengo la funcion tranferencia Tranferencia = Polinomio.subs(s, 0) / Polinomio #Busco los polos Num, Den = sympy.fraction(Tranferencia) Den_Coef = sympy.Poly(Den) Den_Coef = Den_Coef.all_coeffs() Polos = scipy.roots(Den_Coef) for i in range(len(Polos)): Polos[i] = Polos[i] #Devuelvo el orden, los polos y la constante Num = 1 return N, Polos, Num
def PontosSeparacao(self): """ Calcula os pontos de separação e retorna só os pertinentes. """ num = self.polyDnum den = self.polyDden pontos = [] ganhos = [] # Geracao dos pontos de separacao # Fazendo d(-1/G(s))/ds = 0 deriv = scipy.polyder(den)*num - scipy.polyder(num)*den cpss = scipy.roots(deriv) # candidatos a ponto de separacao # Verificacao de quais os candidatos pertinentes for raiz in cpss: aux = num(raiz) if aux != 0: Kc = -den(raiz) / num(raiz) if (numpy.isreal(Kc)):# and (Kc <= self.Kmax) and (Kc >= self.Kmin): pontos.append(raiz) ganhos.append(Kc) return pontos, ganhos
def _BOpntsLoc(sys): """Breakout point locater This returns the location of breakout points on the root locus and the associated gains at those locations. Parameters ---------- sys: StateSpace or TransferFunction Linear system Returns ------- KatBO: list of gains at which a breakout point occurs BOpnts: list of breakout points """ (nump, denp) = _systopoly1d(sys) # Breakout points potentially occur where N*D' - N'*D = 0 numpD = polyder(nump) denpD = polyder(denp) BOpnts = roots((nump*denpD) - (numpD*denp)) # Selects only the Breakout points on the real line BOpnts = BOpnts[imag(BOpnts) == 0] # Finds gains from breakout points fgain = vectorize(lambda s: polyval(-denp,s)/polyval(nump,s)) KatBO = fgain(BOpnts) # Selects only the positive gains at the Breakout points KatBO = KatBO[KatBO >= 0] return KatBO, BOpnts
gss1 = ss(A,B,C,D) gss = ss(A,B,C2,D2) gz = c2d(gss,ts,'zoh') # Control design wn = 10 xi1 = np.sqrt(2)/2 xi2 = np.sqrt(3)/2 xi2 = 0.85 cl_p1 = [1,2*xi1*wn,wn**2] cl_p2 = [1,2*xi2*wn,wn**2] cl_p3 = [1,wn] cl_poly1 = sp.polymul(cl_p1,cl_p2) cl_poly = sp.polymul(cl_poly1,cl_p3) cl_poles = sp.roots(cl_poly) # Desired continous poles cl_polesd = sp.exp(cl_poles*ts) # Desired discrete poles # Add discrete integrator for steady state zero error Phi_f = np.vstack((gz.A,-gz.C*ts)) Phi_f = np.hstack((Phi_f,[[0],[0],[0],[0],[1]])) G_f = np.vstack((gz.B,zeros((1,1)))) # Pole placement k = place(Phi_f,G_f,cl_polesd) # Observer design - reduced order observer poli_of = 5*sp.roots(cl_poly1) # Desired continous poles poli_o = 5*cl_poles[0:2] poli_oz = sp.exp(poli_o*ts) poli_ozf = sp.exp(poli_of*ts)
def real_roots(expr): import scipy as sc r = sc.roots(coeffs(expr)) return np.real( r[np.imag(r)==0] )
def roots(expr): import scipy as sc return sc.roots(coeffs(expr))
def lars_regression_noise_old(Yp, X, positive, noise, verbose=False): """ Run LARS for regression problems with LASSO penalty, with optional positivity constraints Author: Andrea Giovannucci. Adapted code from Eftychios Pnevmatikakis Parameters: ------- Yp: Yp[:,t] is the observed data at time t X: the regresion problem is Yp=X*W + noise maxcomps: maximum number of active components to allow positive: a flag to enforce positivity noise: the noise of the observation equation. if it is not provided as an argument, the noise is computed from the variance at the end point of the algorithm. The noise is used in the computation of the Cp criterion. Returns: ------- Ws: weights from each iteration lambdas: lambda_ values at each iteration Cps: C_p estimates last_break: last_break(m) == n means that the last break with m non-zero weights is at Ws(:,:,n) See Also: ------- LARS : https://en.wikipedia.org/wiki/Least-angle_regression group Lasso : """ # INITAILIZATION T = len(Yp) # of time steps k = 1 Yp = np.squeeze(np.asarray(Yp)) # necessary for matrix multiplications Yp = np.expand_dims(Yp, axis=1) _, T = np.shape(Yp) # of time steps _, N = np.shape(X) # of compartments # 1 : Start with all Weights equal to zero. maxcomps = N W = np.zeros((N, k)) active_set = np.zeros((N, k)) visited_set = np.zeros((N, k)) lambdas = [] # Just preallocation. Ws may end with more or less than maxcomp columns Ws = [] r = np.expand_dims(np.dot(X.T, Yp.flatten()), axis=1) # N-dim vector M = np.dot(-X.T, X) # N x N matrix # %% begin main loop i = 0 flag = 0 while 1: if flag == 1: W_lam = 0 break # % calculate new gradient component if necessary if i > 0 and new >= 0 and visited_set[new] == 0: # AG NOT CLEAR HERE visited_set[new] = 1 # % remember this direction was computed # % Compute full gradient of Q dQ = r + np.dot(M, W) # % Compute new W if i == 0: if positive: dQa = dQ else: dQa = np.abs(dQ) lambda_, new = np.max(dQa), np.argmax(dQa) if lambda_ < 0: print('All negative directions!') break else: # 2 : Find the predictor x_{j} most correlated with y # % calculate vector to travel along avec, gamma_plus, gamma_minus = calcAvec( new, dQ, W, lambda_, active_set, M, positive) # % calculate time of travel and next new direction if new == -1: # % if we just dropped a direction we don't allow it to emerge if dropped_sign == 1: # % with the same sign gamma_plus[dropped] = np.inf else: gamma_minus[dropped] = np.inf # 3 : Increase the coefficient W in the direction of the sign of its correlation with y # % don't consider active components gamma_plus[active_set == 1] = np.inf # % or components outside the range [0, lambda_] gamma_plus[gamma_plus <= 0] = np.inf gamma_plus[gamma_plus > lambda_] = np.inf gp_min, gp_min_ind = np.min(gamma_plus), np.argmin(gamma_plus) if positive: gm_min = np.inf # % don't consider new directions that would grow negative else: gamma_minus[active_set == 1] = np.inf gamma_minus[gamma_minus > lambda_] = np.inf gamma_minus[gamma_minus <= 0] = np.inf gm_min, gm_min_ind = np.min( gamma_minus), np.argmin(gamma_minus) [g_min, which] = np.min(gp_min), np.argmin(gp_min) # % if there are no possible new components, try move to the end if g_min == np.inf: g_min = lambda_ # % This happens when all the components are already active or, if positive==1, # when there are no new positive directions # % LARS check (is g_min*avec too large?) gamma_zero = old_div(-W[active_set == 1], np.squeeze(avec)) gamma_zero_full = np.zeros((N, k)) gamma_zero_full[active_set == 1] = gamma_zero gamma_zero_full[gamma_zero_full <= 0] = np.inf gz_min, gz_min_ind = np.min( gamma_zero_full), np.argmin(gamma_zero_full) # 4: Increase Wj,Wk in their joint least squares direction, until some other predictor x_{m} # has as much correlation with the residual r. (see 5) if gz_min < g_min: if verbose: print(('DROPPING active weight:' + str(gz_min_ind))) active_set[gz_min_ind] = 0 dropped = gz_min_ind dropped_sign = np.sign(W[dropped]) W[gz_min_ind] = 0 avec = avec[gamma_zero != gz_min] g_min = gz_min new = -1 elif g_min < lambda_: if which == 0: new = gp_min_ind if verbose: print(('new positive component:' + str(new))) else: new = gm_min_ind print(('new negative component:' + str(new))) W[active_set == 1] = W[active_set == 1] + \ np.dot(g_min, np.squeeze(avec)) if positive: if any(W < 0): flag = 1 lambda_ = lambda_ - g_min # % Update weights and lambdas lambdas.append(lambda_) Ws.append(W.copy()) # 5 : Take residuals r=y-y_ along the way. Stop when some other predictor x_{k} # has as much correlation with r as x_{j} has. if len((Yp - np.dot(X, W)).shape) > 2: res = scipy.linalg.norm(np.squeeze(Yp - np.dot(X, W)), 'fro') ** 2 else: res = scipy.linalg.norm(Yp - np.dot(X, W), 'fro') ** 2 # % Check finishing conditions if lambda_ == 0 or (new >= 0 and np.sum(active_set) == maxcomps) or (res < noise): if verbose: print('end. \n') break # 6: Continue until: all predictors are in the model if new >= 0: active_set[new] = 1 i = i + 1 Ws_old = Ws # end main loop #%% final calculation of mus Ws = np.asarray(np.swapaxes(np.swapaxes(Ws_old, 0, 1), 1, 2)) if flag == 0: if i > 0: Ws = np.squeeze(Ws[:, :, :len(lambdas)]) w_dir = old_div(-(Ws[:, i] - Ws[:, i - 1]), (lambdas[i] - lambdas[i - 1])) Aw = np.dot(X, w_dir) y_res = np.squeeze( Yp) - np.dot(X, Ws[:, i - 1] + w_dir * lambdas[i - 1]) ld = scipy.roots([scipy.linalg.norm(Aw) ** 2, -2 * np.dot(Aw.T, y_res), np.dot(y_res.T, y_res) - noise]) lam = ld[np.intersect1d( np.where(ld > lambdas[i]), np.where(ld < lambdas[i - 1]))] if len(lam) == 0 or np.any(lam) < 0 or np.any(~np.isreal(lam)): lam = np.array([lambdas[i]]) W_lam = Ws[:, i - 1] + np.dot(w_dir, lambdas[i - 1] - lam[0]) else: warn('LARS REGRESSION NOT SOLVABLE, USING NN LEAST SQUARE') W_lam = scipy.optimize.nnls(X, np.ravel(Yp))[0] lam = 10 else: W_lam = 0 Ws = 0 lambdas = 0 lam = 0 return Ws, lambdas, W_lam, lam, flag
def TB_lib(compuesto, T): """Librería de cálculo de la ecuación de estado de Trebble-Bishnoi""" if compuesto.Tc!=0.0 and compuesto.Pc.atm!=0.0 and compuesto.vc!=0.0: Zc=compuesto.Pc.atm*compuesto.vc*compuesto.peso_molecular/R_atml/compuesto.Tc else: if compuesto.f_acent<0.225: TcPc=775.9+12009*compuesto.f_acent-57335*compuesto.f_acent**2+91393*compuesto.f_acent**3 elif compuesto.f_acent<=1.: TcPc=1876-1160*compuesto.f_acent else: TcPc=compuesto.Tc*compuesto.Pc.MPa if compuesto.f_acent>=-0.14: Zc=0.29-0.0885*compuesto.f_acent-0.0005/((compuesto.Tc*compuesto.Pc.MPa)**0.5-TcPc**0.5) else: Zc=0.3024 d=0.341*compuesto.vc*compuesto.peso_molecular-0.005 Xc=1.075*Zc Dc=d*compuesto.Pc.atm/R_atml/compuesto.Tc Cc=1-3*Xc B=roots([1, 2-3*Xc, 3*Xc**2, -Dc**2-Xc**3]) Bpositivos=[] for i in range(3): if B[i]>0: Bpositivos.append(B[i]) Bc=min(Bpositivos) Ac=3*Xc**2+2*Bc*Cc+Bc+Cc+Bc**2+Dc**2 if compuesto.indice==212 and compuesto.tr(T)<=1: q1=-0.31913 elif compuesto.f_acent<-0.1: q1=0.66208+4.63961*compuesto.f_acent+7.45183*compuesto.f_acent**2 elif compuesto.f_acent<=0.4: q1=0.35+0.7924*compuesto.f_acent+0.1875*compuesto.f_acent**2-28.93*(0.3-Zc)**2 elif compuesto.f_acent>0.4: q1=0.32+0.9424*compuesto.f_acent-28.93*(0.3-Zc)**2 if compuesto.f_acent<-0.0423: q2=0 elif compuesto.f_acent<=0.3: q2=0.05246+1.15058*compuesto.f_acent-1.99348*compuesto.f_acent**2+1.5949*compuesto.f_acent**3-1.39267*compuesto.f_acent**4 else: q2=0.17959+0.23471*compuesto.f_acent alfa=exp(q1*(1-compuesto.tr(T))) if T<=compuesto.Tc: beta=1.+q2*(1-compuesto.tr(T)+log(compuesto.tr(T))) else: beta=1 ac=Ac*R_atml**2*compuesto.Tc**2/compuesto.Pc.atm bc=Bc*R_atml*compuesto.Tc/compuesto.Pc.atm c=Cc*R_atml*compuesto.Tc/compuesto.Pc.atm return ac*alfa, bc*beta, c, d def TB_Fugacidad(self, T, P): """Método de cálculo de la fugacidad mediante la ecuación de estado de Trebble-Bishnoi""" a, b, c, d, q1, q2=self.TB_lib(T, P) z=self.TB_Z(T, P) A=a*P/R_atml**2/T**2 B=b*P/R_atml/T u=1+c/b t=1+6*c/b+c**2/b**2+4*d**2/b**2 tita=abs(t)**0.5 if t>=0: lamda=log((2*z+B*(u-tita))/(2*z+B*(u+tita))) else: lamda=2*arctan((2*z+u*B)/B/tita)-pi fi=z-1-log(z-B)+A/B/tita*lamda return unidades.Pressure(P*exp(fi), "atm") def TB_U_exceso(self, T, P): """Método de cálculo de la energía interna de exceso mediante la ecuación de estado de Trebble-Bishnoi""" a, b, c, d, q1, q2=self.TB_lib(T, P) v=self.TB_V(T, P) z=P*v/R_atml/T A=a*P/R_atml**2/T**2 B=b*P/R_atml/T u=1+c/b t=1+6*c/b+c**2/b**2+4*d**2/b**2 tita=abs(t)**0.5 if t>=0: lamda=log((2*z+B*(u-tita))/(2*z+B*(u+tita))) else: lamda=2*arctan((2*z+u*B)/B/tita)-pi delta=v**2+(b+c)*v-b*c-d**2 beta=1.+q2*(1-self.tr(T)+log(self.tr(T))) da=-q1*a/self.Tc if self.tr(T)<=1.0: db=b/beta*(1/T-1/self.Tc) else: db=0 U=lamda/b/tita*(a-da*T)+db*T*(-R_atml*T/(v-b)+a/b**2/t*((v*(3*c+b)-b*c+c**2-2*d**2)/delta+(3*c+b)*lamda/b/tita)) #atm*l/mol return unidades.Enthalpy(U*101325/1000/self.peso_molecular, "Jkg") def TB_H_exceso(self, T, P): """Método de cálculo de la entalpía de exceso mediante la ecuación de estado de Trebble-Bishnoi""" p=unidades.Pressure(P, "atm") U=self.TB_U_exceso(T, P) a, b, c, d, q1, q2=self.TB_lib(T, P) t=1+6*c/b+c**2/b**2+4*d**2/b**2 if t>=0: v=self.TB_V(T, P).m3g*self.peso_molecular return unidades.Enthalpy(p*v-R/T/self.peso_molecular+U.Jg, "Jg") else: Z=self.TB_Z(T, P) return unidades.Enthalpy(R/self.peso_molecular*T*(Z-1)+U.Jg, "Jg") def TB_Entalpia(self, T, P): """Método de cálculo de la entalpía mediante la ecuación de estado de Trebble-Bishnoi""" Ho=self._Ho(T) Delta=self.TB_H_exceso(T, P) return unidades.Enthalpy(Delta+Ho) def TB_S_exceso(self, T, P): """Método de cálculo de la entropía de exceso mediante la ecuación de estado de Trebble-Bishnoi""" H=self.TB_H_exceso(T, P) f=self.TB_Fugacidad(T, P) return unidades.SpecificHeat(H.Jg/T-R/self.peso_molecular*log(f.atm/P), "JgK") def TB_Entropia(self, T, P): """Método de cálculo de la entropía mediante la ecuación de estado de Trebble-Bishnoi""" So=self._so(T) Delta=self.TB_S_exceso(T, P) return unidades.SpecificHeat(Delta+So) def TB_Cv_exceso(self, T, P): """Método de cálculo de la capacidad calorífica a volumen constante de exceso mediante la ecuación de estado de Trebble-Bishnoi""" a, b, c, d, q1, q2=self.TB_lib(T, P) v=self.TB_V(T, P) z=P*v/R_atml/T t=1+6*c/b+c**2/b**2+4*d**2/b**2 tita=abs(t)**0.5 A=a*P/R_atml**2/T**2 B=b*P/R_atml/T u=1+c/b delta=v**2+(b+c)*v-b*c-d**2 beta=1.+q2*(1-self.tr(T)+log(self.tr(T))) da=-q1*a/self.Tc dda=q1**2*a/self.Tc**2 if self.tr(T)<=1.0: db=b/beta*(1/T-1/self.Tc) ddb=-q2*b/beta/T**2 else: db=0 ddb=0 dt=-db/b**2*(6*c+2*c**2/b+8*d**2/b) dtita=abs(dt)/20 if t>=0: lamda=log((2*z+B*(u-tita))/(2*z+B*(u+tita))) dlamda=(db-db*tita-b*dtita)/(2*v+b+c-b*tita)-(db+db*tita+b*dtita)/((2*v+b+c+b*tita)) else: lamda=2*arctan((2*z+u*B)/B/tita)-pi dlamda=2/(1+((2*v+b+c)/b/tita)**2)*(db/b/tita-(2*v+b+c)*(db/b**2/tita+dtita/b/tita**2)) Cv=1/b/tita*(dlamda*(a-da*T)-lamda*dda*T-lamda*(a-da*T)*(db/b+dtita/tita))+(ddb*T+db)*(-R_atml*T/(v-b)+a/b**2/t*((v*(3*c+b)-b*c+c**2-2*d**2)/delta+(3*c+b)*lamda/b/tita))+db*T*(-R_atml/(v-b)-R_atml*T*db/(v-b)**2+1/b**2/t*(da-2*a*db/b-a*dt/t)*((v*(3*c+b)-b*c+c**2-2*d**2)/delta+(3*c+b)*lamda/b/tita)+a/b**2/t*(db*(v-c)*(v**2-2*c*v-c**2+d**2)/delta**2+db*lamda/b/tita+(3*c+b)/b/tita*(dlamda-lamda*(db/b+dtita/tita)))) return unidades.SpecificHeat(Cv*101325/1000/self.peso_molecular, "JkgK") def TB_Cv(self, T, P): """Método de cálculo de la capacidad calorifica a volumen constante mediante la ecuación de estado de Trebble-Bishnoi""" Cvo=self.Cv_ideal(T) Delta=self.TB_Cv_exceso(T, P) return unidades.SpecificHeat(Delta+Cvo) def TB_Cp_exceso(self, T, P): """Método de cálculo de la capacidad calorífica a presión constante de exceso mediante la ecuación de estado de Trebble-Bishnoi""" a, b, c, d, q1, q2=self.TB_lib(T, P) v=self.TB_V(T, P) Cv=self.TB_Cv_exceso(T, P) beta=1.+q2*(1-self.tr(T)+log(self.tr(T))) delta=v**2+(b+c)*v-b*c-d**2 da=-q1*a/self.Tc if self.tr(T)<=1.0: db=b/beta*(1/T-1/self.Tc) else: db=0 dpdt=R_atml/(v-b)+R*T*db/(v-b)**2-da/delta+a*(v-c)*db/delta**2 dpdv=-R_atml*T/(v-b)**2+a*(2*v+b+c)/delta**2 Cp=-R-T*dpdt**2/dpdv*101325/1000+Cv.JgK*self.peso_molecular return unidades.SpecificHeat(Cp/self.peso_molecular, "JgK") def TB_Cp(self, T, P): """Método de cálculo de la capacidad calorifica a presión constante mediante la ecuación de estado de Trebble-Bishnoi""" Cpo=self.Cp_ideal(T) Delta=self.TB_Cp_exceso(T, P) return unidades.SpecificHeat(Delta+Cpo) def TB_Joule_Thomson(self, T, P): """Método de cálculo del coeficiente de Joule-Thomson mediante la ecuación de estado de Trebble-Bishnoi""" v=self.TB_V(T, P) Cp=self.TB_Cp(T, P) a, b, c, d, q1, q2=self.TB_lib(T, P) beta=1.+q2*(1-self.tr(T)+log(self.tr(T))) delta=v**2+(b+c)*v-b*c-d**2 da=-q1*a/self.Tc if self.tr(T)<=1.0: db=b/beta*(1/T-1/self.Tc) else: db=0 dpdt=R_atml/(v-b)+R*T*db/(v-b)**2-da/delta+a*(v-c)*db/delta**2 dpdv=-R_atml*T/(v-b)**2+a*(2*v+b+c)/delta**2 return -(T*dpdt+v*dpdv)/Cp/dpdv
def lars_regression_noise_old(Yp, X, positive, noise, verbose=False): """ Run LARS for regression problems with LASSO penalty, with optional positivity constraints Author: Andrea Giovannucci. Adapted code from Eftychios Pnevmatikakis Input Parameters: Yp: Yp[:,t] is the observed data at time t X: the regresion problem is Yp=X*W + noise maxcomps: maximum number of active components to allow positive: a flag to enforce positivity noise: the noise of the observation equation. if it is not provided as an argument, the noise is computed from the variance at the end point of the algorithm. The noise is used in the computation of the Cp criterion. Output Parameters: Ws: weights from each iteration lambdas: lambda_ values at each iteration TODO: W_lam, lam, flag Cps: C_p estimates last_break: last_break(m) == n means that the last break with m non-zero weights is at Ws(:,:,n) """ #%% # verbose=true; # do NNLS first # if hard noise constraint problem infeasible we are done, otherwise good for warm-starting # W_lam, RSS = scipy.optimize.nnls(X, np.ravel(Yp)) # RSS = RSS * RSS # if RSS > noise: # hard noise constraint problem infeasible # return 0, 0, W_lam, 0, 0 # # while 1: # eliminate = [] # for i in np.where(W_lam[:-1] > 0)[0]: # W_lam[:-1] to skip background # mask = W_lam > 0 # mask[i] = 0 # Wtmp, tmp = scipy.optimize.nnls(X * mask, np.ravel(Yp)) # if tmp * tmp < noise: # eliminate.append([i, tmp]) # if eliminate == []: # return 0, 0, W_lam, 0, 0 # else: # W_lam[eliminate[np.argmin(np.array(eliminate)[:, 1])][0]] = 0 # obsolete stuff below # solve hard noise constraint problem T = len(Yp) # of time steps # A = Yp.dot(X) # B = X.T.dot(X) # dB = 1 / np.diag(B) # import pdb # pdb.set_trace() # z = np.sqrt(1 / dB) # lam = np.max(1 * np.sqrt(noise / T) * z) # counter = 0 # res = X.dot(W_lam) - Yp # tmp = X.dot(dB) # aa = tmp.dot(tmp) # while (RSS < noise * .9999 or RSS > noise * 1.0001) and counter < 20: # counter += 1 # bb = tmp.dot(res) # cc = RSS - noise # if counter > 1: # lam += (bb + (0 if bb * bb <= aa * cc else np.sqrt(bb * bb - aa * cc))) / aa # for _ in range(3): # for i in range(len(W_lam)): # W_lam[i] = np.clip(W_lam[i] + (A[i] - W_lam.dot(B)[i] - lam) * dB[i], 0, np.inf) # res = X.dot(W_lam) - Yp # RSS = res.dot(res) # return 1, 1, W_lam, 1, 1 k = 1 Yp = np.squeeze(np.asarray(Yp)) Yp = np.expand_dims(Yp, axis=1) # necessary for matrix multiplications _, T = np.shape(Yp) # of time steps _, N = np.shape(X) # of compartments maxcomps = N W = np.zeros((N, k)) active_set = np.zeros((N, k)) visited_set = np.zeros((N, k)) lambdas = [] # =np.zeros((W.shape[0],W.shape[1],maxcomps)); # Just preallocation. Ws may end with more or less than maxcomp columns Ws = [] r = np.expand_dims(np.dot(X.T, Yp.flatten()), axis=1) # N-dim vector M = np.dot(-X.T, X) # N x N matrix #%% begin main loop i = 0 flag = 0 while 1: if flag == 1: W_lam = 0 break #% calculate new gradient component if necessary if i > 0 and new >= 0 and visited_set[new] == 0: # AG NOT CLEAR HERE visited_set[new] = 1 # % remember this direction was computed #% Compute full gradient of Q dQ = r + np.dot(M, W) #% Compute new W if i == 0: if positive: dQa = dQ else: dQa = np.abs(dQ) lambda_, new = np.max(dQa), np.argmax(dQa) if lambda_ < 0: print('All negative directions!') break else: #% calculate vector to travel along avec, gamma_plus, gamma_minus = calcAvec(new, dQ, W, lambda_, active_set, M, positive) # % calculate time of travel and next new direction if new == -1: # % if we just dropped a direction we don't allow it to emerge if dropped_sign == 1: # % with the same sign gamma_plus[dropped] = np.inf else: gamma_minus[dropped] = np.inf gamma_plus[active_set == 1] = np.inf # % don't consider active components gamma_plus[gamma_plus <= 0] = np.inf # % or components outside the range [0, lambda_] gamma_plus[gamma_plus > lambda_] = np.inf gp_min, gp_min_ind = np.min(gamma_plus), np.argmin(gamma_plus) if positive: gm_min = np.inf # % don't consider new directions that would grow negative else: gamma_minus[active_set == 1] = np.inf gamma_minus[gamma_minus > lambda_] = np.inf gamma_minus[gamma_minus <= 0] = np.inf gm_min, gm_min_ind = np.min(gamma_minus), np.argmin(gamma_minus) [g_min, which] = np.min(gp_min), np.argmin(gp_min) if g_min == np.inf: # % if there are no possible new components, try move to the end g_min = lambda_ # % This happens when all the components are already active or, if positive==1, when there are no new positive directions #% LARS check (is g_min*avec too large?) gamma_zero = old_div(-W[active_set == 1], np.squeeze(avec)) gamma_zero_full = np.zeros((N, k)) gamma_zero_full[active_set == 1] = gamma_zero gamma_zero_full[gamma_zero_full <= 0] = np.inf gz_min, gz_min_ind = np.min(gamma_zero_full), np.argmin(gamma_zero_full) if gz_min < g_min: # print 'check_here' if verbose: print(('DROPPING active weight:' + str(gz_min_ind))) active_set[gz_min_ind] = 0 dropped = gz_min_ind dropped_sign = np.sign(W[dropped]) W[gz_min_ind] = 0 avec = avec[gamma_zero != gz_min] g_min = gz_min new = -1 # new = 0; elif g_min < lambda_: if which == 0: new = gp_min_ind if verbose: print(('new positive component:' + str(new))) else: new = gm_min_ind print(('new negative component:' + str(new))) W[active_set == 1] = W[active_set == 1] + np.dot(g_min, np.squeeze(avec)) if positive: if any(W < 0): # min(W); flag = 1 #%error('negative W component'); lambda_ = lambda_ - g_min #% Update weights and lambdas lambdas.append(lambda_) Ws.append(W.copy()) # print Ws if len((Yp - np.dot(X, W)).shape) > 2: res = scipy.linalg.norm(np.squeeze(Yp - np.dot(X, W)), 'fro')**2 else: res = scipy.linalg.norm(Yp - np.dot(X, W), 'fro')**2 #% Check finishing conditions if lambda_ == 0 or (new >= 0 and np.sum(active_set) == maxcomps) or (res < noise): if verbose: print('end. \n') break #% if new >= 0: active_set[new] = 1 i = i + 1 Ws_old = Ws # end main loop #%% final calculation of mus Ws = np.asarray(np.swapaxes(np.swapaxes(Ws_old, 0, 1), 1, 2)) if flag == 0: if i > 0: Ws = np.squeeze(Ws[:, :, :len(lambdas)]) w_dir = old_div(-(Ws[:, i] - Ws[:, i - 1]), (lambdas[i] - lambdas[i - 1])) Aw = np.dot(X, w_dir) y_res = np.squeeze(Yp) - np.dot(X, Ws[:, i - 1] + w_dir * lambdas[i - 1]) ld = scipy.roots([scipy.linalg.norm(Aw)**2, -2 * np.dot(Aw.T, y_res), np.dot(y_res.T, y_res) - noise]) lam = ld[np.intersect1d(np.where(ld > lambdas[i]), np.where(ld < lambdas[i - 1]))] if len(lam) == 0 or np.any(lam) < 0 or np.any(~np.isreal(lam)): lam = np.array([lambdas[i]]) W_lam = Ws[:, i - 1] + np.dot(w_dir, lambdas[i - 1] - lam[0]) else: warn('LARS REGRESSION NOT SOLVABLE, USING NN LEAST SQUARE') W_lam = scipy.optimize.nnls(X, np.ravel(Yp))[0] # problem = picos.Problem(X,Yp) # W_lam = problem.add_variable('W_lam', X.shape[1]) # problem.set_objective('min', 1|W_lam) # problem.add_constraint(W_lam >= 0) # problem.add_constraint(picos.norm(matrix(Yp.astype(np.float))-matrix(X.astype(np.float))*W_lam,2)<=np.sqrt(noise)) # sel_solver = [] # problem.solver_selection() # problem.solve(verbose=True) # cvx_begin quiet # variable W_lam(size(X,2)); # minimize(sum(W_lam)); # subject to # W_lam >= 0; # norm(Yp-X*W_lam)<= sqrt(noise); # cvx_end lam = 10 else: W_lam = 0 Ws = 0 lambdas = 0 lam = 0 return Ws, lambdas, W_lam, lam, flag
def main(argv): ################################################################## # Parse arguments fitopt = {0:'gaussian',1:'2nd order polynome'} from optparse import OptionParser parser = OptionParser() parser.add_option( '--fittype', help='Which type of fit will be performed. Options are %r.'%fitopt, type='int', default=0) opt,args = parser.parse_args(argv) print 'Will find minimum by %s fitting...'%(fitopt[opt.fittype]) ################################################################## # Parameters HJD0 = 2450111.5144 Porb = 0.44267714 # ################################################################## # Input definition _path = os.path.expanduser('~/Documents/analise/CAL87/emap_0305keV_rateall') #_cldat = 'cal87_0305keV_rateall.dat.122' #'cal87_0305keV_rateall.dat.122' #_cldat = '../cal87_0153250101_b250s_051keV_master_pnm1m2.tfits' #'cal87_0305keV_rateall.dat.122' _cldat = '../cal87_0153250101_b250s_0514keV_master_pnm1m2.tfits' #'cal87_0305keV_rateall.dat.122' #_clmod = 'cal87_0305keV_rateall.prd.122' # ################################################################## # Reading data #cldat = np.loadtxt(os.path.join(_path,_cldat),unpack=True) #clmod = np.loadtxt(os.path.join(_path,_clmod),unpack=True) table = pyfits.open(os.path.join(_path,_cldat)) time_hjd = table[1].data['TIME']/86400.+2450814.5000 rate_all = table[1].data['RATE_ALL'] error_all = table[1].data['ERROR_ALL'] # ################################################################## # Fitting if opt.fittype == 0: phase = (time_hjd - HJD0) / Porb phase = phase-np.floor(phase) phase[phase > 0.5] -= 1.0 sort = phase.argsort() cldat = np.array([phase[sort],rate_all[sort],error_all[sort]]) func = lambda p,x: p[0] + p[1]*np.exp(-((x-p[2])/p[3])**2.0) fitfunc = lambda p,x,y: y - func(p,x) p0 = [np.mean(cldat[1]),np.min(cldat[1])-np.mean(cldat[1]),1e-1,0.15] sol,cov,info,mesg,ier = leastsq(fitfunc, p0, args=(cldat[0],cldat[1]), full_output=True) print sol py.errorbar( cldat[0], cldat[1], cldat[2], fmt='rs:', capsize=0) py.plot(cldat[0], func(sol,cldat[0]),'k-') if opt.fittype == 1: # Fit parabola phase = (time_hjd - HJD0) / Porb ciclos = np.unique(np.floor(phase)) print '# - %i cycles, fitting %i eclipses...'%(len(ciclos),len(ciclos)-1) for i in range(len(ciclos)-1): print '## - Fitting from phases [%f:%f]'%(ciclos[i+1]-0.5,ciclos[i+1]+0.5) mask = np.bitwise_and(phase >ciclos[i+1]-0.5,phase < ciclos[i+1]+0.5) cldat = np.array([phase[mask]-ciclos[i+1],rate_all[mask],error_all[mask]]) mask = np.bitwise_and(cldat[0] > -0.1, cldat[0]<0.1) p,residuals,rank,singular_values,rcond = polyfit(cldat[0][mask], cldat[1][mask], deg=2,full=True) print '# - Bootstraping...' ndata = MC_sim(cldat[1][mask],cldat[2][mask],100) bootpar = np.array([p]) bootroots = np.array([roots(p).real]) for j in range(len(ndata)): bp = polyfit( cldat[0][mask], ndata[j], deg=2,full=False) bootpar = np.append(bootpar,bp) bootroots = np.append(bootroots,np.roots(bp).real) bootpar = bootpar.reshape(-1,3) print bootpar.shape,bootpar[0] print p,singular_values print roots(p) print bootroots.mean(),'+/-',bootroots.std() py.subplot(2,len(ciclos)-1,i+1) py.errorbar( cldat[0][mask], cldat[1][mask], cldat[2][mask], fmt='rs:', capsize=0) py.plot(cldat[0][mask], polyval(p,cldat[0][mask]),'k-') py.subplot(2,len(ciclos)-1,len(ciclos)-1+i+1) py.hist(bootroots,bins=40) py.show() return 0 mask = np.bitwise_and(cldat[0] > -0.05, cldat[0]<0.09) p,residuals,rank,singular_values,rcond = polyfit(cldat[0][mask], cldat[1][mask], deg=2,full=True) py.errorbar( cldat[0][mask], cldat[1][mask], cldat[2][mask], fmt='rs:', capsize=0) py.plot(cldat[0][mask], polyval(p,cldat[0][mask]),'k-') print p,singular_values print roots(p) # ################################################################## # End py.show() return 0
def duff_amp_solve(mu = 0.01, k = 0.013, alpha = .2, sigma = (-0.5,.5)): sigma = sp.linspace(sigma[0],sigma[1],1000) #print(sigma.size) #print(sigma) a = sp.zeros((sigma.size,3))*1j first = 1 #print(a) for idx, sig in enumerate(sigma): #print(idx) p = sp.array([alpha**2, 0, -16./3.*alpha*sig, 0, 64./9.*(mu**2 + sig**2),0,-64./9.*k**2]) soln = sp.roots(p) #print('original soln') #print(soln) #print(soln) #print(sp.sort(soln)[0:5:2]) sorted_indices = sp.argsort(sp.absolute(soln)) a[idx,:] = soln[sorted_indices][0:5:2] if sum(sp.isreal(a[idx,:])) == 3 and first == 1: first = 0 #if sp.absolute(a[idx,2] - a[idx,1]) < sp.absolute(a[idx,1] - a[idx,0]): solns = sp.sort(sp.absolute(a[idx,:])) #print(solns) if (solns[2] - solns[1]) > (solns[1]-solns[0]): ttl = 'Hardening spring' softening = False else: ttl = 'Softening spring' softening = True #print(solns) first_bif_index = idx if first == 0 and sum(sp.isreal(a[idx,:])) == 1: first = 2 second_bif_index = idx if softening == True: low_sig = sigma[0:second_bif_index] low_amp = sp.zeros(second_bif_index) low_amp[0:first_bif_index] = sp.absolute(sp.sum(sp.isreal(a[0:first_bif_index,:])*a[0:first_bif_index,:],axis = 1)) low_amp[first_bif_index:second_bif_index] = sp.absolute(a[first_bif_index:second_bif_index,:]).min(axis = 1) med_sig = sigma[first_bif_index:second_bif_index] med_amp = sp.sort(sp.absolute(a[first_bif_index:second_bif_index,:]),axis = 1)[:,1] high_sig = sigma[first_bif_index:] high_amp = sp.zeros(sigma.size - first_bif_index) high_amp[0:second_bif_index - first_bif_index] = sp.absolute(a[first_bif_index:second_bif_index,:]).max(axis = 1) high_amp[second_bif_index - first_bif_index:] = sp.absolute(sp.sum(sp.isreal(a[second_bif_index:,:])*a[second_bif_index:,:],axis = 1)) else: high_sig = sigma[0:second_bif_index] high_amp = sp.zeros(second_bif_index) high_amp[0:first_bif_index] = sp.absolute(sp.sum(sp.isreal(a[0:first_bif_index,:])*a[0:first_bif_index,:],axis = 1)) high_amp[first_bif_index:second_bif_index] = sp.absolute(a[first_bif_index:second_bif_index,:]).max(axis = 1) med_sig = sigma[first_bif_index:second_bif_index] med_amp = sp.sort(sp.absolute(a[first_bif_index:second_bif_index,:]),axis = 1)[:,1] low_sig = sigma[first_bif_index:] low_amp = sp.zeros(sigma.size - first_bif_index) low_amp[0:second_bif_index - first_bif_index] = sp.absolute(a[first_bif_index:second_bif_index,:]).min(axis = 1) low_amp[second_bif_index - first_bif_index:] = sp.absolute(sp.sum(sp.isreal(a[second_bif_index:,:])*a[second_bif_index:,:],axis = 1)) plt.plot(low_sig,low_amp,'-b') plt.plot(med_sig, med_amp, '--g') plt.plot(high_sig,high_amp,'-r') plt.title(ttl) plt.xlabel('$\sigma$') plt.ylabel('a') return
def lars_regression_noise(Yp, X, positive, noise,verbose=False): """ Run LARS for regression problems with LASSO penalty, with optional positivity constraints Author: Andrea Giovannucci. Adapted code from Eftychios Pnevmatikakis Input Parameters: Yp: Yp[:,t] is the observed data at time t X: the regresion problem is Yp=X*W + noise maxcomps: maximum number of active components to allow positive: a flag to enforce positivity noise: the noise of the observation equation. if it is not provided as an argument, the noise is computed from the variance at the end point of the algorithm. The noise is used in the computation of the Cp criterion. Output Parameters: Ws: weights from each iteration lambdas: lambda_ values at each iteration TODO: W_lam, lam, flag Cps: C_p estimates last_break: last_break(m) == n means that the last break with m non-zero weights is at Ws(:,:,n) """ #%% #verbose=true; k=1; Yp=np.squeeze(np.asarray(Yp)) Yp=np.expand_dims(Yp,axis=1) #necessary for matrix multiplications _,T = np.shape(Yp); # of time steps _,N = np.shape(X); # of compartments maxcomps = N; W = np.zeros((N,k)); active_set = np.zeros((N,k)); visited_set = np.zeros((N,k)); lambdas = []; Ws=[] #=np.zeros((W.shape[0],W.shape[1],maxcomps)); # Just preallocation. Ws may end with more or less than maxcomp columns r = np.expand_dims(np.dot(X.T,Yp.flatten()),axis=1) # N-dim vector M = np.dot(-X.T,X); # N x N matrix #%% begin main loop i = 0; flag = 0; while 1: if flag == 1: W_lam = 0 break; #% calculate new gradient component if necessary if i>0 and new>=0 and visited_set[new] ==0: # AG NOT CLEAR HERE visited_set[new] =1; #% remember this direction was computed #% Compute full gradient of Q dQ = r + np.dot(M,W); #% Compute new W if i == 0: if positive: dQa = dQ else: dQa = np.abs(dQ) lambda_, new = np.max(dQa),np.argmax(dQa) if lambda_ < 0: print 'All negative directions!' break else: #% calculate vector to travel along avec, gamma_plus, gamma_minus = calcAvec(new, dQ, W, lambda_, active_set, M, positive) # % calculate time of travel and next new direction if new==-1: # % if we just dropped a direction we don't allow it to emerge if dropped_sign == 1: # % with the same sign gamma_plus[dropped] = np.inf; else: gamma_minus[dropped] = np.inf; gamma_plus[active_set == 1] = np.inf #% don't consider active components gamma_plus[gamma_plus <= 0] = np.inf #% or components outside the range [0, lambda_] gamma_plus[gamma_plus> lambda_] = np.inf gp_min, gp_min_ind = np.min(gamma_plus),np.argmin(gamma_plus) if positive: gm_min = np.inf; #% don't consider new directions that would grow negative else: gamma_minus[active_set == 1] = np.inf gamma_minus[gamma_minus> lambda_] =np.inf gamma_minus[gamma_minus <= 0] = np.inf gm_min, gm_min_ind = np.min(gamma_minus),np.argmin(gamma_minus) [g_min, which] = np.min(gp_min),np.argmin(gp_min) if g_min == np.inf: #% if there are no possible new components, try move to the end g_min = lambda_; #% This happens when all the components are already active or, if positive==1, when there are no new positive directions #% LARS check (is g_min*avec too large?) gamma_zero = -W[active_set == 1] / np.squeeze(avec); gamma_zero_full = np.zeros((N,k)); gamma_zero_full[active_set == 1] = gamma_zero; gamma_zero_full[gamma_zero_full <= 0] = np.inf; gz_min, gz_min_ind = np.min(gamma_zero_full),np.argmin(gamma_zero_full) if gz_min < g_min: # print 'check_here' if verbose: print 'DROPPING active weight:' + str(gz_min_ind) active_set[gz_min_ind] = 0; dropped = gz_min_ind; dropped_sign = np.sign(W[dropped]); W[gz_min_ind] = 0; avec = avec[gamma_zero != gz_min]; g_min = gz_min; new=-1 # new = 0; elif g_min < lambda_: if which == 0: new = gp_min_ind; if verbose: print 'new positive component:' + str(new) else: new = gm_min_ind; print 'new negative component:' + str(new) W[active_set == 1] = W[active_set == 1] + np.dot(g_min,np.squeeze(avec)); if positive: if any(W<0): #min(W); flag = 1; #%error('negative W component'); lambda_ = lambda_ - g_min; #% Update weights and lambdas lambdas.append(lambda_); Ws.append(W.copy()) # print Ws if len((Yp-np.dot(X,W)).shape)>2: res = scipy.linalg.norm(np.squeeze(Yp-np.dot(X,W)),'fro')**2; else: res = scipy.linalg.norm(Yp-np.dot(X,W),'fro')**2; #% Check finishing conditions if lambda_ ==0 or (new>=0 and np.sum(active_set) == maxcomps) or (res < noise): if verbose: print 'end. \n' break #% if new>=0: active_set[new] = 1 i = i + 1 Ws_old=Ws # end main loop #%% final calculation of mus Ws=np.asarray(np.swapaxes(np.swapaxes(Ws_old,0,1),1,2)) if flag == 0: if i > 0: Ws= np.squeeze(Ws[:,:,:len(lambdas)]); w_dir = -(Ws[:,i] - Ws[:,i-1])/(lambdas[i]-lambdas[i-1]); Aw = np.dot(X,w_dir); y_res = np.squeeze(Yp) - np.dot(X,Ws[:,i-1] + w_dir*lambdas[i-1]); ld = scipy.roots([scipy.linalg.norm(Aw)**2,-2*np.dot(Aw.T,y_res),np.dot(y_res.T,y_res)-noise]); lam = ld[np.intersect1d(np.where(ld>lambdas[i]),np.where(ld<lambdas[i-1]))]; if len(lam) == 0 or np.any(lam)<0 or np.any(~np.isreal(lam)): lam = np.array([lambdas[i]]); W_lam = Ws[:,i-1] + np.dot(w_dir,lambdas[i-1]-lam[0]); else: warn('LARS REGRESSION NOT SOLVABLE, USING NN LEAST SQUARE') W_lam=scipy.optimize.nnls(X,Yp) # problem = picos.Problem(X,Yp) # W_lam = problem.add_variable('W_lam', X.shape[1]) # problem.set_objective('min', 1|W_lam) # problem.add_constraint(W_lam >= 0) # problem.add_constraint(picos.norm(matrix(Yp.astype(np.float))-matrix(X.astype(np.float))*W_lam,2)<=np.sqrt(noise)) # sel_solver = [] # problem.solver_selection() # problem.solve(verbose=True) # cvx_begin quiet # variable W_lam(size(X,2)); # minimize(sum(W_lam)); # subject to # W_lam >= 0; # norm(Yp-X*W_lam)<= sqrt(noise); # cvx_end lam = 10; else: W_lam = 0; Ws = 0; lambdas = 0; lam = 0; return Ws, lambdas, W_lam, lam, flag
def find_roots(wl, epsilon, alpha, beta): """Find roots of characteristic equation. Given a wavelength, a 3x3 tensor epsilon and the tangential components of the wavevector k = (alpha,beta,gamma_i), returns the 4 possible gamma_i, i = 1,2,3,4 that satisfy the boundary conditions. """ omega = 2.0 * S.pi * c / wl K = omega ** 2 * mu0 * epsilon k0 = 2.0 * S.pi / wl K /= k0 ** 2 alpha /= k0 beta /= k0 alpha2 = alpha ** 2 alpha3 = alpha ** 3 alpha4 = alpha ** 4 beta2 = beta ** 2 beta3 = beta ** 3 beta4 = beta ** 4 coeff = [ K[2, 2], alpha * (K[0, 2] + K[2, 0]) + beta * (K[1, 2] + K[2, 1]), alpha2 * (K[0, 0] + K[2, 2]) + alpha * beta * (K[1, 0] + K[0, 1]) + beta2 * (K[1, 1] + K[2, 2]) + (K[0, 2] * K[2, 0] + K[1, 2] * K[2, 1] - K[0, 0] * K[2, 2] - K[1, 1] * K[2, 2]), alpha3 * (K[0, 2] + K[2, 0]) + beta3 * (K[1, 2] + K[2, 1]) + alpha2 * beta * (K[1, 2] + K[2, 1]) + alpha * beta2 * (K[0, 2] + K[2, 0]) + alpha * (K[0, 1] * K[1, 2] + K[1, 0] * K[2, 1] - K[0, 2] * K[1, 1] - K[2, 0] * K[1, 1]) + beta * (K[0, 1] * K[2, 0] + K[1, 0] * K[0, 2] - K[0, 0] * K[1, 2] - K[0, 0] * K[2, 1]), alpha4 * (K[0, 0]) + beta4 * (K[1, 1]) + alpha3 * beta * (K[0, 1] + K[1, 0]) + alpha * beta3 * (K[0, 1] + K[1, 0]) + alpha2 * beta2 * (K[0, 0] + K[1, 1]) + alpha2 * (K[0, 1] * K[1, 0] + K[0, 2] * K[2, 0] - K[0, 0] * K[2, 2] - K[0, 0] * K[1, 1]) + beta2 * (K[0, 1] * K[1, 0] + K[1, 2] * K[2, 1] - K[0, 0] * K[1, 1] - K[1, 1] * K[2, 2]) + alpha * beta * (K[0, 2] * K[2, 1] + K[2, 0] * K[1, 2] - K[0, 1] * K[2, 2] - K[1, 0] * K[2, 2]) + K[0, 0] * K[1, 1] * K[2, 2] - K[0, 0] * K[1, 2] * K[2, 1] - K[1, 0] * K[0, 1] * K[2, 2] + K[1, 0] * K[0, 2] * K[2, 1] + K[2, 0] * K[0, 1] * K[1, 2] - K[2, 0] * K[0, 2] * K[1, 1], ] gamma = S.roots(coeff) tmp = S.sort_complex(gamma) gamma = tmp[[3, 0, 2, 1]] # convention k = k0 * S.array([alpha * S.ones(gamma.shape), beta * S.ones(gamma.shape), gamma]).T v = S.zeros((4, 3), dtype=complex) for i, g in enumerate(gamma): H = K + [ [-beta2 - g ** 2, alpha * beta, alpha * g], [alpha * beta, -alpha2 - g ** 2, beta * g], [alpha * g, beta * g, -alpha2 - beta2], ] v[i, :] = [ (K[1, 1] - alpha2 - g ** 2) * (K[2, 2] - alpha2 - beta2) - (K[1, 2] + beta * g) ** 2, (K[1, 2] + beta * g) * (K[2, 0] + alpha * g) - (K[0, 1] + alpha * beta) * (K[2, 2] - alpha2 - beta2), (K[0, 1] + alpha * beta) * (K[1, 2] + beta * g) - (K[0, 2] + alpha * g) * (K[1, 1] - alpha2 - g ** 2), ] p3 = v[0, :] p3 /= norm(p3) p4 = v[1, :] p4 /= norm(p4) p1 = S.cross(p3, k[0, :]) p1 /= norm(p1) p2 = S.cross(p4, k[1, :]) p2 /= norm(p2) p = S.array([p1, p2, p3, p4]) q = wl / (2.0 * S.pi * mu0 * c) * S.cross(k, p) return k, p, q