4.2.1 Criação e Refinamento
A primeira etapa do algoritmo consiste na criação e decomposição inicial da octree linear. CAMATA [17] define uma restrição na qual a octree inicial deve possuir ao menos 1 octante para cadacore (núcleo de processamento) disponível. Por isso, seja Do nível de profundidade da octree e np o número de cores, a decomposição inicial garante que8D ≥np.
Após a decomposição inicial, um primeiro particionamento é realizado. O algo-ritmo determina o número de octantes por processo, e cada processo fica responsável por gerar os códigos de localização de seus octantes.
Segue-se então para o refinamento da octree. O critério de refinamento é definido por uma função que recebe como argumento um octante e retorna um valor booleano definindo se o mesmo deve ou não ser dividido em novos elementos. No caso de um refinamento com base em geometrias imersas, como é o caso, a função retorna um valor verdadeiro caso o octante contenha em seu interior alguma parte do contorno da geometria dada como entrada. A partir deste critério é esperada uma octree com muitos elementos de tamanho menor em sua borda, e poucos elementos maiores em seu interior.
O refinamento da árvore, apresentado pelo Algoritmo 4.1, consiste em um laço no qual a função critério é executada para todos os octantes folha a cada iteração.
Caso a função critério retorne verdadeiro para ao menos 1 dos octantes, este é
decomposto em 8 novos filhos que são adicionados a octree resultando em um novo nível de profundidade. Com isso, o número de iterações do laço define o nível de profundidade final da octree.
Algoritmo 4.1:Refinar a octree com base em geometria imersa
Entrada: L, uma partição da octree linear, f, uma função-critério e Dmax, o nível de profundidade máximo da octree
Saída: L, uma octree linear refinada
1 para d←0 até Dmax faça
O custo assintótico de cada iteração do loop de refinamento, sem levar em conta a função de critério, é O(n), onden é o número de octantes folha da árvore.
4.2.2 Balanceamento 2:1
Como já introduzido na Seção 2.4, o balanceamento 2:1 define uma restrição onde dois octantes folhas vizinhos não podem ter uma diferença de mais de 1 nível de profundidade, ou considerando Π = {o1, o2...on} o conjunto de octantes folhas de uma octree L, N(oi) = {n1, n2...n8} o conjunto de octantes vizinhos de oi e D a função que fornece o nível do octante o, L está balanceada se, e somente se,
∀oi, oj ∈Π, oj ∈N(oi)⇒ ||D(oi)−D(oj)|| ≤1[84].
Esta restrição, utilizada em praticamente todos trabalhos de geração de malha com base em octree revisados [1, 12, 16, 44, 46–49] é primordial para viabilizar uma boa discretização do modelo numérico, já que como resultado obtêm-se transições mais suaves entre os elementos adjacentes, influenciando diretamente na qualidade da malha gerada. O balanceamento garante também que, ao mapear a geometria da octree diretamente para uma malha de hexaedros, cada aresta ou face da malha terá no máximo 1 nó em seu interior (no caso de vizinhos em diferentes níveis). Traz ainda uma diminuição do custo de travessia da estrutura de árvore, por eliminar as altas variações de profundidade entre nós vizinhos. Como inconveniente, o processo de balanceamento pode elevar o número de octantes em até 10% [27].
Ao se aplicar o processo de balanceamento, uma subdivisão realizada para bal-ancear um octante pode causar o desbalanceamento de algum de seus vizinhos. E a correção destes vizinhos pode causar o mesmo efeito, em um comportamento em cascata conhecido comoefeito ripple[84]. O tratamento do efeitoripple é a principal
dificuldade na implementação paralela dos algoritmos de balanceamento, já que os processos precisam ser sincronizados a cada iteração de balanceamento.
No algoritmo de CAMATA [17], o processo se inicia pelos octantes de maior nível de profundidade, verificando se a vizinhança dos mesmos satisfaz a restrição de balanceamento. Caso seja encontrado um octante vizinho com mais de 1 nível de diferença, este é refinado até que a restrição seja satisfeita. Para tratar o efeito ripple, as verificações e os condicionamentos são repetidos para os octantes de nível superior até que toda árvore satisfaça a condição de balanceamento. A verificação de vizinhança de todos os octantes da árvore e o tratamento do efeitoripple faz com que a complexidade assintótica do algoritmo sejaO(nlogn).
Na implementação paralela do algoritmo, cada processo realiza o balanceamento de sua sub-árvore. Porém, cuidados adicionais são tomados: como existe dependên-cia da informação de vizinhança, de alguma forma é preciso tratar os octantes cujos vizinhos estão alocados em um processo diferente. Para isso define-se uma estrutura local a cada processo que armazena os octantes de fronteira do processo vizinho (fronteira inter processos). Essa estrutura é sincronizada a cada iteração e um novo balanceamento local é feito com base na estrutura atualizada. A Figura 4.3 apre-senta uma octree dividida entre 4 processos e destaca a fronteira local e fronteira remota para o processo P0.
Figura 4.3: Esquema de sincronização do balanceamento entre vários processos -Adaptada de CAMATA [17]
4.2.3 Particionamento
O particionamento é responsável pela redistribuição dos octantes entre os processos de execução com o objetivo de manter o equilíbrio de carga de execução e assegurar a escalabilidade do algoritmo.
Como descrito na Seção 4.2.1, a inicialização da octree divide ao menos um
octante para cada processo de execução. Porém, a etapa de refinamento não garante a distribuição uniforme dos novos octantes entre todos os processos. O mesmo acontece na etapa de balanceamento, levando a uma diferença de carga na execução paralela das etapas subsequentes.
A Figura 4.4 apresenta um exemplo da distribuição dos tempos do balanceamento utilizando 16cores sem o particionamento (Figura 4.4(a)) e com o particionamento (Figura 4.4(b)). Observa-se que o tempo máximo obtido pode ter uma redução significativa. No exemplo, o tempo diminui de 10 para menos 1 segundo.
(a) (b)
Figura 4.4: Exemplo dos tempos de execução por core para o balanceamento 2:1 sem particionamento (a) e com particionamento (b)
Com a utilização da octree linear, onde cada processo armazena um bloco con-tíguo de octantes ordenados pelo código de localização, o particionamento é uma operação relativamente simples: primeiramente é feito a divisão do número total de octantes pelo número decoressendo utilizados para execução. Com base neste valor, uma nova distribuição do arranjo de octantes da octree linear entre os processos é realizada. A complexidade do algoritmo éO(p), sendop o número de processos.
4.2.4 Detecção de geometrias imersas
Como descrito na Seção 4.2.1, o critério de refinamento é estabelecido através da definição de uma função booleana que recebe um octante como argumento. Caso retorne um valor verdadeiro para o octante, o mesmo é substituído na octree linear por 8 novos octantes filhos.
Para a geração de malha com base em geometrias imersas no formato STL (do inglês, Standard Triangulation Language), o critério de refinamento utilizado foi a intersecção dos octantes da árvore com os triângulos que definem a geometria. Este critério traz como resultado uma octree com refinamento maior nas áreas próximas do contorno.
Para implementação da função critério, que precisa calcular de forma eficiente a interseção dos triângulos da geometria com os octantes da octree, CAMATA [17]
utilizou uma estrutura da geometria computacional conhecida como BBT (do inglês,
Bounding box tree). A BBT é um tipo de hierarquia de volumes de contorno [87]
que organiza um conjunto de objetos geométricos em forma de árvore, na qual cada nó da árvore define uma caixa de contorno regular, alinhada ao eixo cartesiano, que contenha seus nós filhos. A BBT da Figura 4.5 representa um conjunto de 4 objetos geométricos: os 4 nós folhas definem uma caixa de contorno para cada um dos objetos, os nós intermediários (em vermelho) definem uma caixa de contorno que contém seus 2 elementos filhos, e o nó raiz (em azul) define o contorno englobando todo conjunto.
Figura 4.5: BBT representando o domínio definido por 4 objetos geométricos -Adaptada de CAMATA [17]
A BBT é construída em paralelo, no processo de leitura do arquivo de geometria no formato STL, anteriormente à etapa de refinamento. Cada triângulo da geometria é representado por um nó folha da BBT.
A partir daí, a função-critério realiza uma busca na BBT para cada octante recebido verificando se o mesmo tem alguma intersecção com os volumes de contorno.
No caso de não haver nenhuma intersecção, a função-critério retorna um valor falso.
Se a procura alcançar um nó folha da BBT e o octante interceptar o triângulo armazenado pelo nó, a função-critério retorna um valor verdadeiro e o algoritmo de refinamento providencia a subdivisão do octante.