2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение03.11.2015, 15:50 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Dmitriy40 в сообщении #1069837 писал(а):
Пока не нужны огромные (миллиарды элементов) массивы булевых переменных, в таком случае расходы памяти становятся неприемлимыми.

А они не нужны практически никогда. Практика показывает, что большие массивы нужны либо чисел (в расчётных задачах), либо нечисловых типов (в базах данных), и булевые там если и встречаются, то как сбоку припёка к чему-нибудь основному, и накладных расходов дают приемлемые проценты.

-- 03.11.2015 15:53:10 --

GAA в сообщении #1069866 писал(а):
К слову, где могут возникать проблемы.
При чтении двоичных файлов (записан в программе, написанной на одном компиляторе, а читается во второй программе, написанной на другом).

Ужас какой. В таких случаях надо тщательно прописывать формат файла, вплоть до битового уровня.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение04.11.2015, 20:52 
Заслуженный участник


29/12/14
504
В общем, в очередной раз, чтобы темы не плодить, напишу здесь. Следуя совету товарища Pphantom, отошёл от использования составных типов и перешёл к двумерным массивам. То, что написано на данный момент, по логике должно создавать некоторое (определяемое из характеристик системы) число пор, расположенных хаотично и имеющих некоторое дискретное распределение по радиусам. Это работает вроде как нормально. Дальше должны определяться кластеры этих самых пор, за это отвечает подпрограмма findclusters. И вот тут уже всё не очень хорошо. Программа упорно выдаёт ошибку stack overflow (как я понимаю, это типичная ошибка в программах новичков, поскольку так назван крупнейший ресурс типа вопросы-ответы). Я, было дело, грешил на переполнение памяти из-за массива indx1, но его подчистка в конце итерации не помогла. В чём моя ошибка?

Код под катом или по ссылке.

(Оффтоп)

