func EnvSplitTcB(baseEnv *tempAll.Environment, TcFactors, BeFields []float64, epsAbs, epsRel float64) ([]*tempAll.Environment, error) { TcEnv := baseEnv.Copy() TcEnv.Be_field = 0.0 TcEnv.Mu_b = 0.0 _, err := tempCrit.CritTempSolve(TcEnv, epsAbs, epsRel) if err != nil { return nil, err } Tc := 1.0 / TcEnv.Beta omegaFit, err := tempCrit.OmegaFit(TcEnv, tempCrit.OmegaPlus) if err != nil { return nil, err } TcEnv.A, TcEnv.B = omegaFit[0], omegaFit[2] TcEnv.PairCoeffsReady = true result := []*tempAll.Environment{} for _, TcFactor := range TcFactors { env := TcEnv.Copy() T := TcFactor * Tc env.Beta = 1.0 / T env.Temp = T // fix (D1, Mu_h) appropriate for Beta //_, err := SolveD1Mu_h(env, epsAbs, epsRel) _, err := SolveD1Mu_hMu_b(env, epsAbs, epsRel) if err != nil { return nil, err } // keep (D1, Mu_h) independent of magnetic field BeNum := len(BeFields) thisEnv_BeSplit := env.MultiSplit([]string{"Be_field"}, []int{BeNum}, []float64{BeFields[0]}, []float64{BeFields[BeNum-1]}) result = append(result, thisEnv_BeSplit...) } return result, nil }
func innerMu_h(env *tempAll.Environment, k vec.Vector) float64 { sxy := math.Sin(k[0]) - math.Sin(k[1]) numer := sxy * sxy * math.Tanh(env.Beta*env.Xi_h(k)/2.0) denom := env.Mu_b + 2.0*env.Xi_h(k) //denom := env.Mu_b - 2.0*env.Be_field*env.A + 2.0*env.Xi_h(k) return numer / denom }
func AbsErrorBeta(env *tempAll.Environment, variables []string) solve.Diffable { F := func(v vec.Vector) (float64, error) { if v.ContainsNaN() { fmt.Printf("got NaN in AbsErrorBeta (v=%v)\n", v) return 0.0, errors.New("NaN in input") } env.Set(v, variables) if !env.FixedPairCoeffs || !env.PairCoeffsReady { // Before we evaluate error in Beta, Mu_h and D1 should have // appropriate values. eps := 1e-9 _, err := D1MuSolve(env, eps, eps) if err != nil { return 0.0, err } } // Beta equation error = x - x1 - x2 x1 := X1(env) x2, err := tempCrit.X2(env) if err != nil { fmt.Printf("error from X2(): %v\n", err) return 0.0, err } lhs := env.X rhs := x1 + x2 return lhs - rhs, nil } h := 1e-5 epsabs := 1e-4 return solve.SimpleDiffable(F, len(variables), h, epsabs) }
// Solve the (D1, Mu_h, Beta) system with x and F0 fixed. func D1MuBetaSolve(env *tempAll.Environment, epsAbs, epsRel float64) (vec.Vector, error) { // our guess for beta should be above beta_c if env.A == 0.0 && env.B == 0.0 { D1, Mu_h, F0 := env.D1, env.Mu_h, env.F0 env.F0 = 0.0 // F0 is 0 at T_c _, err := tempCrit.CritTempSolve(env, epsAbs, epsRel) if err != nil { return nil, err } fmt.Printf("%v; Tc = %f\n", env, 1.0/env.Beta) omegaFit, err := tempCrit.OmegaFit(env, tempCrit.OmegaPlus) if err != nil { return nil, err } env.A, env.B = omegaFit[0], omegaFit[2] env.PairCoeffsReady = true env.Beta += 0.1 // we are at T < T_c; uncache env env.D1, env.Mu_h, env.F0 = D1, Mu_h, F0 } //fmt.Printf("%v; Tc = %f\n", env, 1.0 / env.Beta) // solve low temp system for reasonable values of D1 and Mu_h first _, err := D1MuSolve(env, epsAbs, epsRel) if err != nil { return nil, err } // solve the full low temp system system, start := D1MuBetaSystem(env) solution, err := solve.MultiDim(system, start, epsAbs, epsRel) if err != nil { return nil, err } return solution, nil }
// Calculate x - (x_1 + x_2) with Mu_h fixed. func AbsErrorX(env *tempAll.Environment, variables []string) solve.Diffable { F := func(v vec.Vector) (float64, error) { if v.ContainsNaN() { fmt.Printf("got NaN in AbsErrorX (v=%v)\n", v) return 0.0, errors.New("NaN in input") } env.Set(v, variables) // Before we evaluate error in X, Mu_b and D1 should have // appropriate values. system, start := D1Mu_bSystem(env) eps := 1e-9 _, err := solve.MultiDim(system, start, eps, eps) if err != nil { return 0.0, err } if env.Mu_b > 0.0 { fmt.Println("Warning: got Mu_b > 0 in AbsErrorX") env.Mu_b = 0.0 } // evaluate X error x1 := tempPair.X1(env) x2, err := tempCrit.X2(env) if err != nil { fmt.Printf("error from X2(): %v\n", err) return 0.0, err } lhs := env.X rhs := x1 + x2 return lhs - rhs, nil } h := 1e-5 epsabs := 1e-4 return solve.SimpleDiffable(F, len(variables), h, epsabs) }
func AbsErrorMu_h(env *tempAll.Environment, variables []string) solve.Diffable { F := func(v vec.Vector) (float64, error) { env.Set(v, variables) lhs := env.X rhs := X1(env) return lhs - rhs, nil } h := 1e-6 epsabs := 1e-4 return solve.SimpleDiffable(F, len(variables), h, epsabs) }
func SolveNoninteracting(env *tempAll.Environment, epsAbs, epsRel float64) (vec.Vector, error) { env.F0 = 0.0 env.Mu_h = 0.3 env.Beta = 50.0 system, start := NoninteractingSystem(env) solution, err := solve.MultiDim(system, start, epsAbs, epsRel) if err != nil { return nil, err } return solution, nil }
// Return the absolute error and gradient for the doping w.r.t. the given // parameters. func AbsErrorMu_h(env *tempAll.Environment, variables []string) solve.Diffable { F := func(v vec.Vector) (float64, error) { env.Set(v, variables) L := env.PointsPerSide lhs := 2.0 / (env.T0 + env.Tz) rhs := bzone.Avg(L, 2, tempAll.WrapFunc(env, innerMu_h)) return lhs - rhs, nil } h := 1e-5 epsabs := 1e-4 return solve.SimpleDiffable(F, len(variables), h, epsabs) }
// Evaluate the anomalous retarded pair Green's function, // Pi^A(k, omega)_{xx, xy, yy}. k must be a two-dimensional vector. func PiAnom(env *tempAll.Environment, k vec.Vector, omega float64) vec.Vector { piInner := func(q vec.Vector, out *vec.Vector) { // Do vector operations on out to avoid allocation: // first case, out = k/2 + q (*out)[0] = k[0]/2.0 + q[0] (*out)[1] = k[1]/2.0 + q[1] Delta1 := env.Delta_h(*out) E1 := env.BogoEnergy(*out) // second case, out = k/2 - q (*out)[0] = k[0]/2.0 - q[0] (*out)[1] = k[1]/2.0 - q[1] Delta2 := env.Delta_h(*out) E2 := env.BogoEnergy(*out) // Get part of result that's the same for all (xx, xy, yy): t1 := math.Tanh(env.Beta * E1 / 2.0) t2 := math.Tanh(env.Beta * E2 / 2.0) common := -Delta1 * Delta2 / (4.0 * E1 * E2) * ((t1+t2)*(1.0/(omega+E1+E2)-1.0/(omega-E1-E2)) + (t1-t2)*(1.0/(omega-E1+E2)-1.0/(omega+E1-E2))) // Set out = result: sx := math.Sin(q[0]) sy := math.Sin(q[1]) (*out)[0] = sx * sx * common (*out)[1] = sx * sy * common (*out)[2] = sy * sy * common } return bzone.VectorAvg(env.PointsPerSide, 2, 3, piInner) }
// Partial derivative of Mu_h with respect to T; x and V held constant. func dMu_hdT(env *tempAll.Environment) (float64, error) { ct := 0 // F gets Mu_h given Beta F := func(Beta float64) (float64, error) { ct += 1 // save the environment state before changing it // (don't want one call of F to affect the next) oD1, oMu_h, oBeta, oMu_b := env.D1, env.Mu_h, env.Beta, env.Mu_b env.Beta = Beta // fix free variables eps := 1e-9 _, err := D1MuF0Solve(env, eps, eps) if err != nil { return 0.0, err } Mu_h := env.Mu_h // restore the environment env.D1, env.Mu_h, env.Beta, env.Mu_b = oD1, oMu_h, oBeta, oMu_b return Mu_h, nil } h := 1e-4 epsAbs := 1e-5 deriv, err := solve.OneDimDerivative(F, env.Beta, h, epsAbs) //fmt.Println("MuT ct", ct) return -math.Pow(env.Beta, 2.0) * deriv, err }
// Partial derivative of F (some function of env) with respect to Mu_h; // T and V held constant. func dFdMu_h(env *tempAll.Environment, F envFunc) (float64, error) { ct := 0 // G gets F given Mu_h (allow x to vary; constant Beta) G := func(Mu_h float64) (float64, error) { ct += 1 // save the environment state before changing it // (don't want one call of F to affect the next) oD1, oMu_h, oX, oMu_b := env.D1, env.Mu_h, env.X, env.Mu_b env.Mu_h = Mu_h // fix free variables2 eps := 1e-9 _, err := D1F0XSolve(env, eps, eps) if err != nil { return 0.0, err } vF, err := F(env) if err != nil { return 0.0, err } // restore the environment env.D1, env.Mu_h, env.X, env.Mu_b = oD1, oMu_h, oX, oMu_b return vF, nil } h := 1e-4 epsAbs := 1e-5 deriv, err := solve.OneDimDerivative(G, env.Mu_h, h, epsAbs) //fmt.Println("dF_dMu ct", ct) return deriv, err }
func AbsErrorMu_h(env *tempAll.Environment, variables []string) solve.Diffable { F := func(v vec.Vector) (float64, error) { env.Set(v, variables) if -env.Mu_b > -2.0*env.Mu_h { // when |Mu_b| is this large, no longer have pairs return env.X - tempPair.X1(env), nil } L := env.PointsPerSide lhs := 0.5 / (env.T0 + env.Tz) rhs := bzone.Avg(L, 2, tempAll.WrapFunc(env, innerMu_h)) return lhs - rhs, nil } h := 1e-5 epsabs := 1e-4 return solve.SimpleDiffable(F, len(variables), h, epsabs) }
// Partial derivative of F with respect to T; Mu_h and V held constant. func dFdT(env *tempAll.Environment, F envFunc) (float64, error) { ct := 0 // G gets F given Beta (allow x to vary; constant Mu_h) G := func(Beta float64) (float64, error) { ct += 1 // save the environment state before changing it // (don't want one call of F to affect the next) oD1, oBeta, oX, oMu_b := env.D1, env.Beta, env.X, env.Mu_b env.Beta = Beta // fix free variables eps := 1e-9 _, err := SolveD1Mu_bX(env, eps, eps) if err != nil { return 0.0, err } vF, err := F(env) if err != nil { return 0.0, err } // restore the environment env.D1, env.Beta, env.X, env.Mu_b = oD1, oBeta, oX, oMu_b return vF, nil } h := 1e-4 epsAbs := 1e-5 deriv, err := solve.OneDimDerivative(G, env.Beta, h, epsAbs) fmt.Println("dF_dT ct", ct) return -math.Pow(env.Beta, 2.0) * deriv, err }
// For use with solve.Iterative: func CritTempStages(env *tempAll.Environment) ([]solve.DiffSystem, []vec.Vector, func([]vec.Vector)) { vars0 := []string{"D1", "Mu_h"} vars1 := []string{"Beta"} diffD1 := tempPair.AbsErrorD1(env, vars0) diffMu_h := tempPair.AbsErrorBeta(env, vars0) system0 := solve.Combine([]solve.Diffable{diffD1, diffMu_h}) diffBeta := AbsErrorBeta(env, vars1) system1 := solve.Combine([]solve.Diffable{diffBeta}) stages := []solve.DiffSystem{system0, system1} start := []vec.Vector{[]float64{env.D1, env.Mu_h}, []float64{env.Beta}} accept := func(x []vec.Vector) { env.D1 = x[0][0] env.Mu_h = x[0][1] env.Beta = x[1][0] } return stages, start, accept }
// Calculate Mu_b - (-Omega_+(0)) func AbsErrorMu_b(env *tempAll.Environment, variables []string) solve.Diffable { F := func(v vec.Vector) (float64, error) { if v.ContainsNaN() { fmt.Printf("got NaN in AbsErrorMu_b (v=%v)\n", v) return 0.0, errors.New("NaN in input") } env.Set(v, variables) zv := vec.ZeroVector(3) omega0, err := tempCrit.OmegaPlus(env, zv) if err != nil { return 0.0, err } lhs := env.Mu_b rhs := -omega0 return lhs - rhs, nil } h := 1e-5 epsabs := 1e-4 return solve.SimpleDiffable(F, len(variables), h, epsabs) }
func innerMu_h(env *tempAll.Environment, k vec.Vector) float64 { sxy := math.Sin(k[0]) - math.Sin(k[1]) E := env.BogoEnergy(k) xi := env.Xi_h(k) delta := env.Delta_h(k) return sxy * sxy * math.Tanh(env.Beta*E/2.0) * (2.0*xi*xi + delta*delta) / (E * E * E) }
// Solve the (D1, Mu_h, Beta) system with x and Mu_b fixed. func FlucTempSolve(env *tempAll.Environment, epsAbs, epsRel float64) (vec.Vector, error) { // fix pair coefficients if env.A == 0.0 && env.B == 0.0 && env.FixedPairCoeffs { D1, Mu_h, Mu_b, Beta := env.D1, env.Mu_h, env.Mu_b, env.Beta env.Mu_b = 0.0 // Mu_b is 0 at T_c _, err := tempCrit.CritTempSolve(env, epsAbs, epsRel) if err != nil { return nil, err } omegaFit, err := tempCrit.OmegaFit(env, tempCrit.OmegaPlus) if err != nil { return nil, err } env.A, env.B = omegaFit[0], omegaFit[2] env.PairCoeffsReady = true // uncache env env.D1, env.Mu_h, env.Mu_b, env.Beta = D1, Mu_h, Mu_b, Beta } // our guess for beta should be a bit above Beta_p pairSystem, pairStart := tempPair.PairTempSystem(env) _, err := solve.MultiDim(pairSystem, pairStart, epsAbs, epsRel) if err != nil { return nil, err } env.Beta += 0.1 // solve fluc temp system for reasonable values of Mu_h and D1 first system, start := FlucTempD1MuSystem(env) _, err = solve.MultiDim(system, start, epsAbs, epsRel) if err != nil { return nil, err } // solve the full fluc temp system system, start = FlucTempFullSystem(env) solution, err := solve.MultiDim(system, start, epsAbs, epsRel) if err != nil { return nil, err } return solution, nil }
// Calculate U_{1}/N = 1/N \sum_k \epsilon_h(k) f_h(\xi_h(k)) func HolonEnergy(env *tempAll.Environment) (float64, error) { inner := func(k vec.Vector) float64 { return env.Epsilon_h(k) * env.Fermi(env.Xi_h(k)) } dim := 2 avg := bzone.Avg(env.PointsPerSide, dim, inner) return avg, nil }
// Solve the environment under the conditions at T = T_c. func CritTempSolve(env *tempAll.Environment, epsAbs, epsRel float64) (vec.Vector, error) { // our guess for beta should be a bit above Beta_p pairSystem, pairStart := tempPair.PairTempSystem(env) _, err := solve.MultiDim(pairSystem, pairStart, epsAbs, epsRel) if err != nil { return nil, err } env.Beta += 0.1 // solve crit temp system for reasonable values of Mu and D1 first system, start := CritTempD1MuSystem(env) _, err = solve.MultiDim(system, start, epsAbs, epsRel) if err != nil { return nil, err } // solve the full crit temp system system, start = CritTempFullSystem(env) solution, err := solve.MultiDim(system, start, epsAbs, epsRel) if err != nil { return nil, err } return solution, nil }
// Solve the (D1, Mu_h, F0) system with x and Beta fixed. func D1MuF0Solve(env *tempAll.Environment, epsAbs, epsRel float64) (vec.Vector, error) { if env.A == 0.0 && env.B == 0.0 { // We must have T < T_c < T_p (Beta > Beta_c > Beta_p). // Getting Beta_p is fast, so do that first. D1, Mu_h, F0, Beta := env.F0, env.Mu_h, env.F0, env.Beta // cache env env.F0 = 0.0 // F0 is 0 at T_c and T_p _, err := tempPair.PairTempSolve(env, epsAbs, epsRel) if err != nil { return nil, err } if Beta < env.Beta { return nil, fmt.Errorf("Beta = %f less than Beta_p in env %s", Beta, env.String()) } _, err = tempCrit.CritTempSolve(env, epsAbs, epsRel) if err != nil { return nil, err } if Beta < env.Beta { return nil, fmt.Errorf("Beta = %f less than Beta_c in env %s", Beta, env.String()) } fmt.Printf("%v; Tc = %f\n", env, 1.0/env.Beta) omegaFit, err := tempCrit.OmegaFit(env, tempCrit.OmegaPlus) if err != nil { return nil, err } env.A, env.B = omegaFit[0], omegaFit[2] env.PairCoeffsReady = true // we are at T < T_c; uncache env env.D1, env.Mu_h, env.F0, env.Beta = D1, Mu_h, F0, Beta } // solve low temp system for reasonable values of D1 and Mu_h first _, err := D1MuSolve(env, epsAbs, epsRel) if err != nil { return nil, err } // solve the full low temp system system, start := D1MuF0System(env) solution, err := solve.MultiDim(system, start, epsAbs, epsRel) if err != nil { return nil, err } return solution, nil }
func innerX1(env *tempAll.Environment, k vec.Vector) float64 { return env.Fermi(env.Xi_h(k)) }
func innerX1(env *tempAll.Environment, k vec.Vector) float64 { E := env.BogoEnergy(k) return 1.0 - env.Xi_h(k)*math.Tanh(env.Beta*E/2.0)/E }
func innerD1(env *tempAll.Environment, k vec.Vector) float64 { return math.Sin(k[0]) * math.Sin(k[1]) * env.Fermi(env.Xi_h(k)) }
func innerBeta(env *tempAll.Environment, k vec.Vector) float64 { sxy := math.Sin(k[0]) - math.Sin(k[1]) return sxy * sxy * math.Tanh(env.Beta*env.Xi_h(k)/2.0) / env.Xi_h(k) }
func innerF0(env *tempAll.Environment, k vec.Vector) float64 { sxy := math.Sin(k[0]) + float64(env.Alpha)*math.Sin(k[1]) return sxy * sxy / env.BogoEnergy(k) }
func innerMu_hNoninteracting(env *tempAll.Environment, k vec.Vector) float64 { return env.Fermi(env.Xi_h(k)) }
func innerMu_h(env *tempAll.Environment, k vec.Vector) float64 { return (1.0 - env.Xi_h(k)/env.BogoEnergy(k)) / 2.0 }
func innerD1(env *tempAll.Environment, k vec.Vector) float64 { sxy := math.Sin(k[0]) * math.Sin(k[1]) E := env.BogoEnergy(k) return sxy * (1.0 - env.Xi_h(k)*math.Tanh(env.Beta*E/2.0)/E) }
// Evaluate the retarded pair Green's function Pi_R(k, omega)_{xx, xy, yy}. // k must be a two-dimensional vector. func Pi(env *tempAll.Environment, k vec.Vector, omega float64) vec.Vector { var piInner func(k vec.Vector, out *vec.Vector) // TODO: should this comparison be math.Abs(env.F0)? Not using that to // avoid going to finite F0 procedure when F0 < 0 (since F0 is // positive by choice of gauge). Also - would it be better to just // test if F0 == 0.0? Would prefer to avoid equality comparison // on float. if math.Abs(env.F0) < 1e-9 { piInner = func(q vec.Vector, out *vec.Vector) { // do vector operations on out to avoid allocation: // out = k/2 + q (*out)[0] = k[0]/2.0 + q[0] (*out)[1] = k[1]/2.0 + q[1] xp := env.Xi_h(*out) // out = k/2 - q (*out)[0] = k[0]/2.0 - q[0] (*out)[1] = k[1]/2.0 - q[1] xm := env.Xi_h(*out) tp := math.Tanh(env.Beta * xp / 2.0) tm := math.Tanh(env.Beta * xm / 2.0) common := -(tp + tm) / (omega - xp - xm) sx := math.Sin(q[0]) sy := math.Sin(q[1]) // out = result (*out)[0] = sx * sx * common (*out)[1] = sx * sy * common (*out)[2] = sy * sy * common } } else { piInner = func(q vec.Vector, out *vec.Vector) { // out = k/2 + q (*out)[0] = k[0]/2.0 + q[0] (*out)[1] = k[1]/2.0 + q[1] xi1 := env.Xi_h(*out) E1 := env.BogoEnergy(*out) // out = k/2 - q (*out)[0] = k[0]/2.0 - q[0] (*out)[1] = k[1]/2.0 - q[1] xi2 := env.Xi_h(*out) E2 := env.BogoEnergy(*out) A1 := 0.5 * (1.0 + xi1/E1) A2 := 0.5 * (1.0 + xi2/E2) B1 := 0.5 * (1.0 - xi1/E1) B2 := 0.5 * (1.0 - xi2/E2) t1 := math.Tanh(env.Beta * E1 / 2.0) t2 := math.Tanh(env.Beta * E2 / 2.0) common := -(t1+t2)*(A1*A2/(omega-E1-E2)-B1*B2/(omega+E1+E2)) - (t1-t2)*(A1*B2/(omega-E1+E2)-B1*A2/(omega+E1-E2)) sx := math.Sin(q[0]) sy := math.Sin(q[1]) // out = result (*out)[0] = sx * sx * common (*out)[1] = sx * sy * common (*out)[2] = sy * sy * common } } return bzone.VectorAvg(env.PointsPerSide, 2, 3, piInner) }
// Solve the (D1, Mu_h, Mu_b) system with Beta and x fixed. func SolveD1Mu_hMu_b(env *tempAll.Environment, epsAbs, epsRel float64) (vec.Vector, error) { /* // fix pair coefficients if env.A == 0.0 && env.B == 0.0 && env.FixedPairCoeffs { D1, Mu_h, Mu_b, Beta, Be_field := env.D1, env.Mu_h, env.Mu_b, env.Beta, env.Be_field env.Mu_b = 0.0 // Mu_b is 0 at T_c env.Be_field = 0.0 _, err := tempCrit.CritTempSolve(env, epsAbs, epsRel) if err != nil { return nil, err } omegaFit, err := tempCrit.OmegaFit(env, tempCrit.OmegaPlus) if err != nil { return nil, err } env.A, env.B = omegaFit[0], omegaFit[2] env.PairCoeffsReady = true // uncache env env.D1, env.Mu_h, env.Mu_b, env.Beta, env.Be_field = D1, Mu_h, Mu_b, Beta, Be_field } */ maxIters := 1000 oldMu_b := env.Mu_b for i := 0; i < maxIters; i++ { // iterate D1/Mu_h solution, err := SolveD1Mu_h(env, epsAbs, epsRel) if err != nil { return nil, err } // iterate Mu_b Be_field := env.Be_field env.Be_field = 0.0 zv := vec.ZeroVector(3) omega0, err := tempCrit.OmegaPlus(env, zv) //omegaFit, err := tempCrit.OmegaFit(env, tempCrit.OmegaPlus) if err != nil { return nil, err } env.Mu_b = -omega0 env.Be_field = Be_field //A, Mub_eff := omegaFit[0], omegaFit[3] //env.Mu_b = -omega0 + 2.0 * env.Be_field * env.A //Mub_eff := omegaFit[3] //env.Mu_b = Mub_eff //fmt.Printf("iterating Mu_b: now %f, before %f\n", env.Mu_b, oldMu_b) // check if done if math.Abs(env.Mu_b-oldMu_b) < epsAbs || !env.IterateD1Mu_hMu_b { return []float64{solution[0], solution[1], env.Mu_b}, nil } oldMu_b = env.Mu_b } return []float64{0.0, 0.0, 0.0}, fmt.Errorf("failed to find D1/Mu_h/Mu_b solution for env=%s\n", env.String()) /* system, start := D1Mu_hMu_bSystem(env) solution, err := solve.MultiDim(system, start, epsAbs, epsRel) if err != nil { return nil, err } return solution, nil */ }