func (mini *Minimizer) Step() { m := M.Buffer() size := m.Size() k := mini.k h := mini.h // save original magnetization m0 := cuda.Buffer(3, size) defer cuda.Recycle(m0) data.Copy(m0, m) // make descent cuda.Minimize(m, m0, k, h) // calculate new torque for next step k0 := cuda.Buffer(3, size) defer cuda.Recycle(k0) data.Copy(k0, k) torqueFn(k) setMaxTorque(k) // report to user // just to make the following readable dm := m0 dk := k0 // calculate step difference of m and k cuda.Madd2(dm, m, m0, 1., -1.) cuda.Madd2(dk, k, k0, -1., 1.) // reversed due to LLNoPrecess sign // get maxdiff and add to list max_dm := cuda.MaxVecNorm(dm) mini.lastDm.Add(max_dm) setLastErr(mini.lastDm.Max()) // report maxDm to user as LastErr // adjust next time step var nom, div float32 if NSteps%2 == 0 { nom = cuda.Dot(dm, dm) div = cuda.Dot(dm, dk) } else { nom = cuda.Dot(dm, dk) div = cuda.Dot(dk, dk) } if div != 0. { mini.h = nom / div } else { // in case of division by zero mini.h = 1e-4 } M.normalize() // as a convention, time does not advance during relax NSteps++ }
// vector dot product func dot(a, b outputField) float64 { A, recyA := a.Slice() if recyA { defer cuda.Recycle(A) } B, recyB := b.Slice() if recyB { defer cuda.Recycle(B) } return float64(cuda.Dot(A, B)) }
// average of slice over the magnet volume func sAverageMagnet(s *data.Slice) []float64 { if geometry.Gpu().IsNil() { return sAverageUniverse(s) } else { avg := make([]float64, s.NComp()) for i := range avg { avg[i] = float64(cuda.Dot(s.Comp(i), geometry.Gpu())) / magnetNCell() checkNaN1(avg[i]) } return avg } }
func Relax() { SanityCheck() pause = false // Save the settings we are changing... prevType := solvertype prevErr := MaxErr prevFixDt := FixDt prevPrecess := Precess // ...to restore them later defer func() { SetSolver(prevType) MaxErr = prevErr FixDt = prevFixDt Precess = prevPrecess relaxing = false // Temp.upd_reg = prevTemp // Temp.invalidate() // Temp.update() }() // Set good solver for relax SetSolver(BOGAKISHAMPINE) FixDt = 0 Precess = false relaxing = true // Minimize energy: take steps as long as energy goes down. // This stops when energy reaches the numerical noise floor. const N = 3 // evaluate energy (expensive) every N steps relaxSteps(N) E0 := GetTotalEnergy() relaxSteps(N) E1 := GetTotalEnergy() for E1 < E0 && !pause { relaxSteps(N) E0, E1 = E1, GetTotalEnergy() } // Now we are already close to equilibrium, but energy is too noisy to be used any further. // So now we minimize the total torque which is less noisy and does not have to cross any // bumps once we are close to equilibrium. solver := stepper.(*RK23) defer stepper.Free() // purge previous rk.k1 because FSAL will be dead wrong. avgTorque := func() float32 { return cuda.Dot(solver.k1, solver.k1) } var T0, T1 float32 = 0, avgTorque() // Step as long as torque goes down. Then increase the accuracy and step more. for MaxErr > 1e-9 && !pause { MaxErr /= math.Sqrt2 relaxSteps(N) // TODO: Play with other values T0, T1 = T1, avgTorque() for T1 < T0 && !pause { relaxSteps(N) // TODO: Play with other values T0, T1 = T1, avgTorque() } } pause = true }