избегать дублирования кода путем реструктуризации цикла if / do - PullRequest
0 голосов
/ 13 ноября 2018

Привет. Я пытаюсь навязать определенное условие моей функции во многих различных пространственных точках в моей сетке. Однако я дублирую много кода, и он становится все более неэффективным.

Как я могу делать то, что мне нужно, просто используя цикл do? Конкретное условие, которое я пытаюсь навязать своей функции, одинаково во всех различных пространственных точках, поэтому я считаю, что есть способ сделать все это в одном цикле. Или как я могу объединить все эти операторы If / else if в одно утверждение? Должен быть более эффективный способ, чем то, что я делаю.

Я предоставил пример кода ниже.

FUNCTION grad(psi)
IMPLICIT NONE
INTEGER :: i,j,kk,ll
INTEGER, PARAMETER :: nx = 24, ny = 24
COMPLEX,DIMENSION(3,3,-nx:nx, -ny:ny) :: psi, grad
REAL :: pi
REAL :: f0
INTEGER :: nxx, nyy

nxx = nx/2
nyy = ny/2

pi = 4*atan(1.0)
f0 = pi**2*1.3

DO i=-nx+1,nx-1 !spatial points
DO j=-ny+1,ny-1 !spatial points

   IF ( i == 0 .AND. j == 0 .AND. i == j) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

    ELSE IF ( i == nxx .AND. j == nyy .AND. i == j) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

  ELSE IF ( i == -nxx .AND. j == -nyy .AND. i == j) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == nxx .AND. j == -nyy) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == -nxx .AND. j == nyy) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

  ELSE IF ( i == nxx .AND. j == ny) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

  ELSE IF ( i == -nxx .AND. j == ny) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == nx .AND. j == -nyy) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == nx .AND. j == nyy) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

    ELSE 

        DO kk=1,3

        grad(kk,1,i,j)  = psi(kk,1,i+1,j) 

        grad(kk,2,i,j)  = psi(kk,2,i+1,j)

        grad(kk,3,i,j)  = psi(kk,3,i+1,j)

    END DO

   END IF

END DO
END DO

END FUNCTION grad

1 Ответ

0 голосов
/ 14 ноября 2018

Если вы ищете краткость , я бы сказал, что вы можете быть намного, гораздо более краткими, чем вы. Вся предоставленная вами функция может быть переписана так:

function grad(psi)
  implicit none
  integer, parameter :: nx = 24, ny = 24, nxx = nx / 2, nyy = ny / 2
  real, parameter :: pi = 4 * atan(1.0), f0 = pi ** 2 * 1.3
  complex, dimension(3,3,-nx:nx,-ny:ny) :: psi, grad

  grad(:,:,-nx+1:nx-1,-ny+1:ny-1) = psi(:,:,-nx+2:nx,-ny+1:ny-1)
  grad(:,:,0,0) = psi(:,:,1,0)
  grad(:,:,[-nxx,nxx],[-nyy,nyy,ny]) = psi(:,:,[-nxx+1,nxx+1],[-nyy,nyy,ny]) - f0 * psi(:,:,[-nxx,nxx],[-nyy,nyy,ny])
  !grad(:,:,nx,[-nyy,nyy]) = psi(:,:,nx+1,[-nyy,nyy]) - f0 * psi(:,:,nx,[-nyy,nyy])
end

Как сказал @IanBush, назначение значений по умолчанию, а затем изменение особых случаев кажется хорошим подходом. Кроме того, обозначение секций массива является одной из отличительных и мощных функций языка Фортран, и его можно использовать для повышения выразительности без ущерба для ясности.

Чистые двоеточия означают все значения в этом измерении , а двоеточие между значениями означает только значения в этом диапазоне в этом измерении .

Итак, когда я пишу grad(:,:,-nx+1:nx-1,-ny+1:ny-1) = psi(:,:,-nx+2:nx,-ny+1:ny-1), я имею в виду: Я присваиваю значения из массива psi grad; Я включаю все значения из двух первых измерений, но только подмножество двух последних измерений (я исключаю первый и последний в каждом); Кроме того, они отображаются напрямую, за исключением третьего измерения, которое отображается на следующую эквивалентную позицию в psi.

Когда я пишу grad(:,:,[-nxx,nxx],[-nyy,nyy,ny]), я указываю список индексов вместо диапазона для третьего и четвертого измерений. Это будет включать в себя общие комбинации двух списков: -nxx,-nyy, -nxx,nyy, -nxx,ny, nxx,-nyy ...

Одним из преимуществ этой записи является то, что, поскольку она более очевидна и ближе к математической записи, легче уловить несоответствия. Вот почему последняя строка закомментирована: индекс nx+1, как это было бы в 8-м и 9-м условиях в коде, который вы написали, был бы за пределами. Я не знаю, является ли образец кода, который вы представили, официальным; если это так, вы должны исправить свой алгоритм (ну, поскольку вы выполняете цикл только со второго по второй-последний индексы, вы фактически никогда не коснетесь этих условий ...).

В качестве дополнительного совета вы можете поместить свои пользовательские функции в модуль, чтобы вы могли передать все эти объявления параметров в область видимости модуля. Кроме того, вы можете рассмотреть аргументы массива предполагаемой формы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...