В моем коде осталась только одна ошибка,

#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» Меткалфа и др.