код: [ скачать ] [ спрятать ]
Используется синтаксис Fortran
   
    subroutine geometry_definition(lattice,prob_distr,M,N,L)
    implicit none
    integer(8) N
    integer s, p, M
    real, parameter :: Pi = 3.141593
    real L
    real(8) phi, Q
    real, dimension(4,N) :: lattice
    real, dimension(M,2) :: prob_distr
    call random_seed()
    call random_number(lattice(1:3,:))          
    lattice(1:3,:)=L*lattice(1:3,:)                                                         ! "Разбрасывание" координат пор                                              

    do s = 1,N                                                                              ! "Разбрасывание" радиусов пор
        call random_number(Q)        
        if &#40;Q < prob_distr&#40;1,2&#41;&#41; then
            lattice&#40;4,s&#41; = prob_distr&#40;1,1&#41;
        else
                do p = 2, M
                if &#40;&#40;Q < sum&#40;prob_distr&#40;1:p,2&#41;&#41;&#41; .and. &#40;Q > sum&#40;prob_distr&#40;1:&#40;p-1&#41;,2&#41;&#41;&#41;&#41; then
                lattice&#40;4,s&#41; = prob_distr&#40;p,1&#41;
                end if
            end do
        end if
    end do
   
    end subroutine geometry_definition
   
    subroutine findclusters&#40;N,R_max,lattice&#41;
    implicit none
    integer&#40;8&#41; N
    integer i, p, j, l, q
    integer :: k = 1
    real R_max, R
    real, dimension&#40;5,N&#41;::lattice&#40;5,N&#41;, locations&#40;N,3&#41;, distances&#40;N&#41;, indx&#40;N&#41;, radius_vectors&#40;N,3&#41;
    integer, dimension&#40;:&#41;,allocatable::indx1
   
    indx = &#40;/&#40;q,q=1,N&#41;/&#41;
    lattice&#40;5,:&#41; = 0
    do l = 1, N  
        do p = 1, 3
            locations&#40;l,p&#41; = lattice&#40;p,l&#41;                                                                  ! Задание матрицы координат пор              
        end do                                                                            
    end do

    do i=1, N-1                                                                                                                            
            do p = 1, 3                                                                                    
                radius_vectors&#40;:,p&#41; = locations&#40;:,p&#41; - locations&#40;i,p&#41;                                      ! Определение матрицы радиус-векторов для текущей поры
            end do
        distances = sqrt&#40;sum&#40;&#40;radius_vectors&#41;**2, dim = 1&#41;&#41;                               ! Определение матрицы расстояний от текущей поры до всех остальных &#40;включая "текущую"&#41;                                                              ! Массив индексов всех пор
        allocate&#40;indx1&#40;count&#40;distances < 2*R_max&#41; - 1&#41;&#41;                                   ! Выделение памяти для массива индексов потенциальных соседей текущей поры indx1
        indx1 = pack&#40;indx, distances < 2*R_max .and. distances /= 0&#41;
        do p = 1,size&#40;indx1,1&#41;
                j = indx1&#40;p&#41;
                R = sqrt&#40;sum&#40;&#40;lattice&#40;1:3,i&#41; - lattice&#40;1:3,j&#41;&#41;**2&#41;&#41;
            if &#40;R < &#40;lattice&#40;4,i&#41; + lattice&#40;4,j&#41;&#41;&#41; then
                if &#40;&#40;lattice&#40;5,i&#41; == 0&#41; .and. &#40;lattice&#40;5,j&#41; == 0&#41;&#41; then                   ! Если поры соединены и не принадлежат ни одному из кластеров, они образуют новый кластер
                    lattice&#40;5,i&#41; = k                                                  
                    lattice&#40;5,j&#41; = k
                    k = k + 1
                else if &#40;&#40;lattice&#40;5,i&#41; /= 0&#41; .and. &#40;lattice&#40;5,j&#41; == 0&#41;&#41; then              ! Если одна из пор уже принадлежит какому-либо кластеру, а другая - нет, то
                    lattice&#40;5,j&#41; = lattice&#40;5,i&#41;                                           ! пора без кластера присоединяется к кластеру другой
                else if &#40;&#40;lattice&#40;5,i&#41; == 0&#41; .and. &#40;lattice&#40;5,j&#41; /= 0&#41;&#41; then
                    lattice&#40;5,i&#41; = lattice&#40;5,j&#41;
                else if &#40;&#40;lattice&#40;5,j&#41; /= 0&#41; .and. &#40;lattice&#40;5,i&#41; /= 0&#41; .and. &#40;lattice&#40;5,j&#41; /= lattice&#40;5,i&#41;&#41;&#41; then                       ! Если же обе поры являются частью кластеров &#40;разных&#41;,
                     where&#40;lattice&#40;5,:&#41; == max&#40;lattice&#40;5,i&#41;,lattice&#40;5,j&#41;&#41;&#41; lattice&#40;5,:&#41; = min&#40;lattice&#40;5,i&#41;,lattice&#40;5,j&#41;&#41;                ! то происходит объединение кластеров в тот, что имел меньший индекс                                                                                                            ! то происходит объединение кластеров в тот, что имел меньший индекс
                end if  
             end if
        end do
        deallocate&#40;indx1&#41;
    end do
   
    end subroutine findclusters
   

   
    program experiment
    implicit none
    integer&#40;8&#41; N                                                                            ! Число пор
    integer k                                                                                                                                                
    real, parameter :: Pi = 3.141593
    real L, phi, V_avg, R_max
    real, dimension&#40;:,:&#41;, allocatable :: lattice
    real, dimension&#40;:,:&#41;, allocatable :: prob_distr                                         ! Распределение пор по радиусам
    print*, &#39;Enter the parameters of your system&#39;
    print*, &#39;L =&#39;                                                                           ! Размер системы    
    read*, L    
    print*, &#39;phi =&#39;                                                                         ! Пористость системы
    read*, phi
    print*, &#39;How many points will be in your distribution?&#39;
    read*, k
    allocate&#40;prob_distr&#40;k,2&#41;&#41;
    print*, &#39;Enter the points of your distribution. First row is for radiuses, second is for probabilities&#39;
    1 read*, prob_distr
        if &#40;sum&#40;prob_distr&#40;:,2&#41;&#41; /= 1&#41; then
            print*, &#39;The probabilities of all possible events must total to 1. Try again&#39;
            goto 1
        end if
    R_max = maxval&#40;prob_distr&#40;:,1&#41;&#41;                                                         ! Максимально возможный радиус поры
    V_avg = &#40;sum&#40;&#40;&#40;prob_distr&#40;:,1&#41;&#41;**3&#41;*prob_distr&#40;:,2&#41;&#41;&#41;*4*Pi/3                            ! Средне значение объёма поры
    N = nint&#40;&#40;L**3*log&#40;1/&#40;1-phi&#41;&#41;&#41;/V_avg&#41;
    allocate&#40;lattice&#40;4,N&#41;&#41;
    call geometry_definition&#40;lattice,prob_distr,size&#40;prob_distr&#40;:,1&#41;&#41;,N,L&#41;
    call findclusters&#40;N,R_max,lattice&#41;
    pause
    end      
 

