aboutsummaryrefslogtreecommitdiff
path: root/method/euler.go
blob: 8370ae9a67718c57eca22bc434b13154976c895b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// Euler method and variants.
//
// Copyright (C) 2020 Juan Marín Noguera
//
// This file is part of Solvned.
//
// Solvned is free software: you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any 
// later version.
//
// Solvned is distributed in the hope that it will be useful, but WITHOUT ANY 
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Solvned. If not, see <https://www.gnu.org/licenses/>.

package method

import "github.com/JwanMan/mned"

func eulerStep(ivp *mned.IVP, h float64) bool {
	deriv, ok := ivp.Derivative(ivp.Start)
	if !ok {
		return false
	}
	for i := 0; i < len(deriv); i++ {
		ivp.Start.Value[i] += h * deriv[i]
	}
	return true
}

// Make an instance of the Euler method with the given step, which must be
// positive. For a problem `x'(t)=f(t,x(t)), x(t0)=x0`, a step of the Euler
// method is given by `x(t0+step) = x(t0) + step*f(t0,x(t0))`.
func Euler(step float64) mned.Method {
	return mned.FixedStepMethod{Step: step, Method: eulerStep}
}

// Make an instance of the adaptive version of the Euler method given the
// tolerance, the initial step, and the minimum and maximum steps.
func AdaptiveEuler(
	tolerance float64, step float64, hmin float64, hmax float64,
) mned.Method {
	return &mned.AdaptiveStepMethod{
		Step:      step,
		Hmin:      hmin,
		Hmax:      hmax,
		Tolerance: tolerance,
		Method:    eulerStep,
		Order:     1,
	}
}

func modEulerStep(ivp *mned.IVP, h float64) bool {
	deriv, ok := ivp.Derivative(ivp.Start)
	if !ok {
		return false
	}
	point := ivp.Start.Clone()
	point.Time += h
	for i, v := range deriv {
		point.Value[i] += h * v
	}
	deriv2, ok := ivp.Derivative(point)
	for i, _ := range deriv {
		ivp.Start.Value[i] += h * (deriv[i] + deriv2[i]) / 2
	}
	return true
}

// Make an instance of the modified Euler method with the given step, which must
// be positive. This is a FixedStepMethod given by
// `x(t+h)=x(t) + h/2 * (f(t,x(t)) + f(t+h,x(t)+h*f(t,x(t))))`.
func ModifiedEuler(step float64) mned.Method {
	return mned.FixedStepMethod{Step: step, Method: modEulerStep}
}