#fortran #fortran90
#fortran #fortran90
Вопрос:
PROGRAM MPI
IMPLICIT NONE
INTEGER, PARAMETER :: nn=100
DOUBLE PRECISION h, L
DOUBLE PRECISION, DIMENSION (2*nn) :: y, ynew
DOUBLE PRECISION, DIMENSION (nn) :: qnew,vnew
DOUBLE PRECISION, DIMENSION (2*nn) :: k1,k2,k3,k4
INTEGER j, k
INTEGER i
INTEGER n
n=100 !particles
L=2.0d0
h=1.0d0/n
y(1)=1.0d0
DO k=1,2*n ! time loop
CALL RHS(y,k1)
CALL RHS(y (h/2.0d0)*k1,k2)
CALL RHS(y (h/2.0d0)*k2,k3)
CALL RHS(y h*k3,k4)
ynew(1:2*n)=y(1:2*n) (k1 2.0d0*(k2 k3) k4)*h/6.0d0
END DO
qnew(1:n)=ynew(1:n)
vnew(1:n)=ynew(n 1:2*n)
DO i=1,n
IF (qnew(i).GT. L) THEN
qnew(i) = qnew(i) - L
ENDIF
END DO
write(*,*) 'qnew=', qnew(1:n)
write(*,*) 'vnew=', vnew(1:n)
END PROGRAM MPI
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
! Right hand side of the ODE
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SUBROUTINE RHS(y,z)
IMPLICIT NONE
INTEGER, PARAMETER :: nn=100
DOUBLE PRECISION, DIMENSION (2*nn) :: y
DOUBLE PRECISION, DIMENSION (2*nn) :: z
DOUBLE PRECISION, DIMENSION (nn) :: F
DOUBLE PRECISION, DIMENSION (nn) :: g
INTEGER n
INTEGER m
n=100
m=1/n
z(1:n)=y(n 1:2*n)
CAll FORCE(g,F)
z(n 1:2*n)=F(1:n)/m
RETURN
END
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
! Force acting on each particle
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SUBROUTINE FORCE(g,F)
IMPLICIT NONE
INTEGER, PARAMETER :: nn=100
DOUBLE PRECISION, DIMENSION (nn) :: F
DOUBLE PRECISION, DIMENSION (nn) :: q
DOUBLE PRECISION, DIMENSION (nn) :: g
DOUBLE PRECISION u
INTEGER j, e
INTEGER n
n=100
e=1/n
DO j=2,n 1
CALL deriv((abs(q(j)-q(j-1)))/e,u)
g(j-1)=((y(j)-y(j-1))/(abs(y(j)-y(j-1))))*u
CALL deriv((abs(q(j)-q(j 1)))/e,u)
g(j 1)=((y(j)-y(j 1))/(abs(y(j)-y(j 1))))*u
F(j)=g(j-1) g(j 1)
END DO
RETURN
END
SUBROUTINE deriv(c,u,n)
IMPLICIT NONE
INTEGER, INTENT(in) :: n
DOUBLE PRECISION, DIMENSION(n), INTENT(IN) :: c
DOUBLE PRECISION, DIMENSION(n), INTENT(OUT) :: u
INTEGER, PARAMETER :: p=2
INTEGER, PARAMETER :: cr=100
INTEGER :: i
DOUBLE PRECISION L
L=2.0d0
DO i= 1,n
IF (c(i) .LE. L) THEN
u(i)=cr*(L*(c(i)**(-p))-L**(1-p))
ELSE IF (c(i) .GT. L) THEN
u(i)=0
END IF
END DO
RETURN
END SUBROUTINE deriv
Я получаю только одну такую же ошибку в строках 85 и 87. В нем говорится:
у y нет неявного типа в y (j-1) и в y (j 1).
Комментарии:
1. Обычно помогает публикация фактических ошибок, выдаваемых компилятором
2. Эта «только» одна ошибка, которая осталась, является довольно большой — вы производите вычисления с y (и, оказывается, q), за исключением того, что вы никогда не устанавливали никаких значений в q нигде в коде. Когда вы вызываете deriv((abs(q(j)-q(j-1)) / e, u), какие числа он должен там использовать? Почему? Когда вы вызываете g (j-1)=((y (j)-y(j-1))/abs(y (j)-y(j-1)))), вы даже не объявили , что это за тип y, не говоря уже о том, чтобы вводить в него какие-либо значения. Что там должно произойти? Откуда
subroutine force
это знать?
Ответ №1:
Здесь много неправильного. Мы можем указать на некоторые вещи, но вам придется сесть за книгу и изучить программирование, начиная с небольших программ и доводя их до совершенства, затем наращивая.
Давайте посмотрим на последнюю процедуру в коде, который вы опубликовали выше. Я изменил синтаксис некоторых объявлений переменных, просто чтобы сделать его короче, чтобы больше отображалось на экране одновременно.
SUBROUTINE deriv(c,u)
IMPLICIT NONE
DOUBLE PRECISION :: deriv, c, u
INTEGER :: p, x, cr, n
L=2.0d0
cr=100
p=2
n=100
DO i= 1,n
IF (c(i).LE. L) THEN
u(c)=cr*(L*c^(-p)-L^(1-p))
ELSE IF (c(i) .GT. L) THEN
u(c)=0
END IF
RETURN
END
Итак, вы ввели в deriv переменную двойной точности, но это также имя подпрограммы. Это ошибка; возможно, вы хотели сделать эту функцию, которая возвращает значение двойной точности; тогда вы почти на месте, вам нужно изменить заголовок процедуры на FUNCTION DERIV(c,u)
— но вы нигде не устанавливаете deriv . Так что, вероятно, это следует просто исключить. Итак, давайте просто избавимся от этого DOUBLE PRECISION deriv
объявления. Кроме того, L, который используется, никогда не объявляется, а x, которого нет, объявляется.
Затем вы передаете в эту подпрограмму две переменные, c и u, которые вы определяете как двойную точность. Пока все хорошо, но затем вы начинаете их индексировать: например, c(i)
. Поэтому они должны быть массивами двойной точности, а не просто скалярами. Глядя на цикл do, я предполагаю, что они оба должны иметь размер n
— который, предположительно, следует передать? . Кроме того, цикл do никогда не завершается; end do
после end if
должно быть an.
Кроме того, ^
оператор, который вы используете, я предполагаю, что вы используете для возведения в степень — но в Fortran это **
, не ^
. И это c^(-p)
должно (я предполагаю здесь) быть c(i)**(-p)
?
Наконец, вы устанавливаете u(c)
— но это не очень разумно, поскольку c представляет собой массив чисел двойной точности. Даже u (c (i)) не имело бы смысла — вы не можете проиндексировать массив с числом двойной точности. Предположительно, и я здесь просто предполагаю, вы имеете в виду значение u
, соответствующее только что вычисленному значению c
— например, u(i)
, not u(c)
?
Итак, учитывая вышесказанное, мы ожидаем, что подпрограмма deriv будет выглядеть следующим образом:
SUBROUTINE deriv(c,u,n)
IMPLICIT NONE
INTEGER, INTENT(in) :: n
DOUBLE PRECISION, DIMENSION(n), intent(IN) :: c
DOUBLE PRECISION, DIMENSION(n), intent(OUT) :: u
INTEGER, PARAMETER :: p=2, cr=100
DOUBLE PRECISION, PARAMETER :: L=2.0
INTEGER :: i
DO i= 1,n
IF (c(i) .LE. L) THEN
u(i)=cr*(L*c(i)**(-p)-L**(1-p))
ELSE IF (c(i) .GT. L) THEN
u(i)=0
END IF
END DO
RETURN
END SUBROUTINE deriv
Обратите внимание, что в современном fortran цикл do может быть заменен оператором where, а также вам не нужно явно передавать размер; так что тогда вы могли бы обойтись более четким и коротким:
SUBROUTINE DERIV(c,u)
IMPLICIT NONE
DOUBLE PRECISION, DIMENSION(:), intent(IN) :: c
DOUBLE PRECISION, DIMENSION(size(c,1)), intent(OUT) :: u
INTEGER, PARAMETER :: p=2, cr=100
DOUBLE PRECISION, PARAMETER :: L=2.0
WHERE (c <= L)
u=cr*(L*c**(-p)-L**(1-p))
ELSEWHERE
u=0
ENDWHERE
RETURN
END SUBROUTINE DERIV
Но обратите внимание, что мне уже пришлось трижды угадывать, что вы имели в виду в этом разделе кода, а это всего лишь примерно 1/4 от общего объема кода. Заставлять нас пытаться угадать ваше намерение во всем этом и переписывать соответствующим образом, вероятно, не лучшее использование чьего-либо времени; почему бы вам не продолжить работу над одной конкретной вещью и не задать другой вопрос, если у вас есть конкретная проблема.
Комментарии:
1. Я поддерживаю совет прочитать книгу. Хорошей ошибкой Fortran является «Fortran 95/2003 Explained» Меткалфа и др.