i'm studing fortran programation through the cambridge self-study guide 2. In the page 11 we can find this program:
program projectile
implicit none
! define constants
real, parameter :: g = 9.8
real, parameter :: pi = 3.1415927
real :: a, t, u, x, y
real :: theta, v, vx, vy
! Read values for a, t, and u from terminal
read(*,*) a, t, u
! convert angle to radians
a = a * pi / 180.0
x = u * cos(a) * t
y = u * sin(a) * t – 0.5 * g * t * t
vx = u * cos(a)
vy = u * sin(a) - g * t
v = sqrt(vx * vx + vy * vy)
theta = atan(vy / vx) * 180.0 / pi
write(*,*) 'x: ',x,'y: ',y
write(*,*) 'v: ',v,'theta: ',theta
end program projectile
But it generates an "Unclassificable statement at (1)" in line 16, can someone please help me? thx
Oh this takes me back. I took this course too when I was a lot younger!
I don't know how you managed to type this, but what appears to be the subtraction operator in
y = u * sin(a) * t – 0.5 * g * t * t
has been written with the wrong symbol. You need to use -, not the en-dash. Did you copy the formula straight from a lecture document?
Also, if you don't mind my saying so, your definition of g has an inadequate amount of precision cf. your other variables.
In your line
y = u * sin(a) * t – 0.5 * g * t * t
you have a character that looks like MINUS SIGN (-) but isn't - it's an EN DASH (–). Yes, they look almost the same. No, you can't use one instead of the other.
Related
I am trying to simulate harmonic oscillator by using Verlet Method(Original Verlet) in Fortran.
My research tells that the order of error should be 2 but my calculation showed the order of 1.
I couldn't find my mistake in my source code. What should I do?
Edit:
The algorithm I am using is below:
x(t+Δt) = 2x(t) - x(t-Δt) + Δt² F(t)/m
v(t) = {x(t+Δt) -x(t-Δt)}/2Δt
Where x(t) represents the position, v(t) represents velocity and F(t) represents Force. I recognize this is the Original Verlet described here
According to this site, the order of error should be at least O(Δt²) but the error of the order of my program plotted in gnuplot (below) does not have a order of O(Δt²).
program newton_verlet
implicit none
real*16, parameter :: DT = 3.0
real*16, parameter :: T0 = 0.0
real*16, parameter :: TEND = 2.0
integer, parameter :: NT = int(TEND/DT + 0.5)
real*16, parameter :: M = 1.0
real*16, parameter :: X0 = 1.0
real*16, parameter :: V0 = 0.0
real*16 x,v,t,xold,xnew,vnew,ek,ep,et,f,h
integer it,n
do n=0,20
h = DT/2**n
x = X0
v = V0
ek = 0.5*M*v*v
ep = x*x/2
et = ek + ep
xold = x - v*h
do it = 1,2**n
! f = -x
f = -x
xnew = 2.0*x - xold + f*h*h/M
v = (xnew-xold)/(2.0*h)
ek = 0.5*M*v*v
ep = 0.5*xnew*xnew
et = ek + ep
xold = x
x = xnew
end do
write(*,*) h,abs(x-cos(DT))+abs(v+sin(DT))
end do
end program
Above program calculates the error of calculation for the time step h.
According to the Wiki page for Verlet integrators, it seems that we need to use a more accurate way of setting the initial value of xold (i.e., include terms up to the force) to get the global error of order 2. Indeed, if we modify xold as
program newton_verlet
implicit none
real*16, parameter :: DT = 3.0
real*16, parameter :: M = 1.0
real*16, parameter :: X0 = 1.0
real*16, parameter :: V0 = 0.0
real*16 x,v,xold,xnew,f,h
integer it,n
do n = 0, 20
h = DT / 2**n
x = X0
v = V0
f = -x
! xold = x - v * h !! original
xold = x - v * h + f * h**2 / (2 * M) !! modified
do it = 1, 2**n
f = -x
xnew = 2 * x - xold + f * h * h / M
xold = x
x = xnew
end do
write(*,*) log10( h ), log10( abs(x - cos(DT)) )
end do
end program
the global error becomes of order 2 (please see the log-log plot below).
I have already posted a question regarding this problem, and have implemented what i've learned from the answers. I'm now at a point where the answers that are printed out on the screen are very close, but incorrect. Here is the code I now have:
program taylor
implicit none
integer :: k = 0
real :: y = 0.75
real :: x = 0.75
do while (abs(y - sin(0.75)) > 1E-6)
k = k + 1
y = y + ((y * (-x * x)) /( 2 * k * (2 * k + 1 )))
print *, y
end do
end program taylor
I can't seem to spot the error here, why is this not working? The first answer it prints is correct, but then it seems to get progressively lower, instead of closer to the true value. (The do while loop is to ensure the program stops when the absolute value between the calculation and the intrinsic sin function is less than 1E-6). I can see that the program is constantly reducing the final output, and the Taylor series is suppose to alternate between - and +, so how can I write that in my program?
Thanks.
The taylor series uses factorials and power of x.
taylor_sin(x) = sum[0->n] ( [(-1 ^ n) / (2n + 1)!] * x**(2n + 1) )
(Sorry for my poor keyboard math skills...)
program taylor
implicit none
integer :: n = 0
real :: fac = 1
real :: y = 0.75
real :: x = 0.75
real :: px = 1
integer :: sgn = -1
integer :: s = 1
do while (abs(y - sin(0.75)) > 1E-6)
n = n + 1
fac = fac * (2 * n) * ((2 * n) + 1)
px = px * (x * x)
s = s * sgn
y = y + ((s /fac) * (px * x))
print *, y
end do
end program taylor
Computing the factorial fac in a loop is rather trivial.
To compute x**(2n + 1), compute and keep x**(2n) and add an extra multiplication by x.
I use an integer to compute -1**n since using a real may lose precision over time.
[EDIT] silly me... you can save that extra multiplication by x by setting px to 0.75 before the loop.
I have this function to reach a certain 1 dimensional value accelerated and damped with overshoot. That is: given an inital value, a velocity and a acceleration (force/mass), the target value is attained by accelerating to it and gets increasingly damped while getting closer to the target value.
This all works fine, howver If i want to know what the TotalAngle is after time 't' I have to run this function say N steps with a 'small' dt to find the 'limit'.
I was wondering If i can (and how) to intergrate over dt so that the TotalAngle can be determined given a time 't' initially.
Regards, Tanks for any help.
dt = delta time step per frame
input = 1
TotalAngle = 0 at t=0
Velocity = 0 at t=0
void FAccelDampedWithOvershoot::Update(float dt, float input, float& Velocity, float& TotalAngle)
{
const float Force = 500000.f;
const float DampForce = 5000.f;
const float MaxAngle = 45.f;
const float InvMass = 1.f / 162400.f;
float target = MaxAngle * input;
float ratio = (target - TotalAngle) / MaxAngle;
float fMove = Force * ratio;
float fDamp = -Velocity * DampForce;
Velocity += (fMove + fDamp) * invMass * dt;
TotalAngle += Velocity * dt;
}
Updated with fixed bugs in math
Originally I've lost mass and MaxAngle a few times. This is why you should first solve it on a paper and then enter to the SO rather than trying to solve it in the text editor.
Anyway, I've fixed the math and now it seems to work reasonably well. I put fixed solution just over previous one.
Well, this looks like a Newtonian mechanics which means differential equations. Let's try to solve them.
SO is not very friendly to math formulas and I'm a bit bored to type characters so here is what I use:
F = Force
Fd = DampForce
MA = MaxAngle
A= TotalAngle
v = Velocity
m = 1 / InvMass
' for derivative i.e. something' is 1-st derivative of something by t and something'' is 2-nd derivative
if I divide you last two lines of code by dt and merge in all the other lines I can get (I also assume that input = 1 as other case is obviously symmetrical)
v' = ([F * (1 - A / MA)] - v * Fd) / m
and applying A' = v we get
m * A'' = F(1 - A/MA) - Fd * A'
or moving to one side we get a simple 2-nd order differential equation
m * A'' + Fd * A' + F/MA * A = F
IIRC, the way to solve it is to first solve characteristic equation which here is
m * x^2 + Fd * x + F/MA = 0
x[1,2] = (-Fd +/- sqrt(Fd^2 - 4*F*m/MA))/ (2*m)
I expect that part under sqrt i.e. (Fd^2 - 4*F*m/MA) is negative thus solution should be of the following form. Let
Dm = Fd/(2*m)
K = sqrt(F/MA/m - Dm^2)
(note the negated value under sqrt so it works now) then
A(t) = e^(-Dm*t) * [P * sin(K*t) + Q * cos(K*t)] + C
where P, Q and C are some constants.
The solution is easier to find as a sum of two solutions: some specific solution for
m * A'' + Fd * A' + F/MA * A = F
and a general solution for homogeneou
m * A'' + Fd * A' + F/MA * A = 0
that makes original conditions fit. Obviously specific solution A(t) = MA works and thus C = MA. So now we need to fit P and Q of general solution to match starting conditions. To find them we need
A(0) = - MA
A'(0) = V(0) = 0
Given that e^0 = 1, sin(0) = 0 and cos(0) = 1 you get something like
Q = -MA
P = 0
or
P = 0
Q = - MA
C = MA
thus
A(t) = MA * [1 - e^(-Dm*t) * cos(K*t)]
where
Dm = Fd/(2*m)
K = sqrt(F/MA/m - Dm^2)
which kind of makes sense given your task.
Note also that this equation assumes that everything happens in radians rather than degrees (i.e. derivative of [sin(t)]' is just cos(t)) so you should transform all your constants accordingly or transform the solution.
const float Force = 500000.f * M_PI / 180;
const float DampForce = 5000.f * M_PI / 180;
const float MaxAngle = M_PI_4;
which on my machine produces
Dm = 0.000268677541
K = 0.261568546
This seems to be similar to original funcion is I step with dt = 0.01f and the main obstacle seems to be precision loss because of float
Hope this helps!
This is not a full answer and I am sure someone else can work it out, but there is no room in the comments and it may help you find a better solution.
The image below shows the velocity (blue) as your function integrates at time steps 1. The red shows the function below that calculates the value for time t
The function F(t)
F(t) = sin((t / f) * pi * 2) * (1 / (((t / f) + a) ^ c)) * b
With f = 23.7, a = 1.4, c = 2, and b= 50 that give the red plot in the image above
All the values are just approximation.
f determines the frequency and is close to a match,
a,b,c control the falloff in amplitude and are a by eye guestimate.
If it does not matter that you have a perfect match then this will work for you. totalAngle uses the same function but t has 0.25 added to it. Unfortunately I did not get any values for a,b,c for totalAngle and I did notice that it was offset so you will have to add the offset value d (I normalised everything so have no idea what the range of totalAngle was)
Function F(t) for totalAngle
F(t) = sin(((t+0.25) / f) * pi * 2) * (1 / ((((t+0.25) / f) + a) ^ c)) * b + d
Sorry only have f = 23.7, c= 2, a~1.4 nothing for b=? d=?
I'm having some trouble trying to plot a polar rose with a offset C of the equation r(theta) = cos(k*theta) + C.
I'm trying to plot this polar rose: http://en.wikipedia.org/wiki/Polar_coordinate_system#/media/File:Cartesian_to_polar.gif
The polar equation can be:
r(theta) = cos(k * theta)
or
r(theta) = sin(k * theta)
The equation of the polar rose I want to draw is:
r(theta) = 2 + sin(6 * theta)
Ok, and the parametric equations will be:
x = C + sin(k * theta) * cos(theta)
y = C + sin(k * theta) * sin(theta)
In my Canvas(drawing area), my origin is not at the center of the screen, so I need to translate the rose to it. Ok, no big deal. Another point is that I need to scale the rose for it to be visible or it will be too small, but still no problem, this explains the: 100*. Here is my code, it is on C++ btw:
for ( float t = 0; t < PI_2; t+= 0.01 )
{
r = Origin.get_x() + 100*(2+(sin(6*t) * cos(t)));
h = Origin.get_y() + 100*(2+(sin(6*t) * sin(t)));
point(r,h);
}
I know that I'm doing it wrong, because when I add the +2 which should be the C constant is not working the way I want to, It's just translating more and drawing a polar rose without an offset. How do I prevent the "extra translation" and draw it properly?
x = r cos(theta), y = r sin(theta) so your parametric equations should be x(theta) = C * cos(theta) + sin(k*theta) * cos(theta) and y(theta) = C * sin(theta) + sin(k*theta) * sin(theta). You just forgot to multiply C by cos(theta) and by sin(theta) respectively.
I have written the following code in F2003, trying to
implement an adaptive trapezoid method and adaptive
simpson's rule method for simple integrals and I am
having seg fault problems when I try to run the code using
intrinsic functions (exp, log, sin) but it works perfectly for
polynomials (x ** 2, for instance).
I have compiled like this:
$ gfortran -Wall -pedantic -fbounds-check integral_module.f03 integrate.f03 -o integral
And I get no warnings.
Any ideas??
integral_module.f03
module integral_module
implicit none
public :: integral
!To test which is more efficient
integer, public :: counter_int = 0, counter_simpson = 0
contains
recursive function integral(f, a, b, tolerance) &
result(integral_result)
intrinsic :: abs
interface
function f(x) result(f_result)
real, intent(in) :: x
real :: f_result
end function f
end interface
real, intent(in) :: a, b, tolerance
real :: integral_result
real :: h, mid
real :: trapezoid_1, trapezoid_2
real :: left_area, right_area
counter_int = counter_int + 1
h = b - a
mid = (a + b) / 2
trapezoid_1 = h * (f(a) + f(b)) / 2.0
trapezoid_2 = h / 2 * (f(a) + f(mid)) / 2.0 + &
h / 2 * (f(mid) + f(b)) / 2.0
if(abs(trapezoid_1 - trapezoid_2) < 3.0 * tolerance) then
integral_result = trapezoid_2
else
left_area = integral(f, a, mid, tolerance / 2)
right_area = integral(f, mid, b, tolerance / 2)
integral_result = left_area + right_area
end if
end function integral
recursive function simpson(f, a, h, tolerance) &
result(simpson_result)
intrinsic :: abs
interface
function f(x) result(f_result)
real, intent(in) :: x
real :: f_result
end function f
end interface
real, intent(in) :: a, h, tolerance
real :: simpson_result
real :: h_half, a_lower, a_upper
real :: parabola_1, parabola_2
real :: left_area, right_area
counter_simpson = counter_simpson + 1
h_half = h / 2.0
a_lower = a - h_half
a_upper = a + h_half
parabola_1 = h / 3.0 * (f(a - h) + 4.0 * f(a) + f(a + h))
parabola_2 = h_half / 3.0 * (f(a_lower - h_half) + 4.0 * f(a_lower) + f(a_lower + h_half)) + &
h_half / 3.0 * (f(a_upper - h_half) + 4.0 * f(a_upper) + f(a_upper + h_half))
if(abs(parabola_1 - parabola_2) < 15.0 * tolerance) then
simpson_result = parabola_2
else
left_area = simpson(f, a_lower, h_half, tolerance / 2.0)
right_area = simpson(f, a_upper, h_half, tolerance / 2.0)
simpson_result = left_area + right_area
end if
end function simpson
end module integral_module
And, integrate.f03
module function_module
implicit none
public :: non_para_errfun, parabola
contains
function non_para_errfun(x) result(errfun_result)
real, intent(in) :: x
real :: errfun_result
intrinsic :: exp
errfun_result = exp(x ** 2.0)
end function non_para_errfun
function parabola(x) result(parabola_result)
real, intent(in) :: x
real :: parabola_result
parabola_result = x ** 2.0
end function parabola
function brainerd(x) result(brainerd_result)
real, intent(in) :: x
real :: brainerd_result
intrinsic :: exp, sin
brainerd_result = exp(x ** 2.0) + sin(2.0 * x)
end function brainerd
end module function_module
module math_module
implicit none
intrinsic :: atan
real, parameter, public :: pi = &
4.0 * atan(1.0)
end module math_module
program integrate
use function_module, f => brainerd
use integral_module
use math_module, only : pi
implicit none
intrinsic :: sqrt, abs
real :: x_min, x_max, a, h, ans, ans_simpson
real, parameter :: tolerance = 0.01
x_min = 0
x_max = 2.0 * pi
a = abs(x_max) - abs(x_min)
h = (abs(x_max) + abs(x_min)) / 2.0
!ans = integral(f, x_min, x_max, tolerance)
ans_simpson = simpson(f, a, h, tolerance)
!print "(a, f11.6)", &
! "The integral is approx. ", ans
print "(a, f11.6)", &
"The Simpson Integral is approx: ", ans_simpson
!print "(a, f11.6)", &
! "The exact answer is ", &
! 1.0/3.0 * x_max ** 3 - 1.0/3.0 * x_min ** 3
print *
!print "(a, i5, a)", "The trapezoid rule was executed ", counter_int, " times."
print "(a, i5, a)", "The Simpson's rule was executed ", counter_simpson, " times."
end program integrate
You are getting a floating point exception when executing exp(x ** 2.0), since round about x > 9.35 the exponent gets too large for single precision floats.
Switching to double precision gets rid of the overflow.
You'd also want to change the x ** 2.0 to x**2, s.t. the compiler can optimize the integer power instead of doing the much more costly floating point operation.