func parabolaTestPoints() []vec.Vector { sk := 0.1 // small value of k ssk := sk / math.Sqrt(2) // unique point zero := vec.ZeroVector(3) // basis vectors xb := []float64{sk, 0.0, 0.0} yb := []float64{0.0, sk, 0.0} zb := []float64{0.0, 0.0, sk} xyb := []float64{ssk, ssk, 0.0} xzb := []float64{ssk, 0.0, ssk} yzb := []float64{0.0, ssk, ssk} basis := []vec.Vector{xb, yb, zb, xyb, xzb, yzb} // create points from basis numRadialPoints := 3 points := []vec.Vector{zero} for _, v := range basis { for i := 1; i <= numRadialPoints; i++ { pt := vec.ZeroVector(len(v)) copy(pt, v) pt.Mul(float64(i), &pt) points = append(points, pt) } } return points }
// Produce a a slice of vectors whose values cover each first Brillouin zone // point once. func bzPoints(L, d int) []vec.Vector { cachedL, okL := pointsCache[L] if okL { cachedD, okD := cachedL[d] if okD { return cachedD } } else { pointsCache[L] = make(map[int][]vec.Vector) } points := make([]vec.Vector, pow(L, d)) // start is the minumum value of any component of a point start := -math.Pi // (finish - step) is the maximum value of any component of a point finish := -start // step is the separation between point components step := (finish - start) / float64(L) k := vec.ZeroVector(d) kIndex := make([]int, d) // set initial value for k for i := 0; i < d; i++ { k[i] = start kIndex[i] = 0 } // iterate over Brillouin zone done := false for i := 0; !done; i++ { points[i] = vec.ZeroVector(len(k)) copy(points[i], k) done = bzAdvance(k, kIndex, start, step, L, d) } pointsCache[L][d] = points return points }
func VectorSum(pointsPerSide, gridDim, fnDim int, fn BzVectorFunc) vec.Vector { c := vec.ZeroVector(fnDim) add := func(next vec.Vector, total *vec.Vector) { for i := 0; i < fnDim; i++ { x := (*total)[i] y := next[i] - c[i] t := x + y c[i] = (t - x) - y (*total)[i] = t } } start := vec.ZeroVector(fnDim) return bzVectorReduce(add, start, pointsPerSide, gridDim, fnDim, fn) }
// Convert v back to Go format. func VecFromGSL(v *C.gsl_vector) vec.Vector { dim := int(v.size) u := vec.ZeroVector(dim) for i := 0; i < dim; i++ { u[i] = float64(C.gsl_vector_get(v, C.size_t(i))) } return u }
// Combine fns into one function, suitable for passing to MultiDim. // All funcs passed in must have the same dimension. func Combine(fns []Diffable) DiffSystem { NumFuncs := len(fns) Dimension := fns[0].Dimension // F(v) = \sum_i fns[i].F(v) e_i // (e_i is unit vector in i'th direction) F := func(v vec.Vector) (vec.Vector, error) { var err error ret := vec.ZeroVector(NumFuncs) for i := 0; i < NumFuncs; i++ { ret[i], err = fns[i].F(v) if err != nil { return ret, err } } return ret, nil } // Df(v) = \sum_i fns[i].Df(v) Df := func(v vec.Vector) ([]vec.Vector, error) { var err error ret := make([]vec.Vector, NumFuncs) for i := 0; i < NumFuncs; i++ { ret[i], err = fns[i].Df(v) if err != nil { return ret, err } } return ret, nil } Fdf := func(v vec.Vector) (vec.Vector, []vec.Vector, error) { var err error ret_f := vec.ZeroVector(NumFuncs) ret_df := make([]vec.Vector, NumFuncs) for i := 0; i < NumFuncs; i++ { ret_f[i], err = fns[i].F(v) if err != nil { return ret_f, ret_df, err } ret_df[i], err = fns[i].Df(v) if err != nil { return ret_f, ret_df, err } } return ret_f, ret_df, nil } return DiffSystem{F, Df, Fdf, NumFuncs, Dimension} }
func VectorAvg(pointsPerSide, gridDim, fnDim int, fn BzVectorFunc) vec.Vector { N := math.Pow(float64(pointsPerSide), float64(gridDim)) sum := VectorSum(pointsPerSide, gridDim, fnDim, fn) avg := vec.ZeroVector(fnDim) for i := 0; i < fnDim; i++ { avg[i] = sum[i] / N } return avg }
func bzVectorReduce(combine bzVectorConsumer, start vec.Vector, L, d, fnDim int, fn BzVectorFunc) vec.Vector { points := bzPoints(L, d) total := start out := vec.ZeroVector(fnDim) for i := 0; i < len(points); i++ { k := points[i] fn(k, &out) combine(out, &total) } return total }
// Gradient of fn at v within tolerance epsabs. h is the initial step size. func Gradient(fn vec.FnDim0, v vec.Vector, h, epsabs float64) (vec.Vector, error) { grad := vec.ZeroVector(len(v)) // calculate derivative of fn w.r.t. each component of v for i := 0; i < len(v); i++ { deriv, err := Derivative(fn, v, i, h, epsabs) if err != nil { return grad, err } grad[i] = deriv } return grad, nil }
// 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) }
// Return a list of all k points surveyed by OmegaCoeffs(). func OmegaCoeffsPoints(numRadial int, sk float64) []vec.Vector { ssk := sk / math.Sqrt(2) // basis vectors xb := []float64{sk, 0.0, 0.0} yb := []float64{0.0, sk, 0.0} zb := []float64{0.0, 0.0, sk} xyb := []float64{ssk, ssk, 0.0} xzb := []float64{ssk, 0.0, ssk} yzb := []float64{0.0, ssk, ssk} basis := []vec.Vector{xb, yb, zb, xyb, xzb, yzb} // create points from basis points := []vec.Vector{} for _, v := range basis { for i := 1; i <= numRadial; i++ { pt := vec.ZeroVector(len(v)) copy(pt, v) pt.Mul(float64(i), &pt) points = append(points, pt) } } return points }
// Return a vector with the fit parameters [a_x, a_y, b, mu_pair] to the // given functions. func omegaFitHelper(env *tempAll.Environment, fn OmegaFunc, points []vec.Vector) (vec.Vector, error) { // evaluate omega_+/-(k) at each point omegas := []float64{} Xs := []vec.Vector{} for _, q := range points { omega, err := fn(env, q) if err != nil { continue } X := vec.ZeroVector(4) X[0] = q[0] * q[0] X[1] = q[1] * q[1] X[2] = q[2] * q[2] X[3] = -1 Xs = append(Xs, X) omegas = append(omegas, omega) } if len(omegas) < 3 { return nil, fmt.Errorf("not enough omega_+/- values can be found") } return fit.Linear(omegas, Xs), nil }
func TestFitParabolaLinear(t *testing.T) { epsAbs := 1e-9 ax, ay, b, mu_b := 1.01, 0.99, 0.1, -0.01 omegaGenerator := func(q vec.Vector) float64 { return ax*q[0]*q[0] + ay*q[1]*q[1] + b*q[2]*q[2] - mu_b } points := parabolaTestPoints() y := make([]float64, len(points)) X := make([]vec.Vector, len(points)) for i, q := range points { y[i] = omegaGenerator(q) X[i] = vec.ZeroVector(4) X[i][0] = q[0] * q[0] X[i][1] = q[1] * q[1] X[i][2] = q[2] * q[2] X[i][3] = -1 } coeffs := Linear(y, X) if math.Abs(coeffs[0]-ax) > epsAbs || math.Abs(coeffs[1]-ay) > epsAbs || math.Abs(coeffs[2]-b) > epsAbs || math.Abs(coeffs[3]-mu_b) > epsAbs { t.Fatalf("unexpected coefficients; got %s, expected %s", coeffs, []float64{ax, ay, b, mu_b}) } }
// 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 */ }