def _EvolveRotationStepRK4(Mstar=None, Age=None, OmegaEnv=None, OmegaCore=None, dAge=None, params=params.paramsDefault, StarEvo=None): """Takes basic stellar parameters, evolves by timestep using classical Runge-Kutta method.""" # Get rates of change k1Env, k1Core = phys.dOmegadt(Mstar=Mstar, Age=Age, OmegaEnv=OmegaEnv, OmegaCore=OmegaCore, params=params, StarEvo=StarEvo) k2Env, k2Core = phys.dOmegadt(Mstar=Mstar, Age=Age + 0.5 * dAge, OmegaEnv=OmegaEnv + 0.5 * dAge * k1Env, OmegaCore=OmegaCore + 0.5 * dAge * k1Core, params=params, StarEvo=StarEvo) k3Env, k3Core = phys.dOmegadt(Mstar=Mstar, Age=Age + 0.5 * dAge, OmegaEnv=OmegaEnv + 0.5 * dAge * k2Env, OmegaCore=OmegaCore + 0.5 * dAge * k2Core, params=params, StarEvo=StarEvo) k4Env, k4Core = phys.dOmegadt(Mstar=Mstar, Age=Age + dAge, OmegaEnv=OmegaEnv + dAge * k3Env, OmegaCore=OmegaCore + dAge * k3Core, params=params, StarEvo=StarEvo) # Do update OmegaEnv += dAge * (k1Env + 2.0 * k2Env + 2.0 * k3Env + k4Env) / 6.0 OmegaCore += dAge * (k1Core + 2.0 * k2Core + 2.0 * k3Core + k4Core) / 6.0 return (dAge, dAge, OmegaEnv, OmegaCore)
def _JacobianRB(Mstar, Age, X, nVar, params, StarEvo): """Calculates Jacobian d(dOmega/dt)/dOmega terms for Rosenbrock solver.""" # Make array Jac = np.zeros((nVar, nVar)) # Loop over elements and fill in Jacobian for iVar in range(0, nVar): # Set perturbed X values to X X1 = copy.deepcopy(X) X2 = copy.deepcopy(X) # Perturb this variable X1[iVar] = X1[iVar] - params['deltaJac'] * X1[iVar] X2[iVar] = X2[iVar] + params['deltaJac'] * X2[iVar] # Get rates based on pertubed quantities dXdt1 = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age, OmegaEnv=X1[0], OmegaCore=X1[1], params=params, StarEvo=StarEvo)) dXdt2 = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age, OmegaEnv=X2[0], OmegaCore=X2[1], params=params, StarEvo=StarEvo)) # Fill in this column of Jacobian Jac[:, iVar] = (dXdt2[:] - dXdt1[:]) / (X2[iVar] - X1[iVar]) return Jac
def _EvolveRotationStepFE(Mstar=None, Age=None, OmegaEnv=None, OmegaCore=None, dAge=None, params=params.paramsDefault, StarEvo=None): """Takes basic stellar parameters, evolves by timestep using forward Euler method.""" # Get rates of change dOmegaEnvdt, dOmegaCoredt = phys.dOmegadt(Mstar=Mstar, Age=Age, OmegaEnv=OmegaEnv, OmegaCore=OmegaCore, params=params, StarEvo=StarEvo) # Do update OmegaEnv += dAge * dOmegaEnvdt OmegaCore += dAge * dOmegaCoredt return (dAge, dAge, OmegaEnv, OmegaCore)
def _kCoeffRB(Mstar, Age, dAge, X, Jac, nVar, CoefficientsRB, params, StarEvo): """Calculates kCoeff for Rosenbrock solver.""" # Make array for holding result kCoeff = np.zeros((nVar, CoefficientsRB['s'])) #----------------------------------------------------------------------------- # Get the function involving the Jacobian, given by (I - dt * gamma_ii * J) # note: since all gamma_ii coefficients are equal, this function only needs to # be calculated once and can then be used for all values of i # however, it must be recalculated if the timestep is changed # Set the function to -dt*J for all elements JacFunc = -dAge * CoefficientsRB['gamma'][0, 0] * Jac # Loop over diagonal elements and add 1 to each for iVar in range(0, nVar): JacFunc[iVar, iVar] += 1.0 #----------------------------------------------------------------------------- # Get k1 dXdt = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age + dAge, OmegaEnv=X[0], OmegaCore=X[1], params=params, StarEvo=StarEvo)) RateFunction = dAge * dXdt kCoeff[:, 0] = _GaussianElimination(JacFunc, RateFunction) #----------------------------------------------------------------------------- # Get k2,...ks for i in range(1, CoefficientsRB['s']): # Get intermediate values Xmid = copy.deepcopy(X) for i2 in range(0, i): Xmid += CoefficientsRB['alpha'][i, i2] * kCoeff[:, i2] # Get intermediate rates dXdt = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age + dAge, OmegaEnv=Xmid[0], OmegaCore=Xmid[1], params=params, StarEvo=StarEvo)) # Get the rate function RateFunction = dAge * dXdt for i2 in range(0, i): for iVar in range(0, nVar): RateFunction[iVar] += dAge * CoefficientsRB['gamma'][ i, i2] * np.sum(Jac[iVar, :] * kCoeff[:, i2]) # Get k value for this step kCoeff[:, i] = _GaussianElimination(JacFunc, RateFunction) #----------------------------------------------------------------------------- return kCoeff
def _EvolveRotationStepRKF(Mstar=None, Age=None, OmegaEnv=None, OmegaCore=None, dAgeMax=None, dAge=None, params=params.paramsDefault, StarEvo=None): """Takes basic stellar parameters, evolves by timestep using Runge-Kutta-Fehlberg method.""" # Start with dAge as timestep dAgeNew = dAge # Setup array to hold integration values X = np.array([OmegaEnv, OmegaCore]) # Start iterating until got accuracy desired while True: # Set dAge dAge = dAgeNew # k1 k1 = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age, OmegaEnv=X[0], OmegaCore=X[1], params=params, StarEvo=StarEvo)) # k2 Age2 = Age + (1.0 / 5.0) * dAge X2 = X + (1.0 / 5.0) * dAge * k1 k2 = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age2, OmegaEnv=X2[0], OmegaCore=X2[1], params=params, StarEvo=StarEvo)) # k3 Age3 = Age + (3.0 / 10.0) * dAge X3 = X + (3.0 / 40.0) * dAge * k1 + (9.0 / 40.0) * dAge * k2 k3 = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age3, OmegaEnv=X3[0], OmegaCore=X3[1], params=params, StarEvo=StarEvo)) # k4 Age4 = Age + (3.0 / 5.0) * dAge X4 = X + (3.0 / 10.0) * dAge * k1 - (9.0 / 10.0) * dAge * k2 + ( 6.0 / 5.0) * dAge * k3 k4 = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age4, OmegaEnv=X4[0], OmegaCore=X4[1], params=params, StarEvo=StarEvo)) # k5 Age5 = Age + dAge X5 = X - (11.0 / 54.0) * dAge * k1 + (5.0 / 2.0) * dAge * k2 - ( 70.0 / 27.0) * dAge * k3 + (35.0 / 27.0) * dAge * k4 k5 = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age5, OmegaEnv=X5[0], OmegaCore=X5[1], params=params, StarEvo=StarEvo)) # k6 Age6 = Age + (7.0 / 8.0) * dAge X6 = X + (1631.0 / 55296.0) * dAge * k1 + ( 175.0 / 512.0) * dAge * k2 + (575.0 / 13824.0) * dAge * k3 + ( 44275.0 / 110592.0) * dAge * k4 + (253.0 / 4096.0) * dAge * k5 k6 = np.array( phys.dOmegadt(Mstar=Mstar, Age=Age6, OmegaEnv=X6[0], OmegaCore=X6[1], params=params, StarEvo=StarEvo)) # Calculate candidate update Xnew = X + (37.0 / 378.0) * dAge * k1 + (250.0 / 621.0) * dAge * k3 + ( 125.0 / 594.0) * dAge * k4 + (512.0 / 1771.0) * dAge * k6 # Calculate forth order update Xforth = X + (2825.0 / 27648.0) * dAge * k1 + ( 18575.0 / 48384.0) * dAge * k3 + (13525.0 / 55296.0) * dAge * k4 + ( 277.0 / 14336.0) * dAge * k5 + (1.0 / 4.0) * dAge * k6 # Get error in this timestep for each species and grid point Delta = Xnew - Xforth # Get the factor by which to change dt # Need to take care here if Delta=0 since this can happen if dX/dt=0 over the entire timestep if (np.min(np.abs(Delta)) == 0.0): dAgeFactor = 1.5 else: dAgeFactor = np.min(np.abs(params['DeltaDesired'] * X / Delta)) # Get new dt dAgeNew = 0.9 * dAge * dAgeFactor**0.2 # Make sure dt is not too big dAgeNew = min(dAgeNew, dAgeMax) # Check for stopping of iteration if (dAgeFactor > 1.0): break # Save new estimate OmegaEnv = Xnew[0] OmegaCore = Xnew[1] return dAge, dAgeNew, OmegaEnv, OmegaCore