progam.f90
1 ! $Id: progam.f90,v 1.2 2006-07-16 23:07:26 emiliano Exp $ 2 ! PROGAM - Programa de Generación Automática de Mallas 3
4 PROGRAM progam_s 5 USE region_mod 6 IMPLICIT NONE 7
8 TYPE(region_t), ALLOCATABLE, TARGET :: regions(:)
9 INTEGER :: i, n_regions, nstart 10
11 ! Procesamiento de la entrada de datos 12 CALL region_input(regions)
13 n_regions = SIZE(regions) 14
15 ! Divide cada región en elementos cuadrangulares 16 DO i=1, n_regions
17 CALL region_grid(regions(i)) 18 END DO
19
20 ! Asigna un número único a cada nodo 21 nstart = 1
22 DO i=1, n_regions
23 CALL region_nodenums(regions(i), nstart, regions) 24 END DO
25
26 ! Genera los elementos 27 DO i=1, n_regions
28 CALL region_elements(regions(i)) 29 END DO
30
31 ! Salida para GiD
32 CALL region_output(regions) 33
34 END PROGRAM progam_s
region.f90
1 ! $Id: region.f90,v 1.2 2006-07-16 21:51:41 emiliano Exp $ 2 ! PROGAM - Programa de Generación Automática de Mallas 3 4 MODULE region_mod 5 !DEC$ REAL:8 6 IMPLICIT NONE 7 8 TYPE region_t
9 INTEGER :: num ! número de región
10 INTEGER :: n, m ! cantidad de filas y columnas 11 INTEGER :: elem_type ! 3=triángulo, 4=cuadrado 12 INTEGER :: vecinas(4) ! datos de conectividad
13 REAL :: def_nodes(8,2) ! los 8 nodos que definen la región 14 REAL, ALLOCATABLE :: node_coords(:,:,:) ! coordenadas de los nodos
15 INTEGER, ALLOCATABLE :: node_nums(:,:) ! números de los nodos
16 INTEGER, ALLOCATABLE :: elements(:,:) ! cada elemento es un vector de 3 o 4 enteros 17 END TYPE region_t
18
19 CONTAINS
20 ! Procesamiento de la entrada de datos 21 SUBROUTINE region_input(regions)
22 TYPE(region_t), TARGET, ALLOCATABLE, INTENT(OUT) :: regions(:) 23 REAL, ALLOCATABLE :: input_nodes(:,:)
26 INTEGER :: node_num, i 27
28 READ(*,*) n_regions, n_input_nodes
29 ALLOCATE(regions(n_regions), input_nodes(n_input_nodes,2)) 30
31 DO i=1, n_input_nodes
32 READ(*,*) node_num, input_nodes(i,:) 33 END DO 34 35 DO i=1, n_regions 36 READ(*,*) regions(i)%n,regions(i)%m,regions(i)%elem_type,regions(i)%vecinas,node_nums 37 regions(i)%num = i 38 regions(i)%def_nodes = input_nodes(node_nums,:) 39 END DO
40 END SUBROUTINE region_input 41
42 ! Divide la región en (n-1)*(m-1) elementos cuadrangulares. 43 SUBROUTINE region_grid(this)
44 TYPE(region_t), INTENT(INOUT) :: this 45 INTEGER :: i, j
46 REAL :: pun(8) ! funciones de forma 47 REAL :: eta, si ! coordenadas normalizadas 48 REAL :: deta, dsi ! incrementos de eta y si 49 50 ALLOCATE(this%node_coords(this%n,this%m,2)) 51 ALLOCATE(this%node_nums(this%n,this%m)) 52 53 deta = 2./(this%n-1) 54 dsi = 2./(this%m-1) 55 DO i=1, this%n 56 eta = 1 - (i-1)*deta 57 DO j=1, this%m 58 si = -1 + (j-1)*dsi
59 pun(1) = -0.25 * (1-si) * (1-eta) * (si+eta+1) 60 pun(2) = 0.5 * (1-si**2) * (1-eta)
61 pun(3) = 0.25 * (1+si) * (1-eta) * (si-eta-1) 62 pun(4) = 0.5 * (1+si) * (1-eta**2)
63 pun(5) = 0.25 * (1+si) * (1+eta) * (si+eta-1) 64 pun(6) = 0.5 * (1-si**2) * (1+eta)
65 pun(7) = 0.25 * (1-si) * (1+eta) * (eta-si-1) 66 pun(8) = 0.5 * (1-si) * (1 - eta**2)
67 this%node_coords(i,j,1) = SUM(this%def_nodes(:,1) * pun) 68 this%node_coords(i,j,2) = SUM(this%def_nodes(:,2) * pun) 69 END DO
70 END DO
71 END SUBROUTINE region_grid 72
73 ! Numera en forma global los nodos de la región, teniendo en cuenta los que 74 ! ya han sido numerados por otras regiones. La variable nstart contiene el 75 ! primer número de la secuencia, y devuelve el primer número de la siguiente 76 ! region.
77 SUBROUTINE region_nodenums(this, nstart, regions) 78 TYPE(region_t), TARGET, INTENT(INOUT) :: this 79 INTEGER, INTENT(INOUT) :: nstart 80 TYPE(region_t), INTENT(IN) :: regions(:)
81 INTEGER :: i, j, istart, jstart, iend, jend 82 INTEGER, POINTER :: bound_nums(:)
83 REAL :: chk_node(2), recv_node(2) 84 85 istart=1 86 jstart=1 87 iend=this%n 88 jend=this%m 89
90 ! Verifica si los nodos de las fronteras son numerados por otra región 91 IF (this%vecinas(1)<this%num .AND. this%vecinas(1)/=0) iend=iend-1 92 IF (this%vecinas(2)<this%num .AND. this%vecinas(2)/=0) jend=jend-1 93 IF (this%vecinas(3)<this%num .AND. this%vecinas(3)/=0) istart=istart+1 94 IF (this%vecinas(4)<this%num .AND. this%vecinas(4)/=0) jstart=jstart+1 95
96 ! Numera los nodos 97 DO i=istart, iend
98 DO j=jstart, jend 99 this%node_nums(i,j) = nstart 100 nstart = nstart+1 101 END DO 102 END DO 103
104 ! Numera las fronteras que no han sido numeradas 105 DO i=1, 4
106 SELECT CASE(i) 107 CASE(1)
108 bound_nums => this%node_nums(this%n,:) ! abajo 109 chk_node = this%node_coords(this%n,1,:)
110 CASE(2)
111 bound_nums => this%node_nums(:,this%m) ! derecha 112 chk_node = this%node_coords(1,this%m,:)
113 CASE(3)
114 bound_nums => this%node_nums(1,:) ! arriba 115 chk_node = this%node_coords(1,1,:)
116 CASE(4)
117 bound_nums => this%node_nums(:,1) ! izquierda 118 chk_node = this%node_coords(1,1,:)
119 END SELECT 120
121 IF (this%vecinas(i)<this%num .AND. this%vecinas(i)/=0) THEN
122 CALL region_bound(regions(this%vecinas(i)), this%num, bound_nums, recv_node) 123 IF (ANY(chk_node/=recv_node)) CALL invertir(bound_nums)
124 END IF 125 END DO
126 END SUBROUTINE region_nodenums 127
128 ! Devuelve los números de nodos que están en la frontera con una región específica. 129 SUBROUTINE region_bound(this, vecina, bound_nums, chk_node)
130 TYPE(region_t), INTENT(IN) :: this ! región origen 131 INTEGER, INTENT(IN) :: vecina ! región destino
132 INTEGER, INTENT(OUT) :: bound_nums(:) ! vector en el que se devuelven los números 133 REAL, INTENT(OUT) :: chk_node(2) ! coordenadas de uno de los extremos 134
135 ! No uso select case porque require expresiones constantes. 136 IF (vecina==this%vecinas(1)) THEN
137 bound_nums = this%node_nums(this%n,:) 138 chk_node = this%node_coords(this%n,1,:) 139 ELSE IF (vecina==this%vecinas(2)) THEN 140 bound_nums = this%node_nums(:,this%m) 141 chk_node = this%node_coords(1,this%m,:) 142 ELSE IF (vecina==this%vecinas(3)) THEN 143 bound_nums = this%node_nums(1,:) 144 chk_node = this%node_coords(1,1,:) 145 ELSE IF (vecina==this%vecinas(4)) THEN 146 bound_nums = this%node_nums(:,1) 147 chk_node = this%node_coords(1,1,:) 148 END IF
149 END SUBROUTINE region_bound 150
151 ! Invierte el orden de los elementos en el vector. 152 SUBROUTINE invertir(vector)
153 INTEGER, INTENT(INOUT) :: vector(:) 154 INTEGER :: aux(SIZE(vector)) 155 INTEGER :: i, n 156 157 n = SIZE(vector) 158 DO i=1, n 159 aux(n-i+1) = vector(i) 160 END DO 161 vector = aux
162 END SUBROUTINE invertir 163
164 ! Genera elementos triangulares (dividiendo los cuadrados según la diagonal más 165 ! corta del elemento (1,1)) o cuadrangulares. Cada elemento es un vector formado 166 ! por los números de los nodos que lo definen.
170 REAL :: diag1, diag2 171
172 IF (this%elem_type == 3) THEN ! elementos triangulares 173 ALLOCATE(this%elements((this%n-1)*(this%m-1)*2, 3)) 174 k = 1
175 diag1 = SQRT((this%node_coords(1,1,1)-this%node_coords(2,2,1))**2 & 176 + (this%node_coords(1,1,2)-this%node_coords(2,2,2))**2) 177 diag2 = SQRT((this%node_coords(2,1,1)-this%node_coords(1,2,1))**2 & 178 + (this%node_coords(2,1,2)-this%node_coords(1,2,2))**2) 179
180 IF (diag1 < diag2) THEN 181 DO i=1, this%n-1 182 DO j=1, this%m-1 183 this%elements(k,1) = this%node_nums(i,j) 184 this%elements(k,2) = this%node_nums(i+1,j) 185 this%elements(k,3) = this%node_nums(i+1,j+1) 186 k = k+1 187 this%elements(k,1) = this%node_nums(i,j) 188 this%elements(k,2) = this%node_nums(i+1,j+1) 189 this%elements(k,3) = this%node_nums(i,j+1) 190 k = k+1 191 END DO 192 END DO 193 ELSE 194 DO i=1, this%n-1 195 DO j=1, this%m-1 196 this%elements(k,1) = this%node_nums(i,j) 197 this%elements(k,2) = this%node_nums(i+1,j) 198 this%elements(k,3) = this%node_nums(i,j+1) 199 k = k+1 200 this%elements(k,1) = this%node_nums(i+1,j) 201 this%elements(k,2) = this%node_nums(i+1,j+1) 202 this%elements(k,3) = this%node_nums(i,j+1) 203 k = k+1 204 END DO 205 END DO 206 END IF 207
208 ELSE IF (this%elem_type == 4) THEN ! elementos cuadrangulares 209 ALLOCATE(this%elements((this%n-1)*(this%m-1), 4)) 210 k = 1 211 DO i=1, this%n-1 212 DO j=1, this%m-1 213 this%elements(k,1) = this%node_nums(i,j) 214 this%elements(k,2) = this%node_nums(i+1,j) 215 this%elements(k,3) = this%node_nums(i+1,j+1) 216 this%elements(k,4) = this%node_nums(i,j+1) 217 k = k+1 218 END DO 219 END DO 220 END IF
221 END SUBROUTINE region_elements 222
223 ! Salida para GiD
224 SUBROUTINE region_output(regions)
225 TYPE(region_t), INTENT(IN) :: regions(:)
226 INTEGER :: i, j, k, elem_num, node_num 227 228 elem_num = 1 229 node_num = 0 230 OPEN(UNIT=1, FILE='output.msh') 231 232 DO k=1, SIZE(regions) 233 ! Cabecera 234 IF (regions(k)%elem_type==3) THEN
235 WRITE(1,*) 'MESH dimension 2 ElemType Triangle Nnode 3' 236 ELSE IF (regions(k)%elem_type==4) THEN
237 WRITE(1,*) 'MESH dimension 2 ElemType Quadrilateral Nnode 4' 238 END IF
239
240 ! Coordenadas de los nodos 241 WRITE(1,*) 'coordinates'
242 WRITE(1,*) '# num x y' 243 DO i=1, regions(k)%n 244 DO j=1, regions(k)%m
245 IF (regions(k)%node_nums(i,j)>node_num) THEN 246 node_num = regions(k)%node_nums(i,j)
247 WRITE(1,*) node_num, regions(k)%node_coords(i,j,:) 248 END IF
249 END DO 250 END DO
251 WRITE(1,*) 'end coordinates' 252
253 ! Elementos
254 WRITE(1,*) 'elements'
255 WRITE(1,*) '# num nodo1 nodo2 nodo3 nodo4' 256 DO i=1, SIZE(regions(k)%elements, DIM=1) 257 WRITE(1,*) elem_num, regions(k)%elements(i,:) 258 elem_num = elem_num+1
259 END DO
260 WRITE(1,*) 'end elements' 261 WRITE(1,*)
262 END DO
263 END SUBROUTINE region_output 264 END MODULE region_mod
test.f90
1 ! $Id: test.f90,v 1.1.1.1 2006-07-16 21:18:46 emiliano Exp $ 2 ! PROGAM - Programa de Generación Automática de Mallas 3
4 ! Esta prueba genera sucesivamente mallas de elementos finitos, 5 ! aumentando la cantidad de elementos geométricamente. Para cada 6 ! malla se toma el tiempo de cálculo, sin considerar la entrada 7 ! ni la salida de datos. 8 9 PROGRAM progam_s_test 10 USE region_mod 11 IMPLICIT NONE 12
13 TYPE(region_t), ALLOCATABLE, TARGET :: regions(:)
14 INTEGER :: i, n_regions, nstart 15 REAL :: ti, tf
16 INTEGER :: ierr, k
17 INTEGER, ALLOCATABLE :: n_init(:), m_init(:) 18
19 ! Procesamiento de la entrada de datos 20 CALL region_input(regions) 21 n_regions = SIZE(regions) 22 23 ALLOCATE(n_init(n_regions), m_init(n_regions)) 24 n_init = regions%n 25 m_init = regions%m 26 27 DO k=1, 100 28 regions%n = n_init*k 29 regions%m = m_init*k 30 31 CALL CPU_TIME(ti)
32 ! Divide cada región en elementos cuadrangulares 33 DO i=1, n_regions
34 CALL region_grid(regions(i)) 35 END DO
36
37 ! Asigna un número único a cada nodo 38 nstart = 1
39 DO i=1, n_regions
40 CALL region_nodenums(regions(i), nstart, regions) 41 END DO
45 CALL region_elements(regions(i)) 46 END DO
47 CALL CPU_TIME(tf) 48
49 WRITE(*,*) DOT_PRODUCT(regions%n, regions%m), tf-ti 50 DO i=1, n_regions 51 DEALLOCATE(regions(i)%node_coords) 52 DEALLOCATE(regions(i)%node_nums) 53 DEALLOCATE(regions(i)%elements) 54 END DO 55 END DO 56