P.S. Ну и вообще, может, какие-нибудь замечания по коду есть, я бы с радостью послушал. :-)
(в частности, есть ощущение, что многие операции с массивами можно сделать значительно проще и элегантнее, чем у меня, но у меня при любых попытках что-нибудь подсократить начинал жаловаться компилятор)

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение04.11.2015, 21:35 
Заслуженный участник


09/05/12
25179
То, что "под катом", малочитаемо (но скачать код можно). Для поиска ошибок (и вообще удобства работы) сначала стоит записать вводимые параметры в текстовый файл и читать оттуда, а не вводить каждый раз вручную. Вообще это некое общее правило хорошего стиля - программа не должна требовать ввода чего-либо с клавиатуры во время работы и не должна выводить на экран ничего, кроме кратких диагностических сообщений, все содержательное - тоже только в файл. Сейчас же понять, что происходит, сложно хотя бы потому, что неизвестно, что именно нужно вводить.

А так... беглый просмотр кода позволяет разве что сократить некоторые участки. А именно:
Вместо
Используется синтаксис Fortran
                do p = 2, M
                if ((Q < sum(prob_distr(1:p,2))) .and. (Q > sum(prob_distr(1:(p-1),2)))) then
                lattice(4,s) = prob_distr(p,1)
                end if

явно стоит сделать что-то такое:
Используется синтаксис Fortran
                tempsum1=0.0
                tempsum2=prob_distr(1,2)
                do p = 2, M
                        tempsum1=tempsum1+prob_distr(p-1,2)
                        tempsum2=tempsum2+prob_distr(p,2)
                        if (Q < tempsum2 .and. Q > tempsum1) then lattice(4,s) = prob_distr(p,1)
                end do

Компилятор, конечно, может многое, но все же заставлять его постоянно считать суммы массивов в громадном количестве не стоит, если без этого можно обойтись (переменные tempsum1 и tempsum2, конечно, нужно определить).

Далее, вот это
Используется синтаксис Fortran
    do l = 1, N  
        do p = 1, 3
            locations(l,p) = lattice(p,l)                                                                  ! Задание матрицы координат пор              
        end do                                                                            
    end do

куда проще записать как
Используется синтаксис Fortran
locations=transpose(lattice(1:3,1:N))
Это, конечно, если подобное вообще зачем-то надо (по моим впечатлениям, массив locations на самом деле совершенно никому не нужен). Ну и т.д. и т.п.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение05.11.2015, 01:20 
Заслуженный участник


29/12/14
504
Pphantom
ещё раз спасибо за советы. Причесал, где чего смог, вроде как отловил всё, из-за чего ничего не работало, теперь программа заводится.
Цитата:
Вообще это некое общее правило хорошего стиля - программа не должна требовать ввода чего-либо с клавиатуры во время работы и не должна выводить на экран ничего, кроме кратких диагностических сообщений, все содержательное - тоже только в файл.

Извиняюсь, впредь буду знать.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение05.11.2015, 01:26 
Заслуженный участник


09/05/12
25179
Gickle в сообщении #1070357 писал(а):
Извиняюсь, впредь буду знать.
Извиняться не обязательно, это не норма вежливости, а просто естественное следствие процесса написания кода. При отладке неработающей программы Вы же первый замучаетесь постоянно вручную вводить ей одни и те же данные.

 Профиль  
                  
 
 Re: Сравнение массивов и ещё один вопрос по Fortran
Сообщение05.11.2015, 14:33 


24/11/11
75
Gickle в сообщении #1069500 писал(а):
Чтобы не засорять форум лишними темами, спрошу ещё несколько вопросов здесь, если никто не против:


В FORTRANе есть функция FORALL, если не ошибаюсь она должна позволить получить нужный результат в одну строку.
Что то типа:
FORALL(I = 1:N, A(I) > 5) A(I) = I

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 21 ]  На страницу Пред.  1, 2

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group