Периодические граничные условия в 3D на с++

Рейтинг: 0Ответов: 0Опубликовано: 31.03.2023

Всем здравствуйте. Пишу проект по моделированию развития кристаллической решётки методом градиентного спуска. Для того, чтобы аппроксимировать бесконечные размеры материала, хочу использовать периодические граничные условия. Если конкретнее, то нужна функция, которая будет копировать координаты атомов с границ куба и переносить на противоположную сторону, тогда будет происходить "самозамыкание" структуры. Придумал реализацию через кучу if-ов, перенося отдельно грани, углы и рёбра куба, но хотелось бы написать покрасивее, а не на 200 строк кода. В-принципе может быть вероятность, что и мои if-ы несовершенны, и если можете предложить лаконичное решение через них, то также прошу помочь.

Сами атомы хранятся в виде vector-а классов Atom (long double x, y, z;), операторы перегружены.

Для лучшего понимания прилагаю диаграмму переноса атомов в плоскости. (Извиняюсь за плохое качество).

Привожу код того, как я реализовал это через if-ы. (crystall_array - основной массив атомов, PGU_array - создаваемый массив атомов периодических граничных условий)

for (Atom atom : crystall_array)
{
    
    Atom temp_atom = atom;

    //Копирование атомов с левой стороны x
    if (atom.x < width_PGU)
    {
        atom.x += crystall_size_x;
        PGU_array.push_back(atom);
        if (atom.y < width_PGU)
        {
            atom.y += crystall_size_y;
            PGU_array.push_back(atom);
            if (atom.z < width_PGU)
            {
                atom.z += crystall_size_z;
                PGU_array.push_back(atom);
            }
            if (atom.z > crystall_size_z - width_PGU)
            {
                atom.z -= crystall_size_z;
                PGU_array.push_back(atom);
            }
        }
        if (atom.y > crystall_size_y - width_PGU)
        {
            atom.y -= crystall_size_y;
            PGU_array.push_back(atom);
            if (atom.z < width_PGU)
            {
                atom.z += crystall_size_z;
                PGU_array.push_back(atom);
            }
            if (atom.z > crystall_size_z - width_PGU)
            {
                atom.z -= crystall_size_z;
                PGU_array.push_back(atom);
            }
        }

        if (atom.z < width_PGU)
        {
            atom.z += crystall_size_z;
            PGU_array.push_back(atom);
            if (atom.y < width_PGU)
            {
                atom.y += crystall_size_y;
                PGU_array.push_back(atom);
            }
            if (atom.y > crystall_size_y - width_PGU)
            {
                atom.y -= crystall_size_y;
                PGU_array.push_back(atom);
            }
        }
        if (atom.z > crystall_size_z - width_PGU)
        {
            atom.z -= crystall_size_z;
            PGU_array.push_back(atom);
            if (atom.y < width_PGU)
            {
                atom.y += crystall_size_y;
                PGU_array.push_back(atom);
            }
            if (atom.y > crystall_size_y - width_PGU)
            {
                atom.y -= crystall_size_y;
                PGU_array.push_back(atom);
            }
        }
    }

    //Копирование атомов с правой стороны x
    if (atom.x > crystall_size_x - width_PGU)
    {
        atom.x -= crystall_size_x;
        PGU_array.push_back(atom);
        if (atom.y < width_PGU)
        {
            atom.y += crystall_size_y;
            PGU_array.push_back(atom);
            if (atom.z < width_PGU)
            {
                atom.z += crystall_size_z;
                PGU_array.push_back(atom);
            }
            if (atom.z > crystall_size_z - width_PGU)
            {
                atom.z -= crystall_size_z;
                PGU_array.push_back(atom);
            }
        }
        if (atom.y > crystall_size_y - width_PGU)
        {
            atom.y -= crystall_size_y;
            PGU_array.push_back(atom);
            if (atom.z < width_PGU)
            {
                atom.z += crystall_size_z;
                PGU_array.push_back(atom);
            }
            if (atom.z > crystall_size_z - width_PGU)
            {
                atom.z -= crystall_size_z;
                PGU_array.push_back(atom);
            }
        }


        if (atom.z < width_PGU)
        {
            atom.z += crystall_size_z;
            PGU_array.push_back(atom);
            if (atom.y < width_PGU)
            {
                atom.y += crystall_size_y;
                PGU_array.push_back(atom);
            }
            if (atom.y > crystall_size_y - width_PGU)
            {
                atom.y -= crystall_size_y;
                PGU_array.push_back(atom);
            }
        }
        if (atom.z > crystall_size_z - width_PGU)
        {
            atom.z -= crystall_size_z;
            PGU_array.push_back(atom);
            if (atom.y < width_PGU)
            {
                atom.y += crystall_size_y;
                PGU_array.push_back(atom);
            }
            if (atom.y > crystall_size_y - width_PGU)
            {
                atom.y -= crystall_size_y;
                PGU_array.push_back(atom);
            }
        }
    }

    atom = temp_atom;

    //Копирование атомов с левой стороны y
    if (atom.y < width_PGU)
    {
        atom.y += crystall_size_y;
        PGU_array.push_back(atom);
        if (atom.z < width_PGU)
        {
            atom.z += crystall_size_z;
            PGU_array.push_back(atom);
        }
        if (atom.z > crystall_size_z - width_PGU)
        {
            atom.z -= crystall_size_z;
            PGU_array.push_back(atom);
        }
    }
    //Копирование атомов с правой стороны y
    if (atom.y > crystall_size_y - width_PGU)
    {
        atom.y -= crystall_size_y;
        PGU_array.push_back(atom);
        if (atom.z < width_PGU)
        {
            atom.z += crystall_size_z;
            PGU_array.push_back(atom);
        }
        if (atom.z > crystall_size_z - width_PGU)
        {
            atom.z -= crystall_size_z;
            PGU_array.push_back(atom);
        }
    }

    atom = temp_atom;
    //Копирование атомов с правой стороны z
    if (atom.z < width_PGU)
    {
        atom.z += crystall_size_z;
        PGU_array.push_back(atom);
    }
    //Копирование атомов с левой стороны z
    if (atom.z > crystall_size_z - width_PGU)
    {
        atom.z -= crystall_size_z;
        PGU_array.push_back(atom);
    }
}

Ответы

Ответов пока нет.