Next:ЗАКЛЮЧЕНИЕ К ЧАСТИ 3
Up:2. ИСПОЛЬЗОВАНИЕ БИБЛИОТЕКИ ПАРАЛЛЕЛЬНЫХ ПОДПРОГРАММ Aztec
Prev:2.4. Хранение разреженных матриц в MSR формате

2.5. Пример использования библиотеки Aztec

В заключение рассмотрим пример программы, в которой Aztec используется для решения системы уравнений, возникающей при конечно-разностной аппроксимации 3-х мерного оператора Лапласа. Для простоты мы не будем использовать систему уравнений, связанную с решением какой-либо реальной физической задачи, а вместо этого будем формировать правую часть таким образом, чтобы получить заранее известное решение, например,
X(i) = i + 1.

    program Aztec
c Параметры:
c ndim - максимальное число неизвестных,
c lda  - максимальный размер матрицы
    parameter (ndim = 125000, lda = 7*ndim)
    include 'mpif.h'
    include 'az_aztecf.h'
    integer n, nz
c
    integer i, ierror, recb(0:63), disp(0:63)
    double precision b(0:ndim), x(0:ndim), tmp(0:ndim)
    double precision s, time, total
c
    integer IAM, NPROCS
    integer N_update
    integer proc_config(0:AZ_PROC_SIZE), options(0:AZ_OPTIONS_SIZE)
    integer update(0:ndim), external(0:ndim), data_org(0:ndim)
    integer update_index(0:ndim), extern_index(0:ndim)
    integer bindx(0:lda)
    double precision params(0:AZ_PARAMS_SIZE)
    double precision status(0:AZ_STATUS_SIZE)
    double precision val(0:lda)
    common /global/ n
c Инициализация MPI (для Aztec не обязательна, если не использовать
c MPI функции)
    CALL MPI_Init(ierror)
c Получаем номер процессора и общее число процессоров,
c выделенных задаче
    call AZ_processor_info(proc_config)
    IAM = proc_config(AZ_node)
    NPROCS = proc_config (AZ_N_procs)
