Для разработки параллельных программ часто используется язык программирования Фортран. Это одно из наиболее эффективных средств программирования вычислительных задач. Далее приводится краткое описание языка.
Для записи исходного текста программы на Фортране могут использоваться фиксированный и свободный форматы.Первый из них характерен для стандарта Фортран 77, второй применяется в Фортране 90 и более новых версиях . Фортран 90 поддерживает также фиксированный формат, что обеспечивает совместимость со старыми стандартами записи. При записи исходного текста в фиксированном формате строка содержит 72 позиции. Первые пять позиций отведены для меток, а шестая может быть пустой или содержать любой, отличный от пробела символ. В последнем случае строка считается строкой продолжения и при обработке компилятором присоединяется к предыдущей строке программы. Оператор может занимать позиции с 7 по 72.
В свободном формате записи все позиции строки равноправны, ее длина составляет 132 символа.
Программа на Фортране состоит из главной программы и, возможно, некоторого числа подпрограмм.Подпрограммы могут быть функциями или процедурами,внешними, внутренними или модульными. Различные программные компоненты могут компилироваться раздельно.
Первым оператором главной программы является её заголовок PROGRAM. За ним следует имя программы:
PROGRAM ИМЯ_ПРОГРАММЫ
Имя программы обязательно начинается с буквы, затем могут идти буквы, цифры и символы подчеркивания, например:
PROGRAM
PROGRAM QUADRATIC_EQUATION_SOLVER45
Максимальная длина любого имени в программах на Фортране - 31 символ. Первым оператором подпрограммы может быть только ее заголовок FUNCTION или . Последней строкой программного компонента должна быть строка с оператором END. Заключительный оператор главной программы может иметь также следующий вид:
END PROGRAM ИМЯ_ПРОГРАММЫ
ИМЯ_ПРОГРАММЫ является необязательной частью оператора.
После заголовка следуют описания переменных, констант, меток, подпрограмм и других объектов, используемых в программе. Эта ее часть называется разделом описаний.После раздела описаний следует раздел операторов.
Перечень встроенных типов в порядке возрастания их ранга дан ниже.
LOGICAL(1) и BYTELOGICAL(2)LOGICAL(4)INTEGER(1)INTEGER(2)INTEGER(4)REAL(4)REAL(8)COMPLEX(8)COMPLEX(16) У каждого встроенного типа Фортрана есть несколько разновидностей, которые отличаются друг от друга диапазоном значений и некоторыми другими характеристиками.
Значение символьного типа CHARACTER представляет собой строку символов. Длина строкового значения в Фортране может быть произвольной и задается с помощью параметра LEN в предложении описания строковой переменной, например:
CHARACTER(LEN = 430) :: Shakespeare_sonet
Предложение описания переменных в Фортране 90 имеет вид:
ТИП[, АТРИБУТЫ] :: СПИСОК_ПЕРЕМЕННЫХ
В списке имена переменных разделяются запятыми, а ТИП задает общий тип переменных, являясь идентификатором типа:
REAL, PARAMETER :: salary = 2000
В Фортране 90 используются следующие атрибуты объектов:
PARAMETER - объект является PUBLIC - объект является доступным за пределами модуля;PRIVATE - объект недоступен за пределами модуля;POINTER - объект является ссылкой (указателем);TARGET - объект можно использовать в качестве адресата в операторах назначения ссылок;ALLOCATABLE - объект является DIMENSION - объект является массивом;INTENT - определяет вид связи для параметра процедуры (т. е., является входным, выходным или и входным и выходным);OPTIONAL - необязательный параметр процедуры;SAVE - сохранять значение локальной переменной подпрограммы в промежутке между ее вызовами;EXTERNAL - для INTRINSIC - для внутренней функции.Буквальные числовые константы записываются обычным образом. Комплексная буквальная константа записывается в круглых скобках:
i ;2 + i.Имеются две буквальные логические константы:
.TRUE. - "истина";.FALSE. - "ложь".Буквальная
Арифметические операции Фортрана (в порядке убывания приоритета):
** - возведение в степень;*, / - умножение, деление;-, + - вычитание, сложение.Минус (-) и плюс (+) используются также как знаки унарных операций: В Фортране поддерживаются следующие
| Знак операции | Альтернативное обозначение | Название операции сравнения |
|---|---|---|
.LT. |
< | меньше |
.LE. |
<= | меньше или равно |
.GT. |
> | больше |
.GE. |
>= | больше или равно |
.EQ. |
== | Равно |
.NE. |
/ = | не равно |
Для значений комплексного типа действительны только операции "равно" ( .EQ.) и "не равно" ( .NE.).
Логические операции:
| Операция | Значение операции |
|---|---|
.NOT. |
Логическое отрицание |
.AND. |
Логическое пересечение (умножение, логическое "И") |
.OR. |
Логическое объединение (сложение, логическое "ИЛИ") |
. EQV.и .NEQV. |
Логические эквивалентность и неэквивалентность (логические равенство и неравенство) |
Массивы описываются с помощью атрибута DIMENSION:
REAL, DIMENSION(1:100) :: C
Параметром этого атрибута должен быть список экстентов (экстент - количество элементов массива для каждого измерения) описываемых массивов в виде
(экстент_1, экстент_2, ..., экстент_n)
Число экстентов определяет ранг массива. Каждый экстент записывается в виде:
[ нижняя_граница : ] верхняя_граница
Пример:
REAL, DIMENSION(0:10, 2, -3:3,11) :: FGRID
Если значение нижней границы опущено, ее значение полагается равным 1. В некоторых случаях, список экстентов сводится к списку разделенных запятыми двоеточий, число которых равно рангу массива. Только число экстентов задается при объявлении
REAL, ALLOCATABLE, DIMENSION(:, :) :: BE_LATER
PROGRAM dyn_array IMPLICIT NONE INTEGER SIZE REAL, ALLOCATABLE, DIMENSION(:) ::array WRITE(*, *) 'SIZE?' READ(*, *) SIZE IF(SIZE > 0) ALLOCATE(array(SIZE)) … IF(ALLOCATED(array)) DEALLOCATE(array) END PROGRAM dyn_array
DIMENSION, форма массива может быть указана непосредственно после его идентификатора:
REAL X(10, 20, 30), Y(100), Z(2, 300, 2, 4)
Решение нелинейного уравнения методом Ньютона
PROGRAM NEWTON IMPLICIT NONE REAL (8) :: X, DX, F, DF X = 3.3 ! НАЧАЛЬНОЕ ПРИБЛИЖЕНИЕ DO ! НЬЮТОНОВСКИЕ ИТЕРАЦИИ DX = F(X) / DF(X) ! ВЫЧИСЛЕНИЕ ШАГА X = X - DX ! ВЫЧИСЛЕНИЕ ОЧЕРЕДНОГО ПРИБЛИЖЕНИЯ IF(DX <= SPACING(X)) EXIT ! ЦИКЛ ЗАВЕРШАЕТСЯ, КОГДА ! ШАГ МЕНЬШЕ РАССТОЯНИЯ МЕЖДУ ДВУМЯ ПОСЛЕДОВАТЕЛЬНЫМИ ! ВЕЩЕСТВЕННЫМИ ЗНАЧЕНИЯМИ END DO PRINT *, X ! ВЫВОД ЗНАЧЕНИЯ КОРНЯ PRINT *, F(X) ! ВЫВОД ЗНАЧЕНИЯ ФУНКЦИИ В ТОЧКЕ X PRINT *, DF(X) ! ВЫВОД ЗНАЧЕНИЯ ПРОИЗВОДНОЙ ! ФУНКЦИИ В ТОЧКЕ X END PROGRAM NEWTON REAL(8) FUNCTION F(X) IMPLICIT NONE REAL(8) :: X F = SIN(X) RETURN END
Ниже дается перечень некоторых конструкций и операторов Фортрана. Необязательные элементы заключены в квадратные скобки []. Если символ пробела не окружен квадратными скобками, то он является обязательным.
| Оператор | Описание |
|---|---|
PROGRAM имя_программы |
Оператор заголовка главной программы |
MODULE имя_модуля |
Оператор заголовка модуля |
END[ MODULE[имя_модуля]] |
Оператор завершения модуля |
USE имя_модуля[, ONLY only_список] |
Оператор |
[ |
Оператор заголовка подпрограммы-процедуры |
[тип][ |
Оператор заголовка подпрограммы-функции |
INTERFACE[ родовое_описание] |
Оператор заголовка интерфейса |
END[ ]INTERFACE |
Оператор завершения интерфейса |
CONTAINS |
Оператор содержания |
ENTRY |
|
BLOCK[ ]DATA[ имя_блока_данных] |
Оператор заголовка блока данных |
END [ ]BLOCK[ ]DATA[имя_блока_данных] |
Оператор завершения блока данных |
| Оператор | Описание |
|---|---|
MODULE PROCEDURE список_имен_модульных_процедур |
Оператор декларации модульных процедур |
и атрибуты - совместимая комбинация из следующих значений:
|
|
TYPE[, атрибут_доступа ::] имя_производного_типа атрибут_доступа - PUBLIC или PRIVATE |
Оператор определения |
END[ ]TYPE[ имя_типа] |
Оператор определения |
|
Оператор определения правил неявной типизации |
ALLOCATABLE [::] имя_массива[( список_экстентов)][, имя_массива [ (список_экстентов) ]...] |
Оператор назначения атрибута ALLOCATABLE |
DIMENSION имя_массива( список_экстентов)[, имя_массива (список_экстентов)...] |
Оператор спецификации массивов |
PARAMETER
(список_определений_именованных_констант) |
Оператор определения |
EXTERNAL список_внешних_имен |
Оператор назначения атрибута EXTERNAL |
|
Оператор назначения атрибута |
INTENT(параметр_входа/выхода) список_формальных_параметров |
Оператор назначения атрибута INTENT |
OPTIONAL список_формальных_параметров |
Оператор назначения атрибута OPTIONAL |
SAVE[[::] список_сохраняемых_объектов] |
Оператор назначения атрибута SAVE |
COMMON /[имя_общего_блока]/список_переменных[, /имя_общего_блока/список_переменных.... ] |
|
DATA список_объектов/список_значений/[, список_объектов/список_значений/...] |
Оператор инициализации объектов |
FORMAT([список_дескрипторов])* |
Оператор |
| Оператор | Описание |
|---|---|
END[ PROGRAM[ имя_программы]] |
Оператор завершения главной программы |
END[ подпрограмма[имя_подпрограммы]] где подпрограмма - |
Оператор завершения подпрограммы |
CALL
имя_подпрограммы[(список_фактических_параметров) ] |
|
RETURN |
Оператор возврата управления вызывающему компоненту программы |
STOP[ сообщение] |
Оператор останова программы |
| Оператор | Описание |
|---|---|
переменная = выражение |
Оператор присваивания для скалярных и массивоподобных объектов |
ссылка => адресат |
Оператор прикрепления ссылки к адресату |
| Оператор | Описание |
|---|---|
IF(скалярное_логическое_выражение) исполняемый_оператор |
Условный оператор |
WHERE( логическое_выражение_массив) массив_переменная = выражение_массив |
|
[ if_имя : ]
IF( скалярное_логическое_выражение) THEN
ELSE[[ ]IF(скалярное_логическое_выражение) THEN[ if_имя]
END[ ]IF[ if_имя] |
Конструкция ветвления IF_THEN_ELSE |
WHERE( логическое_выражение_массив)
ELSEWHERE
END[ ]WHERE |
Конструкция ветвления в присваивании массивов |
[sе1есt_имя:] SELECT [ ] CASE ( скалярное_выражение)
CASE ( список_возможных_значений)[ sе1есt_имя]
CASE DEFAULT [ sе1еct_имя] END [ ] SELECT [ sе1еct_имя] |
Конструкция SELECT |
GO[ ]TO метка |
|
[do_имя:] DO[ метка] переменная = скалярное_целое_выражение1, скалярное_целое_выражение2[, скалярное_целое_выражение3] |
Заголовок оператора цикла |
[do_имя:] DO[ метка] [,] WHILE(скалярное_лог_выражение) |
Заголовок оператора цикла в альтернативной форме |
CYCLE [ do_имя] |
|
EXIT[ do_имя] |
Оператор выхода из цикла с именем do_имя |
CONTINUE |
|
END[ ]DO[ do_имя] |
Оператор завершения цикла с именем do_имя |
| Оператор | Описание |
|---|---|
ALLOCATE( список_выделяемых_объектов[, STAT=статус]) |
Оператор выделения динамической памяти для выделяемых объектов |
|
Оператор освобождения динамической памяти от выделенных объектов |
| Оператор | Описание |
|---|---|
READ( список_управления_вводом) [ список_ввода] READ формат[, список_ввода] |
Оператор чтения данных |
WRITE(список_управления_выводом) [ список_вывода] |
Оператор записи данных |
PRINT формат[, список_вывода] |
Оператор вывода данных на устройство |
OPEN( список_спецификаций) |
|
CLOSE(список_спецификаций) |
Оператор закрытия файла |
| Имя подпрограммы | Возвращаемое значение или производимое действие |
|---|---|
ABS(A) |
Абсолютная величина |
ACHAR(I) |
I-ый символ сортирующей последовательности ASCII |
|
Арккосинус в радианах |
AIMAG(Z) |
Мнимая часть комплексного числа |
AINT(A[, KIND]) |
Усечение до целого |
ALLOCATED(ARRAY) |
Проверка выделенности |
ANINT(A [, KIND]) |
Ближайшее целое |
ASIN(X) |
Арксинус в радианах |
ATAN(X) |
Арктангенс в радианах |
ATAN2(Y, X) |
Аргумент комплексного числа |
CALL DATE_AND_TIME([DATE][, |
Считывание времени и даты с часов реального времени |
CALL RANDOM_NUMBER(HARVEST) |
Случайное число в интервале [0,1) |
CALL RANDOM_SEED([SIZE] [,PUT][,GET]) |
Получение/назначение затравочного массива |
CALL SYSTEM_CLOCK([COUNT] [,COUNT_RATE] [,COUNT_MAX]) |
Целочисленный отсчет часов реального времени |
CEILING(A) |
Наименьшее целое не меньшее аргумента |
CHAR(I [, KIND]) и ICHAR(C) |
I-ый символ в сортирующей последовательности процессора |
CMPLX(X [, Y] [, KIND]) |
Конструктор комплексного числа |
CONJG(Z) |
Комплексное сопряжение |
COS(X) |
Косинус |
COSH(X) |
Гиперболический косинус |
COUNT(MASK [, DIM]) |
Число элементов массива, имеющих значение "истина" |
CSHIFT(ARRAY, SHIFT [, DIM]) |
Циклический сдвиг элементов массива |
DIGITS(X) |
Число значащих цифр в модели представления аргумента |
DOT_PRODUCT(VECTOR_A, VECTOR_B) |
|
DPROD(X, Y) |
Умножение с двойной точностью |
EOSHIFT(ARRAY, SHIFT [, |
Вытесняющий сдвиг элементов массива |
EPSILON(X) |
Наименьшее число в модели представления аргумента, не пренебрежимое по сравнению с единицей |
EXP(X) |
Экспонента |
|
Степенная часть в модели представления аргумента |
FLOOR(A) |
Наименьшее целое, не превышающее аргумент |
|
Дробная часть в модели представления аргумента |
|
Наибольшее число в модели представления аргумента |
IACHAR(С) |
Индекс символа-аргумента в сортирующей последовательности ASCII |
IAND(I, J) |
Побитовое логическое И |
IBCLR(I, POS) |
Установка нуля в заданном бите |
IBITS(I, POS, LEN) |
Извлечение цепочки битов |
IBSET(I, POS) |
Установка единицы в заданном бите |
ICHAR(C) |
Индекс символа-аргумента в сортирующей последовательности процессора |
IEOR(I, J) |
Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ |
INDEX(STRING, SUBSTRING [,BACK]) |
Индекс начала подстроки в строке |
INT(A [, KIND]) |
Приведение к целому типу |
IOR(I, J) |
Побитовое логическое ИЛИ |
ISHIFT(I, SHIFT) |
Логический сдвиг битов |
ISHIFTC(I, SHIFT [, SIZE]) |
Логический циклический сдвиг части битов вправо |
KIND(X) |
Разновидность типа аргумента |
LBOUND(ARRAY [, DIM]) |
Нижняя граница массива |
LEN(S) |
Длина текстового аргумента |
LEN_TRIM(STRING) |
Длина строки без учета конечных пробелов |
LOG(X) |
Натуральный логарифм |
LOG10(X) |
Десятичный логарифм |
LOGICAL(L [, KIND]) |
Приведение к заданной разновидности логического типа |
MATMUL(MATRIX_A, MATRIX_B) |
|
MAX (A1, A2 [, A3, ]) |
Выбор максимального аргумента |
MAXLOC(ARRAY [, MASK]) |
Индекс наибольшего элемента массива |
MAXVAL(ARRAY [, DIM ] [,MASK]) |
Наибольший элемент массива |
MIN (A1, A2 [, A3, ]) |
Выбор минимального аргумента |
MINLOC(ARRAY [, MASK]) |
Индекс наименьшего элемента массива |
MINVAL(ARRAY [, DIM ] [,MASK]) |
Наименьший элемент массива |
MOD(A, P) |
Остаток от деления по модулю |
|
Деление по модулю |
NINT(A [, KIND]) |
Ближайшее целое |
NOT(I) |
Побитовое логическое дополнение |
PRECISION(X) |
Десятичная точность в модели представления аргумента |
PRESENT(A) |
Проверка присутствия необязательного аргумента |
PRODUCT(ARRAY [, DIM] [,MASK]) |
Произведение элементов массива |
REAL(A [, KIND]) |
Приведение к вещественному типу |
RESHAPE(SOURCE, SHAPE [,PAD] [, ORDER]) |
Изменение формы массива |
SCAN(STRING,SET[,BACK]) |
Индекс крайнего символа строки STRING в наборе SET |
SELECTED_INT_KIND(R) |
Параметр разновидности целого типа для заданного степенного диапазона |
SELECTED_REAL_KIND([P][,R]) |
Параметр разновидности вещественного типа для заданной точности и/или заданного степенного диапазона |
SHAPE(SOURCE) |
Форма аргумента |
SIGN(A, B) |
Абсолютное значение A со знаком B |
SIN(X) |
Синус |
SINH(X) |
Гиперболический синус |
SIZE(ARRAY[,DIM]) |
Размер массива |
SQRT(X) |
Квадратный корень |
SUM(ARRAY[,DIM][,MASK]) |
|
TAN(X) |
Тангенс |
TANH(X) |
Гиперболический тангенс |
TINY(X) |
Наименьшее положительное число в модели представления аргумента |
|
Транспонирование матрицы |
UBOUND(ARRAY [, DIM]) |
Верхняя граница массива |
Метод молекулярной динамики является одним из основных методов моделирования динамики систем, состоящих из взаимодействующих между собой частиц. Он применяется в молекулярной физике, астрофизике и других науках. Интерпретация понятия "частица" зависит от предметной области. В молекулярной физике это могут быть атом или молекула, а в астрофизике "частицами" являются звезды или планеты, взаимодействующие с другими астрономическими объектами посредством гравитационного взаимодействия. Динамика систем таких частиц часто описывается уравнениями классической механики.
Будем рассматривать систему N частиц, динамика которых описывается уравнением второго
Здесь $$F_i$$ - равнодействующая всех сил, действующих на $$i$$ -ю частицу, $$m_i$$ - ее масса и $$а_i$$ - ускорение, с которым частица двигается под действием силы. Это
где $$r_i$$
Равнодействующая сил, является суммой парных взаимодействий $$i$$ -й частицы со всеми остальными частицами:
$$F_i=F(r_i)=\sum\limits_{i\ne j=1}^N F(r_i,r_j)$$или
$$F_i=\sum\limits_{j=1}^{i-1}F(r_i,r_j) + \sum\limits_{j=i+1}^N F(r_i,r_j)$$Сила взаимодействия связана с потенциалом взаимодействия. В расчетах молекулярных систем часто используют потенциал Леннарда-Джонса:
$$V(r)=4\epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} - \left(\frac{\sigma}{r}\right)^6 \right]$$Здесь $$r =\mid r\mid $$, а $$\epsilon$$ и $$\sigma$$ - параметры потенциала. Первый определяет интенсивность взаимодействия, а второй - положение минимума (см. рис. 6.5).
(рис 6.5) Потенциал Леннарда-ДжонсаПотенциал Леннарда-Джонса хорошо описывает взаимодействие между атомами Аргона. Для аргона $$m\approx 6.69\times 10^{-23}\hat e \tilde a,\:\:\: \sigma\approx 3.405 \times 10^{-10} \grave i ,\:\:\: \epsilon \approx 1.654\times 10^{-21} \ddot A ae$$. Будем считать, что массы всех частиц одинаковы, система единиц выбрана таким образом, что $$m = 1$$, $$\epsilon=1$$ и $$\sigma=1$$. Тогда сила парного взаимодействия:
$$F(r_i,r_j)=\frac{24(r_i-r_j)}{{\mid r_i-r_j\mid }^2} \left[\frac{2}{{\mid r_i-r_j\mid }^{12}} - \frac{1}{{\mid r_i-r_j\mid }^6} \right]$$Интерес могут представлять траектории частиц или термодинамические характеристики системы, например, зависимость температуры от времени:
$$T(t)=\frac{1}{3Nk_B}\sum\limits_{i=1}^N {\left \mid \frac{dr_i(t)}{dt} \right \mid }^2$$где $$k_B\approx 1.38\times 10^{-23}\frac{\ddot A ae}{\hat E}$$ -постоянная Больцмана.
Для вычисления траекторий в методе молекулярной динамики используются различные алгоритмы. Они основаны на замене непрерывного времени дискретным набором значений $$t\to t^k=t^0+k\Delta t, \:\:\: k=1,2,\ldots$$.. Одним из алгоритмов является метод Верле:
$$r_i^{k+1}=2r_i^k-r_i^{k-1}+F(r_i^k)\frac{\Delta t^2}{m_i}$$Здесь $$r_i^k=r_i(t^k)$$. Наиболее трудоемким является вычисление силы, действующей на частицу.
Для list_nb ) содержит количество ближайших соседей соответствующей частицы:
k0 = 0 j0 = 0 do i = 1, n do j = 1, n if(abs(x(i) - x(j)) < rcutoff) then j0 = j0 + 1 list_nb(i) = j end if end do i_nb(i) = j0 - k0 end do
Во втором массиве содержатся номера соседей каждой частицы. Положения хранятся в элементах, начиная с start(i) и заканчивая finish(i):
start(1) = 1 finish(1) = i_nb(1) do i = 2, n start(i) = finish(i - 1) + 1 finish(i) = finish(i - 1) + i_nb(i) end do
В заданиях лабораторной работы 3.1 предлагается выполнить оптимизацию вычислительной программы. Первый этап оптимизации - сокращение числа операций в последовательном коде на основе использования физических законов. Затем выполняется распараллеливание программы. Выбор инструмента распараллеливания должен быть аргументирован.
Данная работа не предполагает выполнения всех заданий. Учащемуся может быть предложен набор из нескольких заданий, обязательно включающий номера 1, 2 и 3, а также одно или несколько заданий, связанных с распараллеливанием.
По результатам составляется отчет, содержащий решения с обоснованием выбранного метода, результаты измерения быстродействия программы, а также физические результаты и выводы.
Выполнение данной работы рассчитано на несколько занятий (2-6 академических часов). Имеется полный исходный текст программы на языке Fortran 90.
Получить у преподавателя файл с исходным текстом программы и ознакомиться с реализацией метода молекулярной динамики.
Откомпилировать программу, выполнить моделирование для системы с параметрами, заданными преподавателем. Определить процессорное время, потраченное на выполнение моделирования.
Выполнить оптимизацию последовательного кода программы на основе "физических соображений". Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатом, полученным в задании 2.
Проанализировать последовательный код и выявить участки потенциального параллелизма. Выполнить распараллеливание с помощью (если это возможно).
Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатом, полученным в задании 3.
Проанализировать последовательный код, выявить участки потенциального параллелизма и предложить способ распараллеливания в модели передачи сообщений.
Выполнить распараллеливание с помощью MPI, используя блокирующие двухточечные операции обмена (если это возможно). Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатами, полученными в заданиях 3 и 4.
Проанализировать возможность использования других видов обмена (двухточечные неблокирующие, коллективные). Если предполагается выигрыш в производительности, модифицировать вариант программы с
использованием MPI. Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатами, полученными в заданиях 3 , 4 и 5.
Выполнить оптимизацию последовательного кода, полученного при выполнении задания 3, используя введение радиуса обрезания и метод генерации списков частиц. Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатом, полученным в задании 3.
Провести анализ зависимостей при генерации списков частиц. Выполнить распараллеливание, выбрав наиболее подходящий инструмент. Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатом, полученным в задании 7.
Выполнить
Исследовать степень сбалансированности загрузки процессоров (ядер при использовании многоядерной архитектуры). Если сбалансированность неудовлетворительная, предложить способы ее улучшения.
Исследовать масштабируемость программы. Если масштабируемость неудовлетворительная, предложить способы ее улучшения.
На основании результатов, полученных при выполнении заданий данной лабораторной работы, написать отчет, в котором содержатся выводы об эффективности различных способов оптимизации исходного последовательного кода и трудоемкости реализации этих способов на практике.
Далее приводится листинг программы молекулярной динамики.
program mol_dyn implicit real(8) (a-h, o-z) integer, parameter :: ndim = 1000 ! ! Массивы координат, проекций скоростей и ускорений частиц ! real(8), dimension(1:ndim) :: x, y, vx, vy, ax, ay ! ! Задание начальной конфигурации частиц ! call start(x, y, vx, vy, N, Sx, Sy, dt, dt2, nsnap, ntime) ! ! Вычисление ускорений частиц ! call accel(x, y, ax, ay, N, Sx, Sy, zpe) zpe =0.0d0 ! ! Энергия выводится через nsnap шагов ! do isnap = 1, nsnap ! ! Внутренний цикл - по шагам по времени ! do itime = 1, ntime ! ! Выполняется сдвиг частиц ! call move(x, y, vx, vy, ax, ay,N, Sx, Sy, dt, dt2, zke, zpe) end do ! ! Вывод значений энергии: кинетической, потенциальной и полной ! call output(zke, zpe, Sx, Sy, dt, N, ntime) end do end program ! !==================================================== ! subroutine start(x, y, vx, VY, N, Sx, Sy, dt, dt2, nsnap, ntime) implicit real(8) (a-h, o-z) integer, parameter :: ndim = 1000 real(8), dimension(1:ndim) :: x, y, vx, vy, ax, ay ! ! Число частиц ! n = 200 ! ! Размер области моделирования ! sx = 100.0d0 sy = 100.0d0 ! ! Шаг по времени ! dt = 1.0d-11 dt2 = dt**2 ! ! Максимальное значение скорости ! vmax = 10.0d0 ! ! Число строк в таблице вывода и количество шагов по времени между ними ! nsnap = 200 ntime = 500 ! ! Формируется начальная хаотическая конфигурация ! do i = 1, N call rndm(ranx) x(i) = sx * ranx call rndm(rany) y(i) = sy * rany call rndm(ranx) call rndm(rany) vx(i) = vmax * (2 * ranx - 1) vy(i) = vmax * (2 * rany - 1) end do do i = 1, N vxcum = vxcum + vx(i) vycum = vycum + vy(i) end do vxcum = vxcum / N vycum = vycum / N do i = 1, N vx(i) = vx(i) - vxcum vy(i) = vy(i) - vycum end do end subroutine ! !==================================================== ! subroutine move(x, y, vx, vy, ax, ay, N, Sx, Sy, dt, dt2, zke, zpe) implicit real(8) (a-h, o-z) integer, parameter :: ndim = 1000 real(8), dimension(1:ndim) :: x, y, vx, vy, ax, ay do i = 1, N xnew = x(i) + vx(i) * dt + 0.5d0 * ax(i) * dt2 ynew = y(i) + vy(i) * dt + 0.5d0 * ay(i) * dt2 ! ! Учет периодических граничных условий ! call cellp(xnew, ynew, vx(i), vy(i), sx, sy) x(i) = xnew y(i) = ynew vx(i) = vx(i) + 0.5d0 * ax(i) * dt vy(i) = vy(i) + 0.5d0 * ay(i) * dt end do call accel(x, y, ax, ay, N, Sx, Sy, zpe) do i = 1, n vx(i) = vx(i) + 0.5d0 * dt * ax(i) vy(i) = vy(i) + 0.5d0 * dt * ay(i) zke = zke + vx(i)**2 + vy(i)**2 end do end subroutine ! !==================================================== ! subroutine accel(x, Y, ax, ay, N, sx, sy, zpe) implicit real(8) (a-h, o-z) integer, parameter :: ndim = 1000 real(8), dimension(1:ndim) :: x, y, ax, ay do i = 1, n ax(i) = 0.0d0 ay(i) = 0.0d0 end do do i = 1, n do j = 1, n if(i /= j) then dx = x(i) - x(j) dY = y(i) - y(j) if(dabs(dx)>0.5 * sx) dx = dx - sign(sx, dx) if(dabs(dy)> 0.5 * sy) dy = dy - sign(sy, dy) ! Вычисление силы, действующей на j-ю частицу ! r = dsqrt(dx**2 + dy**2) ri = 1.0d0 / r ri6 = ri**6 g = 24.0d0 * ri6 * ri * (2.0d0 * ri6 - 1) force = 0.5d0 * g * ri pot = 4.0d0 * ri6 * (ri6**2 - 1.0d0) ax(i) = ax(i) + force * dx ay(i) = ay(i) + force * dy ax(j) = ax(j) - force * dx ay(j) = ay(j) - force * dy zpe = zpe + pot end if end do end do end subroutine ! !==================================================== ! subroutine cellp(xnew, ynew, vx, vy, Sx, Sy) implicit real(8) (a-h, o-z) if(xnew < 0) xnew = xnew + sx if(xnew > sx) xnew = xnew - sx if(ynew < 0) ynew = ynew + sy if(ynew > sy)ynew = ynew - sy end subroutine ! !==================================================== ! subroutine output(zke, zpe, sx, sy,dt, n, ntime) implicit real(8) (a-h, o-z) data iff/0/ if(iff == 0) then iff = 1 write(6,*) ' ke pe tot' end if zke = 0.5d0 * zke / ntime zpe = zpe / ntime tot = zke + zpe write(6, "(6(1x, e13.6))") zke, zpe,tot zke = 0.0d0 zpe = 0.0d0 end subroutine ! ! Генератор псевдослучайных чисел ! subroutine rndm(ran) implicit real*8(a-h,o-z) data a31/2147483647.d0/, mul/16807.d0/, x/268435451.d0/ t = dmod(x * mul, a31) ra = t x = t ran = ra / a31 end subroutine
Исходный текст последовательного варианта программы снабжен комментариями.
Применение третьего
позволяет сократить объем вычислений в цикле примерно в 2 раза.
Следующий прием основан на введении "радиуса обрезания" $$R_{cut}$$ и разбиении всех частиц на две группы по отношению к данной:
$$R_{cut}$$ выбирается таким образом, чтобы частицы из первой группы давали основной вклад во взаимодействие. Выбор обычно выполняется эмпирически, то есть, на основе пробных расчетов.
При вычислении силы сумма делится на две подсуммы по группам частиц: $$F_i=\sum\limts_{\mid r_i-r_j \mid \le R_{cut}} F(r_i,r_j) + \sum\limts_{\mid r_i-r_j \mid > R_{cut}} F(r_i,r_j)$$
Если вклад от удаленных частиц пересчитывать реже, чем от частиц, для которых $$\mid r_i-r_j\mid \le R_{cut}$$, трудоемкость вычисления силы уменьшится.
Для разработки параллельных программ часто используется язык программирования Фортран. Это одно из наиболее эффективных средств программирования вычислительных задач. Далее приводится краткое описание языка.
Для записи исходного текста программы на Фортране могут использоваться фиксированный и свободный форматы.Первый из них характерен для стандарта Фортран 77, второй применяется в Фортране 90 и более новых версиях . Фортран 90 поддерживает также фиксированный формат, что обеспечивает совместимость со старыми стандартами записи. При записи исходного текста в фиксированном формате строка содержит 72 позиции. Первые пять позиций отведены для меток, а шестая может быть пустой или содержать любой, отличный от пробела символ. В последнем случае строка считается строкой продолжения и при обработке компилятором присоединяется к предыдущей строке программы. Оператор может занимать позиции с 7 по 72.
В свободном формате записи все позиции строки равноправны, ее длина составляет 132 символа.
Программа на Фортране состоит из главной программы и, возможно, некоторого числа подпрограмм.Подпрограммы могут быть функциями или процедурами,внешними, внутренними или модульными. Различные программные компоненты могут компилироваться раздельно.
Первым оператором главной программы является её заголовок PROGRAM. За ним следует имя программы:
PROGRAM ИМЯ_ПРОГРАММЫ
Имя программы обязательно начинается с буквы, затем могут идти буквы, цифры и символы подчеркивания, например:
PROGRAM
PROGRAM QUADRATIC_EQUATION_SOLVER45
Максимальная длина любого имени в программах на Фортране - 31 символ. Первым оператором подпрограммы может быть только ее заголовок FUNCTION или . Последней строкой программного компонента должна быть строка с оператором END. Заключительный оператор главной программы может иметь также следующий вид:
END PROGRAM ИМЯ_ПРОГРАММЫ
ИМЯ_ПРОГРАММЫ является необязательной частью оператора.
После заголовка следуют описания переменных, констант, меток, подпрограмм и других объектов, используемых в программе. Эта ее часть называется разделом описаний.После раздела описаний следует раздел операторов.
Перечень встроенных типов в порядке возрастания их ранга дан ниже.
LOGICAL(1) и BYTELOGICAL(2)LOGICAL(4)INTEGER(1)INTEGER(2)INTEGER(4)REAL(4)REAL(8)COMPLEX(8)COMPLEX(16) У каждого встроенного типа Фортрана есть несколько разновидностей, которые отличаются друг от друга диапазоном значений и некоторыми другими характеристиками.
Значение символьного типа CHARACTER представляет собой строку символов. Длина строкового значения в Фортране может быть произвольной и задается с помощью параметра LEN в предложении описания строковой переменной, например:
CHARACTER(LEN = 430) :: Shakespeare_sonet
Предложение описания переменных в Фортране 90 имеет вид:
ТИП[, АТРИБУТЫ] :: СПИСОК_ПЕРЕМЕННЫХ
В списке имена переменных разделяются запятыми, а ТИП задает общий тип переменных, являясь идентификатором типа:
REAL, PARAMETER :: salary = 2000
В Фортране 90 используются следующие атрибуты объектов:
PARAMETER - объект является PUBLIC - объект является доступным за пределами модуля;PRIVATE - объект недоступен за пределами модуля;POINTER - объект является ссылкой (указателем);TARGET - объект можно использовать в качестве адресата в операторах назначения ссылок;ALLOCATABLE - объект является DIMENSION - объект является массивом;INTENT - определяет вид связи для параметра процедуры (т. е., является входным, выходным или и входным и выходным);OPTIONAL - необязательный параметр процедуры;SAVE - сохранять значение локальной переменной подпрограммы в промежутке между ее вызовами;EXTERNAL - для INTRINSIC - для внутренней функции.Буквальные числовые константы записываются обычным образом. Комплексная буквальная константа записывается в круглых скобках:
i ;2 + i.Имеются две буквальные логические константы:
.TRUE. - "истина";.FALSE. - "ложь".Буквальная
Арифметические операции Фортрана (в порядке убывания приоритета):
** - возведение в степень;*, / - умножение, деление;-, + - вычитание, сложение.Минус (-) и плюс (+) используются также как знаки унарных операций: В Фортране поддерживаются следующие
| Знак операции | Альтернативное обозначение | Название операции сравнения |
|---|---|---|
.LT. |
< | меньше |
.LE. |
<= | меньше или равно |
.GT. |
> | больше |
.GE. |
>= | больше или равно |
.EQ. |
== | Равно |
.NE. |
/ = | не равно |
Для значений комплексного типа действительны только операции "равно" ( .EQ.) и "не равно" ( .NE.).
Логические операции:
| Операция | Значение операции |
|---|---|
.NOT. |
Логическое отрицание |
.AND. |
Логическое пересечение (умножение, логическое "И") |
.OR. |
Логическое объединение (сложение, логическое "ИЛИ") |
. EQV.и .NEQV. |
Логические эквивалентность и неэквивалентность (логические равенство и неравенство) |
Массивы описываются с помощью атрибута DIMENSION:
REAL, DIMENSION(1:100) :: C
Параметром этого атрибута должен быть список экстентов (экстент - количество элементов массива для каждого измерения) описываемых массивов в виде
(экстент_1, экстент_2, ..., экстент_n)
Число экстентов определяет ранг массива. Каждый экстент записывается в виде:
[ нижняя_граница : ] верхняя_граница
Пример:
REAL, DIMENSION(0:10, 2, -3:3,11) :: FGRID
Если значение нижней границы опущено, ее значение полагается равным 1. В некоторых случаях, список экстентов сводится к списку разделенных запятыми двоеточий, число которых равно рангу массива. Только число экстентов задается при объявлении
REAL, ALLOCATABLE, DIMENSION(:, :) :: BE_LATER
PROGRAM dyn_array IMPLICIT NONE INTEGER SIZE REAL, ALLOCATABLE, DIMENSION(:) ::array WRITE(*, *) 'SIZE?' READ(*, *) SIZE IF(SIZE > 0) ALLOCATE(array(SIZE)) … IF(ALLOCATED(array)) DEALLOCATE(array) END PROGRAM dyn_array
DIMENSION, форма массива может быть указана непосредственно после его идентификатора:
REAL X(10, 20, 30), Y(100), Z(2, 300, 2, 4)
Решение нелинейного уравнения методом Ньютона
PROGRAM NEWTON IMPLICIT NONE REAL (8) :: X, DX, F, DF X = 3.3 ! НАЧАЛЬНОЕ ПРИБЛИЖЕНИЕ DO ! НЬЮТОНОВСКИЕ ИТЕРАЦИИ DX = F(X) / DF(X) ! ВЫЧИСЛЕНИЕ ШАГА X = X - DX ! ВЫЧИСЛЕНИЕ ОЧЕРЕДНОГО ПРИБЛИЖЕНИЯ IF(DX <= SPACING(X)) EXIT ! ЦИКЛ ЗАВЕРШАЕТСЯ, КОГДА ! ШАГ МЕНЬШЕ РАССТОЯНИЯ МЕЖДУ ДВУМЯ ПОСЛЕДОВАТЕЛЬНЫМИ ! ВЕЩЕСТВЕННЫМИ ЗНАЧЕНИЯМИ END DO PRINT *, X ! ВЫВОД ЗНАЧЕНИЯ КОРНЯ PRINT *, F(X) ! ВЫВОД ЗНАЧЕНИЯ ФУНКЦИИ В ТОЧКЕ X PRINT *, DF(X) ! ВЫВОД ЗНАЧЕНИЯ ПРОИЗВОДНОЙ ! ФУНКЦИИ В ТОЧКЕ X END PROGRAM NEWTON REAL(8) FUNCTION F(X) IMPLICIT NONE REAL(8) :: X F = SIN(X) RETURN END
Ниже дается перечень некоторых конструкций и операторов Фортрана. Необязательные элементы заключены в квадратные скобки []. Если символ пробела не окружен квадратными скобками, то он является обязательным.
| Оператор | Описание |
|---|---|
PROGRAM имя_программы |
Оператор заголовка главной программы |
MODULE имя_модуля |
Оператор заголовка модуля |
END[ MODULE[имя_модуля]] |
Оператор завершения модуля |
USE имя_модуля[, ONLY only_список] |
Оператор |
[ |
Оператор заголовка подпрограммы-процедуры |
[тип][ |
Оператор заголовка подпрограммы-функции |
INTERFACE[ родовое_описание] |
Оператор заголовка интерфейса |
END[ ]INTERFACE |
Оператор завершения интерфейса |
CONTAINS |
Оператор содержания |
ENTRY |
|
BLOCK[ ]DATA[ имя_блока_данных] |
Оператор заголовка блока данных |
END [ ]BLOCK[ ]DATA[имя_блока_данных] |
Оператор завершения блока данных |
| Оператор | Описание |
|---|---|
MODULE PROCEDURE список_имен_модульных_процедур |
Оператор декларации модульных процедур |
и атрибуты - совместимая комбинация из следующих значений:
|
|
TYPE[, атрибут_доступа ::] имя_производного_типа атрибут_доступа - PUBLIC или PRIVATE |
Оператор определения |
END[ ]TYPE[ имя_типа] |
Оператор определения |
|
Оператор определения правил неявной типизации |
ALLOCATABLE [::] имя_массива[( список_экстентов)][, имя_массива [ (список_экстентов) ]...] |
Оператор назначения атрибута ALLOCATABLE |
DIMENSION имя_массива( список_экстентов)[, имя_массива (список_экстентов)...] |
Оператор спецификации массивов |
PARAMETER
(список_определений_именованных_констант) |
Оператор определения |
EXTERNAL список_внешних_имен |
Оператор назначения атрибута EXTERNAL |
|
Оператор назначения атрибута |
INTENT(параметр_входа/выхода) список_формальных_параметров |
Оператор назначения атрибута INTENT |
OPTIONAL список_формальных_параметров |
Оператор назначения атрибута OPTIONAL |
SAVE[[::] список_сохраняемых_объектов] |
Оператор назначения атрибута SAVE |
COMMON /[имя_общего_блока]/список_переменных[, /имя_общего_блока/список_переменных.... ] |
|
DATA список_объектов/список_значений/[, список_объектов/список_значений/...] |
Оператор инициализации объектов |
FORMAT([список_дескрипторов])* |
Оператор |
| Оператор | Описание |
|---|---|
END[ PROGRAM[ имя_программы]] |
Оператор завершения главной программы |
END[ подпрограмма[имя_подпрограммы]] где подпрограмма - |
Оператор завершения подпрограммы |
CALL
имя_подпрограммы[(список_фактических_параметров) ] |
|
RETURN |
Оператор возврата управления вызывающему компоненту программы |
STOP[ сообщение] |
Оператор останова программы |
| Оператор | Описание |
|---|---|
переменная = выражение |
Оператор присваивания для скалярных и массивоподобных объектов |
ссылка => адресат |
Оператор прикрепления ссылки к адресату |
| Оператор | Описание |
|---|---|
IF(скалярное_логическое_выражение) исполняемый_оператор |
Условный оператор |
WHERE( логическое_выражение_массив) массив_переменная = выражение_массив |
|
[ if_имя : ]
IF( скалярное_логическое_выражение) THEN
ELSE[[ ]IF(скалярное_логическое_выражение) THEN[ if_имя]
END[ ]IF[ if_имя] |
Конструкция ветвления IF_THEN_ELSE |
WHERE( логическое_выражение_массив)
ELSEWHERE
END[ ]WHERE |
Конструкция ветвления в присваивании массивов |
[sе1есt_имя:] SELECT [ ] CASE ( скалярное_выражение)
CASE ( список_возможных_значений)[ sе1есt_имя]
CASE DEFAULT [ sе1еct_имя] END [ ] SELECT [ sе1еct_имя] |
Конструкция SELECT |
GO[ ]TO метка |
|
[do_имя:] DO[ метка] переменная = скалярное_целое_выражение1, скалярное_целое_выражение2[, скалярное_целое_выражение3] |
Заголовок оператора цикла |
[do_имя:] DO[ метка] [,] WHILE(скалярное_лог_выражение) |
Заголовок оператора цикла в альтернативной форме |
CYCLE [ do_имя] |
|
EXIT[ do_имя] |
Оператор выхода из цикла с именем do_имя |
CONTINUE |
|
END[ ]DO[ do_имя] |
Оператор завершения цикла с именем do_имя |
| Оператор | Описание |
|---|---|
ALLOCATE( список_выделяемых_объектов[, STAT=статус]) |
Оператор выделения динамической памяти для выделяемых объектов |
|
Оператор освобождения динамической памяти от выделенных объектов |
| Оператор | Описание |
|---|---|
READ( список_управления_вводом) [ список_ввода] READ формат[, список_ввода] |
Оператор чтения данных |
WRITE(список_управления_выводом) [ список_вывода] |
Оператор записи данных |
PRINT формат[, список_вывода] |
Оператор вывода данных на устройство |
OPEN( список_спецификаций) |
|
CLOSE(список_спецификаций) |
Оператор закрытия файла |
| Имя подпрограммы | Возвращаемое значение или производимое действие |
|---|---|
ABS(A) |
Абсолютная величина |
ACHAR(I) |
I-ый символ сортирующей последовательности ASCII |
|
Арккосинус в радианах |
AIMAG(Z) |
Мнимая часть комплексного числа |
AINT(A[, KIND]) |
Усечение до целого |
ALLOCATED(ARRAY) |
Проверка выделенности |
ANINT(A [, KIND]) |
Ближайшее целое |
ASIN(X) |
Арксинус в радианах |
ATAN(X) |
Арктангенс в радианах |
ATAN2(Y, X) |
Аргумент комплексного числа |
CALL DATE_AND_TIME([DATE][, |
Считывание времени и даты с часов реального времени |
CALL RANDOM_NUMBER(HARVEST) |
Случайное число в интервале [0,1) |
CALL RANDOM_SEED([SIZE] [,PUT][,GET]) |
Получение/назначение затравочного массива |
CALL SYSTEM_CLOCK([COUNT] [,COUNT_RATE] [,COUNT_MAX]) |
Целочисленный отсчет часов реального времени |
CEILING(A) |
Наименьшее целое не меньшее аргумента |
CHAR(I [, KIND]) и ICHAR(C) |
I-ый символ в сортирующей последовательности процессора |
CMPLX(X [, Y] [, KIND]) |
Конструктор комплексного числа |
CONJG(Z) |
Комплексное сопряжение |
COS(X) |
Косинус |
COSH(X) |
Гиперболический косинус |
COUNT(MASK [, DIM]) |
Число элементов массива, имеющих значение "истина" |
CSHIFT(ARRAY, SHIFT [, DIM]) |
Циклический сдвиг элементов массива |
DIGITS(X) |
Число значащих цифр в модели представления аргумента |
DOT_PRODUCT(VECTOR_A, VECTOR_B) |
|
DPROD(X, Y) |
Умножение с двойной точностью |
EOSHIFT(ARRAY, SHIFT [, |
Вытесняющий сдвиг элементов массива |
EPSILON(X) |
Наименьшее число в модели представления аргумента, не пренебрежимое по сравнению с единицей |
EXP(X) |
Экспонента |
|
Степенная часть в модели представления аргумента |
FLOOR(A) |
Наименьшее целое, не превышающее аргумент |
|
Дробная часть в модели представления аргумента |
|
Наибольшее число в модели представления аргумента |
IACHAR(С) |
Индекс символа-аргумента в сортирующей последовательности ASCII |
IAND(I, J) |
Побитовое логическое И |
IBCLR(I, POS) |
Установка нуля в заданном бите |
IBITS(I, POS, LEN) |
Извлечение цепочки битов |
IBSET(I, POS) |
Установка единицы в заданном бите |
ICHAR(C) |
Индекс символа-аргумента в сортирующей последовательности процессора |
IEOR(I, J) |
Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ |
INDEX(STRING, SUBSTRING [,BACK]) |
Индекс начала подстроки в строке |
INT(A [, KIND]) |
Приведение к целому типу |
IOR(I, J) |
Побитовое логическое ИЛИ |
ISHIFT(I, SHIFT) |
Логический сдвиг битов |
ISHIFTC(I, SHIFT [, SIZE]) |
Логический циклический сдвиг части битов вправо |
KIND(X) |
Разновидность типа аргумента |
LBOUND(ARRAY [, DIM]) |
Нижняя граница массива |
LEN(S) |
Длина текстового аргумента |
LEN_TRIM(STRING) |
Длина строки без учета конечных пробелов |
LOG(X) |
Натуральный логарифм |
LOG10(X) |
Десятичный логарифм |
LOGICAL(L [, KIND]) |
Приведение к заданной разновидности логического типа |
MATMUL(MATRIX_A, MATRIX_B) |
|
MAX (A1, A2 [, A3, ]) |
Выбор максимального аргумента |
MAXLOC(ARRAY [, MASK]) |
Индекс наибольшего элемента массива |
MAXVAL(ARRAY [, DIM ] [,MASK]) |
Наибольший элемент массива |
MIN (A1, A2 [, A3, ]) |
Выбор минимального аргумента |
MINLOC(ARRAY [, MASK]) |
Индекс наименьшего элемента массива |
MINVAL(ARRAY [, DIM ] [,MASK]) |
Наименьший элемент массива |
MOD(A, P) |
Остаток от деления по модулю |
|
Деление по модулю |
NINT(A [, KIND]) |
Ближайшее целое |
NOT(I) |
Побитовое логическое дополнение |
PRECISION(X) |
Десятичная точность в модели представления аргумента |
PRESENT(A) |
Проверка присутствия необязательного аргумента |
PRODUCT(ARRAY [, DIM] [,MASK]) |
Произведение элементов массива |
REAL(A [, KIND]) |
Приведение к вещественному типу |
RESHAPE(SOURCE, SHAPE [,PAD] [, ORDER]) |
Изменение формы массива |
SCAN(STRING,SET[,BACK]) |
Индекс крайнего символа строки STRING в наборе SET |
SELECTED_INT_KIND(R) |
Параметр разновидности целого типа для заданного степенного диапазона |
SELECTED_REAL_KIND([P][,R]) |
Параметр разновидности вещественного типа для заданной точности и/или заданного степенного диапазона |
SHAPE(SOURCE) |
Форма аргумента |
SIGN(A, B) |
Абсолютное значение A со знаком B |
SIN(X) |
Синус |
SINH(X) |
Гиперболический синус |
SIZE(ARRAY[,DIM]) |
Размер массива |
SQRT(X) |
Квадратный корень |
SUM(ARRAY[,DIM][,MASK]) |
|
TAN(X) |
Тангенс |
TANH(X) |
Гиперболический тангенс |
TINY(X) |
Наименьшее положительное число в модели представления аргумента |
|
Транспонирование матрицы |
UBOUND(ARRAY [, DIM]) |
Верхняя граница массива |
Метод молекулярной динамики является одним из основных методов моделирования динамики систем, состоящих из взаимодействующих между собой частиц. Он применяется в молекулярной физике, астрофизике и других науках. Интерпретация понятия "частица" зависит от предметной области. В молекулярной физике это могут быть атом или молекула, а в астрофизике "частицами" являются звезды или планеты, взаимодействующие с другими астрономическими объектами посредством гравитационного взаимодействия. Динамика систем таких частиц часто описывается уравнениями классической механики.
Будем рассматривать систему N частиц, динамика которых описывается уравнением второго
Здесь $$F_i$$ - равнодействующая всех сил, действующих на $$i$$ -ю частицу, $$m_i$$ - ее масса и $$а_i$$ - ускорение, с которым частица двигается под действием силы. Это
где $$r_i$$
Равнодействующая сил, является суммой парных взаимодействий $$i$$ -й частицы со всеми остальными частицами:
$$F_i=F(r_i)=\sum\limits_{i\ne j=1}^N F(r_i,r_j)$$или
$$F_i=\sum\limits_{j=1}^{i-1}F(r_i,r_j) + \sum\limits_{j=i+1}^N F(r_i,r_j)$$Сила взаимодействия связана с потенциалом взаимодействия. В расчетах молекулярных систем часто используют потенциал Леннарда-Джонса:
$$V(r)=4\epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} - \left(\frac{\sigma}{r}\right)^6 \right]$$Здесь $$r =\mid r\mid $$, а $$\epsilon$$ и $$\sigma$$ - параметры потенциала. Первый определяет интенсивность взаимодействия, а второй - положение минимума (см. рис. 6.5).
(рис 6.5) Потенциал Леннарда-ДжонсаПотенциал Леннарда-Джонса хорошо описывает взаимодействие между атомами Аргона. Для аргона $$m\approx 6.69\times 10^{-23}\hat e \tilde a,\:\:\: \sigma\approx 3.405 \times 10^{-10} \grave i ,\:\:\: \epsilon \approx 1.654\times 10^{-21} \ddot A ae$$. Будем считать, что массы всех частиц одинаковы, система единиц выбрана таким образом, что $$m = 1$$, $$\epsilon=1$$ и $$\sigma=1$$. Тогда сила парного взаимодействия:
$$F(r_i,r_j)=\frac{24(r_i-r_j)}{{\mid r_i-r_j\mid }^2} \left[\frac{2}{{\mid r_i-r_j\mid }^{12}} - \frac{1}{{\mid r_i-r_j\mid }^6} \right]$$Интерес могут представлять траектории частиц или термодинамические характеристики системы, например, зависимость температуры от времени:
$$T(t)=\frac{1}{3Nk_B}\sum\limits_{i=1}^N {\left \mid \frac{dr_i(t)}{dt} \right \mid }^2$$где $$k_B\approx 1.38\times 10^{-23}\frac{\ddot A ae}{\hat E}$$ -постоянная Больцмана.
Для вычисления траекторий в методе молекулярной динамики используются различные алгоритмы. Они основаны на замене непрерывного времени дискретным набором значений $$t\to t^k=t^0+k\Delta t, \:\:\: k=1,2,\ldots$$.. Одним из алгоритмов является метод Верле:
$$r_i^{k+1}=2r_i^k-r_i^{k-1}+F(r_i^k)\frac{\Delta t^2}{m_i}$$Здесь $$r_i^k=r_i(t^k)$$. Наиболее трудоемким является вычисление силы, действующей на частицу.
Для list_nb ) содержит количество ближайших соседей соответствующей частицы:
k0 = 0 j0 = 0 do i = 1, n do j = 1, n if(abs(x(i) - x(j)) < rcutoff) then j0 = j0 + 1 list_nb(i) = j end if end do i_nb(i) = j0 - k0 end do
Во втором массиве содержатся номера соседей каждой частицы. Положения хранятся в элементах, начиная с start(i) и заканчивая finish(i):
start(1) = 1 finish(1) = i_nb(1) do i = 2, n start(i) = finish(i - 1) + 1 finish(i) = finish(i - 1) + i_nb(i) end do
В заданиях лабораторной работы 3.1 предлагается выполнить оптимизацию вычислительной программы. Первый этап оптимизации - сокращение числа операций в последовательном коде на основе использования физических законов. Затем выполняется распараллеливание программы. Выбор инструмента распараллеливания должен быть аргументирован.
Данная работа не предполагает выполнения всех заданий. Учащемуся может быть предложен набор из нескольких заданий, обязательно включающий номера 1, 2 и 3, а также одно или несколько заданий, связанных с распараллеливанием.
По результатам составляется отчет, содержащий решения с обоснованием выбранного метода, результаты измерения быстродействия программы, а также физические результаты и выводы.
Выполнение данной работы рассчитано на несколько занятий (2-6 академических часов). Имеется полный исходный текст программы на языке Fortran 90.
Получить у преподавателя файл с исходным текстом программы и ознакомиться с реализацией метода молекулярной динамики.
Откомпилировать программу, выполнить моделирование для системы с параметрами, заданными преподавателем. Определить процессорное время, потраченное на выполнение моделирования.
Выполнить оптимизацию последовательного кода программы на основе "физических соображений". Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатом, полученным в задании 2.
Проанализировать последовательный код и выявить участки потенциального параллелизма. Выполнить распараллеливание с помощью (если это возможно).
Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатом, полученным в задании 3.
Проанализировать последовательный код, выявить участки потенциального параллелизма и предложить способ распараллеливания в модели передачи сообщений.
Выполнить распараллеливание с помощью MPI, используя блокирующие двухточечные операции обмена (если это возможно). Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатами, полученными в заданиях 3 и 4.
Проанализировать возможность использования других видов обмена (двухточечные неблокирующие, коллективные). Если предполагается выигрыш в производительности, модифицировать вариант программы с
использованием MPI. Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатами, полученными в заданиях 3 , 4 и 5.
Выполнить оптимизацию последовательного кода, полученного при выполнении задания 3, используя введение радиуса обрезания и метод генерации списков частиц. Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатом, полученным в задании 3.
Провести анализ зависимостей при генерации списков частиц. Выполнить распараллеливание, выбрав наиболее подходящий инструмент. Определить процессорное время, потраченное на выполнение моделирования. Сравнить с результатом, полученным в задании 7.
Выполнить
Исследовать степень сбалансированности загрузки процессоров (ядер при использовании многоядерной архитектуры). Если сбалансированность неудовлетворительная, предложить способы ее улучшения.
Исследовать масштабируемость программы. Если масштабируемость неудовлетворительная, предложить способы ее улучшения.
На основании результатов, полученных при выполнении заданий данной лабораторной работы, написать отчет, в котором содержатся выводы об эффективности различных способов оптимизации исходного последовательного кода и трудоемкости реализации этих способов на практике.
Далее приводится листинг программы молекулярной динамики.
program mol_dyn implicit real(8) (a-h, o-z) integer, parameter :: ndim = 1000 ! ! Массивы координат, проекций скоростей и ускорений частиц ! real(8), dimension(1:ndim) :: x, y, vx, vy, ax, ay ! ! Задание начальной конфигурации частиц ! call start(x, y, vx, vy, N, Sx, Sy, dt, dt2, nsnap, ntime) ! ! Вычисление ускорений частиц ! call accel(x, y, ax, ay, N, Sx, Sy, zpe) zpe =0.0d0 ! ! Энергия выводится через nsnap шагов ! do isnap = 1, nsnap ! ! Внутренний цикл - по шагам по времени ! do itime = 1, ntime ! ! Выполняется сдвиг частиц ! call move(x, y, vx, vy, ax, ay,N, Sx, Sy, dt, dt2, zke, zpe) end do ! ! Вывод значений энергии: кинетической, потенциальной и полной ! call output(zke, zpe, Sx, Sy, dt, N, ntime) end do end program ! !==================================================== ! subroutine start(x, y, vx, VY, N, Sx, Sy, dt, dt2, nsnap, ntime) implicit real(8) (a-h, o-z) integer, parameter :: ndim = 1000 real(8), dimension(1:ndim) :: x, y, vx, vy, ax, ay ! ! Число частиц ! n = 200 ! ! Размер области моделирования ! sx = 100.0d0 sy = 100.0d0 ! ! Шаг по времени ! dt = 1.0d-11 dt2 = dt**2 ! ! Максимальное значение скорости ! vmax = 10.0d0 ! ! Число строк в таблице вывода и количество шагов по времени между ними ! nsnap = 200 ntime = 500 ! ! Формируется начальная хаотическая конфигурация ! do i = 1, N call rndm(ranx) x(i) = sx * ranx call rndm(rany) y(i) = sy * rany call rndm(ranx) call rndm(rany) vx(i) = vmax * (2 * ranx - 1) vy(i) = vmax * (2 * rany - 1) end do do i = 1, N vxcum = vxcum + vx(i) vycum = vycum + vy(i) end do vxcum = vxcum / N vycum = vycum / N do i = 1, N vx(i) = vx(i) - vxcum vy(i) = vy(i) - vycum end do end subroutine ! !==================================================== ! subroutine move(x, y, vx, vy, ax, ay, N, Sx, Sy, dt, dt2, zke, zpe) implicit real(8) (a-h, o-z) integer, parameter :: ndim = 1000 real(8), dimension(1:ndim) :: x, y, vx, vy, ax, ay do i = 1, N xnew = x(i) + vx(i) * dt + 0.5d0 * ax(i) * dt2 ynew = y(i) + vy(i) * dt + 0.5d0 * ay(i) * dt2 ! ! Учет периодических граничных условий ! call cellp(xnew, ynew, vx(i), vy(i), sx, sy) x(i) = xnew y(i) = ynew vx(i) = vx(i) + 0.5d0 * ax(i) * dt vy(i) = vy(i) + 0.5d0 * ay(i) * dt end do call accel(x, y, ax, ay, N, Sx, Sy, zpe) do i = 1, n vx(i) = vx(i) + 0.5d0 * dt * ax(i) vy(i) = vy(i) + 0.5d0 * dt * ay(i) zke = zke + vx(i)**2 + vy(i)**2 end do end subroutine ! !==================================================== ! subroutine accel(x, Y, ax, ay, N, sx, sy, zpe) implicit real(8) (a-h, o-z) integer, parameter :: ndim = 1000 real(8), dimension(1:ndim) :: x, y, ax, ay do i = 1, n ax(i) = 0.0d0 ay(i) = 0.0d0 end do do i = 1, n do j = 1, n if(i /= j) then dx = x(i) - x(j) dY = y(i) - y(j) if(dabs(dx)>0.5 * sx) dx = dx - sign(sx, dx) if(dabs(dy)> 0.5 * sy) dy = dy - sign(sy, dy) ! Вычисление силы, действующей на j-ю частицу ! r = dsqrt(dx**2 + dy**2) ri = 1.0d0 / r ri6 = ri**6 g = 24.0d0 * ri6 * ri * (2.0d0 * ri6 - 1) force = 0.5d0 * g * ri pot = 4.0d0 * ri6 * (ri6**2 - 1.0d0) ax(i) = ax(i) + force * dx ay(i) = ay(i) + force * dy ax(j) = ax(j) - force * dx ay(j) = ay(j) - force * dy zpe = zpe + pot end if end do end do end subroutine ! !==================================================== ! subroutine cellp(xnew, ynew, vx, vy, Sx, Sy) implicit real(8) (a-h, o-z) if(xnew < 0) xnew = xnew + sx if(xnew > sx) xnew = xnew - sx if(ynew < 0) ynew = ynew + sy if(ynew > sy)ynew = ynew - sy end subroutine ! !==================================================== ! subroutine output(zke, zpe, sx, sy,dt, n, ntime) implicit real(8) (a-h, o-z) data iff/0/ if(iff == 0) then iff = 1 write(6,*) ' ke pe tot' end if zke = 0.5d0 * zke / ntime zpe = zpe / ntime tot = zke + zpe write(6, "(6(1x, e13.6))") zke, zpe,tot zke = 0.0d0 zpe = 0.0d0 end subroutine ! ! Генератор псевдослучайных чисел ! subroutine rndm(ran) implicit real*8(a-h,o-z) data a31/2147483647.d0/, mul/16807.d0/, x/268435451.d0/ t = dmod(x * mul, a31) ra = t x = t ran = ra / a31 end subroutine
Исходный текст последовательного варианта программы снабжен комментариями.
Применение третьего
позволяет сократить объем вычислений в цикле примерно в 2 раза.
Следующий прием основан на введении "радиуса обрезания" $$R_{cut}$$ и разбиении всех частиц на две группы по отношению к данной:
$$R_{cut}$$ выбирается таким образом, чтобы частицы из первой группы давали основной вклад во взаимодействие. Выбор обычно выполняется эмпирически, то есть, на основе пробных расчетов.
При вычислении силы сумма делится на две подсуммы по группам частиц: $$F_i=\sum\limts_{\mid r_i-r_j \mid \le R_{cut}} F(r_i,r_j) + \sum\limts_{\mid r_i-r_j \mid > R_{cut}} F(r_i,r_j)$$
Если вклад от удаленных частиц пересчитывать реже, чем от частиц, для которых $$\mid r_i-r_j\mid \le R_{cut}$$, трудоемкость вычисления силы уменьшится.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.