Esempio n. 1
0
func (s *HeunSolver) Step() {
	e := GetEngine()
	equation := e.equation

	// First update all inputs
	dt := engine.dt.Scalar()
	for i := range equation {
		Assert(equation[i].kind == EQN_PDE1)
		equation[i].input[0].Update()
	}

	// Then step all outputs
	// and invalidate them.

	// stage 0
	for i := range equation {
		y := equation[i].output[0]
		dy := equation[i].input[0]
		dyMul := dy.multiplier
		checkUniform(dyMul)
		s.buffer[i] = Pool.Get(y.NComp(), y.Size3D())
		s.buffer[i].CopyFromDevice(dy.Array()) // save for later

		gpu.Madd(y.Array(), y.Array(), dy.Array(), dt*dyMul[0]) // initial euler step

		y.Invalidate()
	}

	// Advance time
	e.time.SetScalar(e.time.Scalar() + dt)

	// update inputs again
	for i := range equation {
		Assert(equation[i].kind == EQN_PDE1)
		equation[i].input[0].Update()
	}

	// stage 1
	for i := range equation {
		y := equation[i].output[0]
		dy := equation[i].input[0]
		dyMul := dy.multiplier

		h := float64(dt * dyMul[0])
		gpu.MAdd2Async(y.Array(), dy.Array(), 0.5*h, s.buffer[i], -0.5*h, y.Array().Stream) // corrected step
		y.Array().Sync()
		Pool.Recycle(&s.buffer[i])

		y.Invalidate()
	}

	e.step.SetScalar(e.step.Scalar() + 1) // advance time step
}
Esempio n. 2
0
// Take one time step
func (s *RK12Solver) Step() {
	e := GetEngine()
	equation := e.equation

	// First update all inputs

	for i := range equation {
		Assert(equation[i].kind == EQN_PDE1)
		equation[i].input[0].Update()
	}

	// Then step all outputs
	// and invalidate them.

	// stage 0
	t0 := e.time.Scalar()
	for i := range equation {
		y := equation[i].output[0]
		dy := equation[i].input[0]
		dyMul := dy.multiplier
		checkUniform(dyMul)
		s.dybuffer[i].CopyFromDevice(dy.Array()) // save for later
		s.y0buffer[i].CopyFromDevice(y.Array())  // save for later

	}

	const maxTry = 10 // undo at most this many bad steps
	const headRoom = 0.8
	try := 0

	for {
		// We need to update timestep if the step has failed
		dt := engine.dt.Scalar()
		// initial euler step
		for i := range equation {
			y := equation[i].output[0]
			dy := equation[i].input[0]
			dyMul := dy.multiplier
			if try > 0 { // restore previous initial conditions
				y.Array().CopyFromDevice(s.y0buffer[i])
				dy.Array().CopyFromDevice(s.dybuffer[i])
			}
			gpu.Madd(y.Array(), y.Array(), dy.Array(), dt*dyMul[0])
			y.Invalidate()
		}

		// Advance time
		e.time.SetScalar(t0 + dt)

		// update inputs again
		for i := range equation {
			equation[i].input[0].Update()
		}

		// stage 1
		badStep := false
		minFactor := 2.0
		for i := range equation {
			y := equation[i].output[0]
			dy := equation[i].input[0]
			dyMul := dy.multiplier

			h := float64(dt * dyMul[0])
			gpu.MAdd2Async(y.Array(), dy.Array(), 0.5*h, s.dybuffer[i], -0.5*h, y.Array().Stream) // corrected step
			y.Array().Sync()

			// error estimate
			stepDiff := s.diff[i].MaxDiff(dy.Array(), s.dybuffer[i]) * h
			err := float64(stepDiff)
			s.err[i].SetScalar(err)
			maxErr := s.maxErr[i].Scalar()
			if err > maxErr {
				s.badSteps.SetScalar(s.badSteps.Scalar() + 1)
				badStep = true
			}
			if (!badStep || try == maxTry-1) && err > s.peakErr[i].Scalar() {
				// peak error should be that of good step, unless last trial which will not be undone
				s.peakErr[i].SetScalar(err)
			}
			factor := 0.0
			if !badStep {
				factor = math.Sqrt(maxErr / err) //maxErr / err
			} else {
				factor = math.Pow(maxErr/err, 1./3.)
			}
			factor *= headRoom
			// do not increase/cut too much
			// TODO: give user the control:
			if factor > 1.5 {
				factor = 1.5
			}
			if factor < 0.1 {
				factor = 0.1
			}
			if factor < minFactor {
				minFactor = factor
			} // take minimum time increase factor of all eqns.

			y.Invalidate()
			//if badStep{break} // do not waste time on other equations
		}

		// Set new time step but do not go beyond min/max bounds
		newDt := dt * minFactor
		if newDt < s.minDt.Scalar() {
			newDt = s.minDt.Scalar()
		}
		if newDt > s.maxDt.Scalar() {
			newDt = s.maxDt.Scalar()
		}
		e.dt.SetScalar(newDt)
		if !badStep || newDt == s.minDt.Scalar() {
			break
		}
		if try > maxTry {
			panic(Bug(fmt.Sprint("The solver cannot converge after ", maxTry, " badsteps")))
		}

		try++
	} // end try

	// advance time step
	e.step.SetScalar(e.step.Scalar() + 1)
}