1!> @example DirectAccessNoHolesF90.F902!! \brief Use direct access to MOAB data to avoid calling through API, in Fortran90 \n3!!4!! This example creates a 1d row of quad elements, such that all quad and vertex handles5!! are contiguous in the handle space and in the database. Then it shows how to get access6!! to pointers to MOAB-native data for vertex coordinates, quad connectivity, and tag storage7!! (vertex to quad adjacency lists aren't accessible from Fortran because they are std::vector's).8!! This allows applications to access this data directly9!! without going through MOAB's API. In cases where the mesh is not changing (or only mesh10!! vertices are moving), this can save significant execution time in applications.11!!12!! Using direct access (or MOAB in general) from Fortran is complicated in two specific ways:13!! 1) There is no way to use arrays with specified dimension starting/ending values with ISO_C_BINDING;14!! therefore, all arrays passed back from MOAB/iMesh must use 1-based indices; this makes it a bit15!! more difficult to traverse the direct arrays. In this example, I explicitly use indices that16!! look like my_array(1+v_ind...) to remind users of this.17!! 2) Arithmetic on handles is complicated by the fact that Fortran has no unsigned integer type. I get18!! around this by assigning to a C-typed variable first, before the handle arithmetic. This seems to19!! work fine. C-typed variables are part of the Fortran95 standard.20!!21!! ----------------------22!! | | | |23!! | | | | ...24!! | | | |25!! ----------------------26!!27!! -# Initialize MOAB \n28!! -# Create a quad mesh, as depicted above29!! -# Create 2 dense tags (tag1, tag2) for avg position to assign to quads, and # verts per quad (tag3)30!! -# Get connectivity, coordinate, tag1 iterators31!! -# Iterate through quads, computing midpoint based on vertex positions, set on quad-based tag132!! -# Iterate through vertices, summing positions into tag2 on connected quads and incrementing vertex count33!! -# Iterate through quads, normalizing tag2 by vertex count and comparing values of tag1 and tag234!!35!! <b>To compile</b>: \n36!! make DirectAccessNoHolesF90 \n37!! <b>To run</b>: ./DirectAccessNoHolesF90 [-nquads <# quads>]\n38!!39!! VSM: Note that IBM xlf compilers do not like dynamic sizing functions for40!! C_F_POINTER calls. This leads to internal compiler failure.41!! http://www-01.ibm.com/support/docview.wss?uid=swg1IV4942842!!43 #define CHECK(a) if (a .ne. iBase_SUCCESS) callexit(a)
4445program directaccessnoholesf90
46use, intrinsic :: iso_c_binding47implicitnone48 #include"iMesh_f.h"4950! declarations51 imesh_instance :: imesh
52 ibase_entitysethandle root_set
53integer :: nverts, tmpflag
54integer ierr, nquads, nquads_tmp
55 ibase_taghandle tag1h, tag2h
56TYPE(c_ptr) verts_ptr, quads_ptr, conn_ptr, x_ptr, y_ptr, z_ptr, tag1_ptr, tag2_ptr
57TYPE(c_ptr) tmp_quads_ptr, offsets_ptr ! pointers that are equivalence'd to arrays using c_f_pointer58real(c_double), pointer :: x(:), y(:), z(:), tag1(:), tag2(:) ! arrays equivalence'd to pointers59integer, pointer :: offsets(:) ! arrays equivalence'd to pointers60 ibase_entityhandle, pointer :: quads(:), verts(:), conn(:), tmp_quads(:) ! arrays equivalence'd to pointers61 ibase_entityarriterator viter, qiter
62integer(C_SIZE_T) :: startv, startq, v_ind, e_ind ! needed to do handle arithmetic63integercount, vpere, e, i, j, v, offsets_size, tmp_quads_size, n_dis
64character*120 opt
6566! initialize interface and get root set67call imesh_newmesh("", imesh, ierr)
68 check(ierr)
69call imesh_getrootset(%val(imesh), root_set, ierr)
70 check(ierr)
7172! create mesh73 nquads_tmp = 100074call create_mesh_no_holes(imesh, nquads_tmp, ierr)
75 check(ierr)
7677! get all vertices and quads as arrays78 nverts = 079call imesh_getentities(%val(imesh), %val(root_set), %val(0), %val(ibase_vertex), &
80 verts_ptr, nverts, nverts, ierr)
81 check(ierr)
82callc_f_pointer(verts_ptr, verts, [nverts])
83 nquads = 084call imesh_getentities(%val(imesh), %val(root_set), %val(2), %val(imesh_quadrilateral), &
85 quads_ptr, nquads, nquads, ierr)
86 check(ierr)
87callc_f_pointer(quads_ptr, quads, [nquads])
8889! First vertex/quad is at start of vertex/quad list, and is offset for vertex/quad index calculation90 startv = verts(1)
91 startq = quads(1)
92call imesh_freememory(%val(imesh), quads_ptr)
9394! create tag1 (element-based avg), tag2 (vertex-based avg)95 opt = 'moab:TAG_STORAGE_TYPE=DENSE moab:TAG_DEFAULT_valUE=0'96call imesh_createtagwithoptions(%val(imesh), 'tag1', opt, %val(3), %val(ibase_double), &
97 tag1h, ierr, %val(4), %val(56))
98 check(ierr)
99call imesh_createtagwithoptions(%val(imesh), 'tag2', opt, %val(3), %val(ibase_double), &
100 tag2h, ierr, %val(4), %val(56))
101 check(ierr)
102103! Get iterator to verts, then pointer to coordinates104call imesh_initentarriter(%val(imesh), %val(root_set), %val(ibase_vertex), %val(imesh_all_topologies), &
105 %val(nverts), %val(0), viter, ierr)
106 check(ierr)
107call imesh_coordsiterate(%val(imesh), %val(viter), x_ptr, y_ptr, z_ptr, count, ierr)
108 check(ierr)
109 check(count-nverts) ! check that all verts are in one contiguous chunk110callc_f_pointer(x_ptr, x, [nverts])
111callc_f_pointer(y_ptr, y, [nverts])
112callc_f_pointer(z_ptr, z, [nverts])
113114! Get iterator to quads, then pointers to connectivity and tags115call imesh_initentarriter(%val(imesh), %val(root_set), %val(ibase_face), %val(imesh_all_topologies), &
116 %val(nquads), %val(0), qiter, ierr)
117 check(ierr)
118call imesh_connectiterate(%val(imesh), %val(qiter), conn_ptr, vpere, count, ierr)
119 check(ierr)
120callc_f_pointer(conn_ptr, conn, [vpere*nquads])
121call imesh_tagiterate(%val(imesh), %val(tag1h), %val(qiter), tag1_ptr, count, ierr)
122 check(ierr)
123callc_f_pointer(tag1_ptr, tag1, [3*nquads])
124call imesh_tagiterate(%val(imesh), %val(tag2h), %val(qiter), tag2_ptr, count, ierr)
125 check(ierr)
126callc_f_pointer(tag2_ptr, tag2, [3*nquads])
127128! iterate over elements, computing tag1 from coords positions;129! use (1+... in array indices for 1-based indexing130do i = 0, nquads-1131 tag1(1+3*i+0) = 0.0132 tag1(1+3*i+1) = 0.0133 tag1(1+3*i+2) = 0.0! initialize position for this element134do j = 0, vpere-1! loop over vertices in this quad135 v_ind = conn(1+vpere*i+j) ! assign to v_ind to allow handle arithmetic136 v_ind = v_ind - startv ! vert index is just the offset from start vertex137 tag1(1+3*i+0) = tag1(1+3*i+0) + x(1+v_ind)
138 tag1(1+3*i+1) = tag1(1+3*i+1) + y(1+v_ind) ! sum vertex positions into tag1...139 tag1(1+3*i+2) = tag1(1+3*i+2) + z(1+v_ind)
140enddo141 tag1(1+3*i+0) = tag1(1+3*i+0) / vpere;
142 tag1(1+3*i+1) = tag1(1+3*i+1) / vpere ! then normalize143 tag1(1+3*i+2) = tag1(1+3*i+2) / vpere;
144enddo! loop over elements in chunk145146! Iterate through vertices, summing positions into tag2 on connected elements;147! get adjacencies all at once,148! could also get them per vertex (time/memory tradeoff)149 tmp_quads_size = 0150 offsets_size = 0151 tmpflag = imesh_quadrilateral
152call imesh_getentarradj(%val(imesh), verts, %val(nverts), %val(tmpflag), &
153 tmp_quads_ptr, tmp_quads_size, tmp_quads_size, &
154 offsets_ptr, offsets_size, offsets_size, ierr)
155 check(ierr)
156157callc_f_pointer(tmp_quads_ptr, tmp_quads, [tmp_quads_size])
158callc_f_pointer(offsets_ptr, offsets, [offsets_size])
159call imesh_freememory(%val(imesh), verts_ptr)
160do v = 0, nverts-1161do e = 1+offsets(1+v), 1+offsets(1+v+1)-1! 1+ because offsets are in terms of 0-based arrays162 e_ind = tmp_quads(e) ! assign to e_ind to allow handle arithmetic163 e_ind = e_ind - startq ! e_ind is the quad handle minus the starting quad handle164 tag2(1+3*e_ind+0) = tag2(1+3*e_ind+0) + x(1+v)
165 tag2(1+3*e_ind+1) = tag2(1+3*e_ind+1) + y(1+v) ! tag on each element is 3 doubles, x/y/z166 tag2(1+3*e_ind+2) = tag2(1+3*e_ind+2) + z(1+v)
167enddo168enddo169call imesh_freememory(%val(imesh), tmp_quads_ptr)
170call imesh_freememory(%val(imesh), offsets_ptr)
171172! Normalize tag2 by vertex count (vpere); 173! loop over elements using same approach as before174! At the same time, compare values of tag1 and tag2175 n_dis = 0176do e = 0, nquads-1177do j = 0, 2178 tag2(1+3*e+j) = tag2(1+3*e+j) / vpere ! normalize by # verts179enddo180if (tag1(1+3*e) .ne. tag2(1+3*e) .or. tag1(1+3*e+1) .ne. tag2(1+3*e+1) .or. tag1(1+3*e+2) .ne. tag2(1+3*e+2)) then181print *, "Tag1, tag2 disagree for element ", e
182print *, "tag1: ", tag1(1+3*e), tag1(1+3*e+1), tag1(1+3*e+2)
183print *, "tag2: ", tag2(1+3*e), tag2(1+3*e+1), tag2(1+3*e+2)
184 n_dis = n_dis + 1185endif186enddo187if (n_dis .eq. 0) then188print *, 'All tags agree, success!'189endif190191! Ok, we are done, shut down MOAB192call imesh_dtor(%val(imesh), ierr)
193 check(ierr)
194endprogram directaccessnoholesf90
195196subroutine create_mesh_no_holes(imesh, nquads, ierr)
197use, intrinsic :: iso_c_binding198implicitnone199 #include"iMesh_f.h"200201 imesh_instance imesh
202integer nquads, ierr
203204real(C_DOUBLE), pointer :: coords(:,:)
205TYPE(c_ptr) tmp_ents_ptr, stat_ptr
206 ibase_entityhandle, pointer :: connect(:), tmp_ents(:)
207integer nverts, tmp_size, stat_size, i
208209! first make the mesh, a 1d array of quads with left hand side x = elem_num;210! vertices are numbered in layers211! create verts, num is 2(nquads+1) because they're in a 1d row212 nverts = 2*(nquads+1)
213allocate(coords(0:2, 0:nverts-1))
214do i = 0, nquads-1215 coords(0,2*i) = i
216 coords(0,2*i+1) = i ! x values are all i217 coords(1,2*i) = 0.0218 coords(1,2*i+1) = 1.0! y coords219 coords(2,2*i) = 0.0220 coords(2,2*i+1) = 0.0! z values, all zero (2d mesh)221enddo222! last two vertices223 coords(0, nverts-2) = nquads
224 coords(0, nverts-1) = nquads
225 coords(1, nverts-2) = 0.0226 coords(1, nverts-1) = 1.0! y coords227 coords(2, nverts-2) = 0.0228 coords(2, nverts-1) = 0.0! z values, all zero (2d mesh)229 tmp_size = 0230!!!!!! VSM: This is the culprit call that screws up IBM xlf compiler231call imesh_createvtxarr(%val(imesh), %val(nverts), %val(ibase_interleaved), &
232 coords, %val(3*nverts), tmp_ents_ptr, tmp_size, tmp_size, ierr)
233 check(ierr)
234callc_f_pointer(tmp_ents_ptr, tmp_ents, [nverts])
235deallocate(coords)
236allocate(connect(0:4*nquads-1))
237do i = 0, nquads-1238 connect(4*i+0) = tmp_ents(1+2*i)
239 connect(4*i+1) = tmp_ents(1+2*i+2)
240 connect(4*i+2) = tmp_ents(1+2*i+3)
241 connect(4*i+3) = tmp_ents(1+2*i+1)
242enddo243 stat_size = 0244 stat_ptr = c_null_ptr245! re-use tmp_ents here;246! we know it'll always be larger than nquads so it's ok247call imesh_createentarr(%val(imesh), %val(imesh_quadrilateral), connect, %val(4*nquads), &
248 tmp_ents_ptr, tmp_size, tmp_size, stat_ptr, stat_size, stat_size, ierr)
249 check(ierr)
250251 ierr = ibase_success
252253call imesh_freememory(%val(imesh), tmp_ents_ptr)
254call imesh_freememory(%val(imesh), stat_ptr)
255deallocate(connect)
256257return258endsubroutine create_mesh_no_holes
259