c
c На 0-м процессоре печатаем пояснительную информацию и считываем
c параметр, определяющий размер решаемой задачи
c (максимально 50х50х50)
    if (IAM.eq.0) then
    write(6,2)
 2  format(' '/
 $ ' Aztec example driver'//
 $ ' This program creates an MSR matrix corresponding to'/
 $ ' a 7pt discrete approximation to the 3D Poisson operator'/
 $ ' on an n x n x n square and solves it by various methods.'/
 $ ' n must be <= 50.'//)
    write (6,*) 'input number grid point on each direction n = '
    read(*,*) n
    endif
c Рассылаем считанный параметр всем процессорам
    call MPI_BCAST(n, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
c Вычисляем количество неизвестных в системе
    nz = n*n*n

c Цикл по всем методам решения
    DO 777 K = 0,4
    time = MPI_Wtime()
c Определяем параметры разбиения матрицы по процессорам
    call AZ_read_update(N_update, update, proc_config, nz, 1, 0)
c Формируем матрицу в виде массивов val и bindx,
c в bindx(0) заносим номер позиции, с которой начнут располагаться
c недиагональные элементы, и выполняем цикл по всем строкам
    bindx(0) = N_update+1
    do 250 i = 0, N_update-1
      call add_row_7pt(update(i), i, val, bindx)
  250 continue
c Формируем правую часть системы таким образом, чтобы получить
c известное решениеа b(i) = A(i,j)*j
c
    do 341 i = 0, N_update-1
    in = bindx(i)
    ik = bindx(i+1) - 1
    s = val(i)*(update(i)+1)
    do 342 j = in,ik
    s = s + val(j)*(bindx(j)+1)
 342 continue
     tmp(i) = s
 341 continue
c
c Преобразуем глобальную индексацию в локальную
    call AZ_transform(proc_config, external, bindx, val, update,
  $                   update_index, extern_index, data_org,
  $                   N_update, NULL,NULL,NULL,NULL, AZ_MSR_MATRIX)
c Устанавливаем параметры для решателя
    call AZ_defaults(options, params)
    options(AZ_solver) = K
    options(AZ_precond) = AZ_dom_decomp
    options(AZ_subdomain_solve) = AZ_ilu
    options(4) = 1
    options(AZ_output) = AZ_none
    options(AZ_max_iter) = 2000
    params(AZ_tol) = 1.d-10
c 0-й процессор печатает параметры решения задачи
    if (IAM.eq.0) then
    write(6,780)
    write (6,*) '        The solution of method is =',К
    write (6,*) '        Dimension matrices =',nz,
 $  '   NPROCS = ', NPROCS
    endif
c Преобразуем правую часть в соответствии с новой индексацией
    do 350 i = 0, N_update-1
    x(update_index(i)) = 0.0
    b(update_index(i)) = tmp(i)
 350 continue
c Решаем систему уравнений
    call AZ_solve(x,b, options, params, NULL,bindx,NULL,NULL,
 $                NULL, val, data_org, status, proc_config)
c Полученное решение возвращаем к исходной индексации
    DO 415 I = 0,N_update - 1
 415 tmp(i) = x(update_index(i))

c Выполняем сборку полученных частей решения в один вектор
c
    CALL MPI_ALLgather(N_update, 1, MPI_INTEGER, recb, 1,
 $                     MPI_INTEGER, MPI_COMM_WORLD, ierror)
    DISP(0) = 0
    DO 404 I = 1,NPROCS-1
 404 DISP(I) = DISP(I-1) + RECB(I-1)
    CALL MPI_ALLgatherv(tmp, N_update, MPI_DOUBLE_PRECISION, x, recb,
 $              disp, MPI_DOUBLE_PRECISION, MPI_COMM_WORLD, ierror)

c Печатаем первую и последнюю компоненты решения
    nz1 = nz-1
    if (IAM.eq.0) then
    do 348 i = 0,nz1,nz1
    s = x(i)
    write (6,956) i,s
 348 continue
 956 format (2x,'i=',I12,2x,'x(i)=',F18.8)
    endif
c
    time = MPI_Wtime() - time
c
    if(IAM.eq.0) write(*,435) time
 435  FORMAT(2x,'TIME CALCULATION (SEC.) = ',F12.4)
 777  continue
c
    CALL MPI_FINALIZE(IERROR)
    stop
    end

c Подпрограмма добавления очередной строки в массивы val и bindx
    subroutine add_row_7pt(row, location, val, bindx)
    integer row, location, bindx(0:*)
    double precision val(0:*)
    integer n3,n,k
    common /global/ n
c Входные параметры:
c row        - глобальный номер добавляемой строки
c location   - локальный номер строки в процессоре

c n3 - максимально возможный номер столбца
    n3 = n*n*n - 1
c Далее выполняется проверка: существует ли в трехмерной решетке
c ближайший сосед по каждому из направлений; если да, то
c соответствующий матричный элемент заносится и
c счетчик увеличивается на 1
    k = bindx(location)
    bindx(k) = row + 1
    if (bindx(k).le.n3) then
    val(k) = -1.
    k = k + 1
    endif
    bindx(k) = row - 1
    if (bindx(k) .ge. 0) then
    val(k) = -1.
    k = k + 1
    endif
    bindx(k) = row + n
    if (bindx(k).le.n3) then
    val(k) = -1.0
    k = k + 1
    endif
    bindx(k) = row - n
    if (bindx(k).ge. 0) then
    val(k) = -1.0
    k = k + 1
    endif
    bindx(k) = row + n*n
    if (bindx(k) .le. n3) then
    val(k) = -1.0
    k = k + 1
    endif
    bindx(k) = row - n*n
    if (bindx(k) .ge. 0) then
    val(k) = -1.0
    k = k + 1
    endif
c Занесение диагонального матричного элемента
    val(location) = 6.0
c Подготовка следующего шага: заносим номер позиции, с которой
c будут располагаться недиагональные элементы следующей строки
    bindx(location+1) = k
    return
    end



Next:ЗАКЛЮЧЕНИЕ К ЧАСТИ 3
Up:2. ИСПОЛЬЗОВАНИЕ БИБЛИОТЕКИ ПАРАЛЛЕЛЬНЫХ ПОДПРОГРАММ Aztec
Prev:2.4. Хранение разреженных матриц в MSR формате