Моделирование процессов в объектах со сложной структурой микровключений (сюда относятся композиты, геофизические среды, различные смеси, бетон и др), которое в последнее время становится весьма популярным (или оно давно стало популярным, а я заметил это только сейчас), побудило меня сконструировать какой-нибудь код, которым могли бы пользоваться для определения геометрии таких объектов. Конечно, у каждой задачи свои особенности и создать универсальный код вряд ли получится, но, может, какие-нибудь его части или идеи могут быть кому-нибудь полезны (а кому-то, кто моделирует бетон с кусочками щебня - точно пригодится ;-) ).
Начнем с простого. Зададим геометрию объекта, имеющего большое количество сферических непересекающихся микровключений. Слово "непересекающихся" здесь ключевое, потому что мы все будем делать в Gmsh'е, а он, как известно, не умеет осуществлять логические операции над объектами (объединение, пересечение и т.д.). Для этих целей нужно воспользоваться дополнительным инструментом, некоторые из них я перечислял в посте Триангуляция сложных моделей.
Многие приемы задания геометрии уже были рассмотрены, например, здесь. Некоторые мы рассмотрим впервые.
Итак, приступим. В качестве образца рассматриваемого материала выступает параллелепипед. Поэтому зададим его первым. Вариантов задания можно придумать воз и маленькую тележку (хотя нет - для параллелепипеда два воза точно). Приведем здесь самый короткий способ определения параллелепипеда, который я только смог придумать (хотя далеко не самый простой). Заодно воспользуемся принципом модульного программирования, поддерживаемого Gmsh'ем, и каждый значимый кусок модели будем оформлять в отдельном файле.
brick.geo
sphere.geo
Приведем также список всех команд типа newp, newl, использующихся в нашем коде:
Соберем теперь наши готовые геометрические элементы в одном файле, который и определит целиком геометрию исследуемого объекта.
model.geo
Отмечу, что код во многом основан на примере t5.geo из туториала Gmsh'а. Также можно заметить, что код получился вполне универсальным в том смысле, что добавив функции-шаблоны, задающие включения цилиндрического, эллипсоидного и других типов, можно создать вполне интересный инструмент определения геометрии объектов со сложной структурой микровключений. Единственное условие - включения не должны пересекаться. Приведенный код это не отслеживает.
Ну и на десерт - что получилось у меня с использованием данного кода (привожу только включения: слева 2х2х2, справа - 3х3х3)
Начнем с простого. Зададим геометрию объекта, имеющего большое количество сферических непересекающихся микровключений. Слово "непересекающихся" здесь ключевое, потому что мы все будем делать в Gmsh'е, а он, как известно, не умеет осуществлять логические операции над объектами (объединение, пересечение и т.д.). Для этих целей нужно воспользоваться дополнительным инструментом, некоторые из них я перечислял в посте Триангуляция сложных моделей.
Многие приемы задания геометрии уже были рассмотрены, например, здесь. Некоторые мы рассмотрим впервые.
Итак, приступим. В качестве образца рассматриваемого материала выступает параллелепипед. Поэтому зададим его первым. Вариантов задания можно придумать воз и маленькую тележку (хотя нет - для параллелепипеда два воза точно). Приведем здесь самый короткий способ определения параллелепипеда, который я только смог придумать (хотя далеко не самый простой). Заодно воспользуемся принципом модульного программирования, поддерживаемого Gmsh'ем, и каждый значимый кусок модели будем оформлять в отдельном файле.
brick.geo
// начальная точка параллелепипеда
x0 = 0;
y0 = 0;
z0 = 0;
// размеры параллелепипеда
lenX = 1;
lenY = 1;
lenZ = 1;
// характеристическая длина элементов разбиения параллелепипеда
clBrick = lenX / 2;
// задаем точку
Point(1) = { x0, y0, z0, clBrick };
// получаем линию
lineBrick[] = Extrude { lenX, 0, 0 } { Point{1}; };
// получаем поверхность
surfBrick[] = Extrude { 0, lenY, 0 } { Line{lineBrick[1]}; };
// получаем объем
volBrick[] = Extrude { 0, 0, lenZ } { Surface{surfBrick[1]}; };
// сохраняем поверхность параллелепипеда в виде массива
// для удобства дальнейшего использования
brickSurface[] = Boundary { Volume{volBrick[1]}; };
// сохраняем также номер замкнутого контура поверхностей
sl = newreg;
Surface Loop(sl) = { brickSurface[] };
brickSurfaceLoop = sl;
Теперь зададим шар, символизирующий микровключения. Оформим его в виде функции. Как и для параллелепипеда, создадим новый файл.sphere.geo
// центр шара - (x_c, y_c, z_c)
// радиус шара - rad
// характеристическая длина элементов разбиения шара - clSphere
// порядковый номер шара - number
Function SphereTemplate
// задаем 3 точки сектора сферы
p1 = newp; // команда newp определяет новый уникальный номер точки
Point(p1) = { x_c, y_c, z_c, clSphere };
p2 = newp;
Point(p2) = { x_c - rad, y_c, z_c, clSphere };
p3 = newp;
Point(p3) = { x_c, y_c - rad, z_c, clSphere };
// определяем одну линию - полуокружность
line = newl; // команда newl определяет новый уникальный номер линии
Circle(line) = { p2, p1, p3 };
// получаем поверхность - 1/8 часть всей поверхности шара
surfSphere1[] = Extrude { { rad, 0, 0 }, { x_c, y_c, z_c }, Pi / 2 }
{ Line{line}; };
// получаем остальные части поверхности, копируя исходную поверхность
// с зеркальным отображением по трем плоскостям
surfSphere2[] = Symmetry { 1, 0, 0, -x_c }
{ Duplicata { Surface{surfSphere1[1]}; } };
surfSphere3[] = Symmetry { 0, 1, 0, -y_c }
{ Duplicata { Surface{surfSphere1[1],
surfSphere2[0]}; } };
surfSphere4[] = Symmetry { 0, 0, 1, -z_c }
{ Duplicata { Surface{surfSphere1[1],
surfSphere2[0],
surfSphere3[0],
surfSphere3[1]}; } };
// замкнутый контур поверхностей шара
sl1 = newsl; // команда newsl определяет новый уникальный номер
// контура поверхностей
Surface Loop(sl1) = { surfSphere1[1], surfSphere2[0],
surfSphere3[0], surfSphere3[1],
surfSphere4[0], surfSphere4[1],
surfSphere4[2], surfSphere4[3] };
surfaceLoops[number] = sl1; // массив номеров контуров поверхностей
// задаем шар
v1 = newv; // команда newv определяет новый уникальный номер объема
Volume(v1) = { sl1 };
sphereVolumes[number] = v1; // массив номеров объемов
Return
Несколько замечаний по поводу функций в Gmsh'е. Начинается функция со строки Function funcName Заканчивается словом Return (без ';' в конце). Никаких входных и выходных параметров нет. Просто-напросто те переменные, которые вы используете в функции, должны быть инициализированы к моменту вызова функции, который осуществляется командой Call funcName; (здесь уже ';' присутствует). В нашей функции определения шара это переменные x_c, y_c, z_c, rad, clSphere, number. Приведем также список всех команд типа newp, newl, использующихся в нашем коде:
- newp определяет новый уникальный номер точки (point)
- newl определяет новый уникальный номер линии (line)
- newll определяет новый уникальный номер контура линий (line loop)
- news определяет новый уникальный номер поверхности (surface)
- newsl определяет новый уникальный номер контура поверхностей (surface loop)
- newv определяет новый уникальный номер объема (volume)
- newreg определяет новый уникальный номер региона (region) - может использоваться вместо любой из вышеперечисленных команд
Соберем теперь наши готовые геометрические элементы в одном файле, который и определит целиком геометрию исследуемого объекта.
model.geo
Include "brick.geo";
Include "sphere.geo";
// пусть центры включений расположены не случайно,
// а в узлах некоторой трехмерной решетки.
// подход, основанный на отдельном задании координат центров включений,
// позволит без большого изменения кода перейти
// к случаю, когда включения разбросаны по параллелепипеду случайным образом
// количество включений по каждому измерению
nInclusionsX = 2;
nInclusionsY = 2;
nInclusionsZ = 2;
// радиус сферического включения
radIncl = lenX / 10; // величина lenX взята из "brick.geo"
// общее количество включений
nIncl = nInclusionsX * nInclusionsY * nInclusionsZ;
// координаты центров включений
n = 0;
For i In { 1:nInclusionsZ }
For j In { 1:nInclusionsY }
For k In { 1:nInclusionsX }
// x0, y0, z0, lenX, lenY, lenZ взяты из "brick.geo"
x[n] = x0 + k * lenX / (nInclusionsX + 1);
y[n] = y0 + j * lenY / (nInclusionsY + 1);
z[n] = z0 + i * lenZ / (nInclusionsZ + 1);
n = n + 1;
EndFor
EndFor
EndFor
// создание включений
For i In { 1:nIncl }
x_c = x[i-1];
y_c = y[i-1];
z_c = z[i-1];
rad = radIncl; // здесь можно варьировать радиус шаров,
// создавая разномасштабные включения
clSphere = rad; // "мелкость" сетки в каждом шаре также можно варьировать
number = i; // номер включения
Call SphereTemplate; // вызов функции
EndFor
// окончательно оформляем массив номеров контуров поверхностей
surfaceLoops[0] = brickSurfaceLoop;
// создаем объем на основе массива контуров.
// этот объем - то, что не занято включениями
v = newreg;
Volume(v) = { surfaceLoops[] };
Physical Volume(1001) = { v }; // скелет (матрица)
Physical Volume(1002) = { sphereVolumes[] }; // поры (включения)
Для построения сетки остается только открыть в Gmsh'е файл "model.geo".Отмечу, что код во многом основан на примере t5.geo из туториала Gmsh'а. Также можно заметить, что код получился вполне универсальным в том смысле, что добавив функции-шаблоны, задающие включения цилиндрического, эллипсоидного и других типов, можно создать вполне интересный инструмент определения геометрии объектов со сложной структурой микровключений. Единственное условие - включения не должны пересекаться. Приведенный код это не отслеживает.
Ну и на десерт - что получилось у меня с использованием данного кода (привожу только включения: слева 2х2х2, справа - 3х3х3)
Комментариев нет:
Отправить комментарий