/[escript]/trunk/finley/src/Mesh_saveVTK.c
ViewVC logotype

Contents of /trunk/finley/src/Mesh_saveVTK.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3981 - (show annotations)
Fri Sep 21 02:47:54 2012 UTC (6 years, 10 months ago) by jfenwick
File MIME type: text/plain
File size: 47221 byte(s)
First pass of updating copyright notices
1
2 /*****************************************************************************
3 *
4 * Copyright (c) 2003-2012 by University of Queensland
5 * http://www.uq.edu.au
6 *
7 * Primary Business: Queensland, Australia
8 * Licensed under the Open Software License version 3.0
9 * http://www.opensource.org/licenses/osl-3.0.php
10 *
11 * Development until 2012 by Earth Systems Science Computational Center (ESSCC)
12 * Development since 2012 by School of Earth Sciences
13 *
14 *****************************************************************************/
15
16 /*************************************************************************************************/
17 /* Writes data and mesh in VTK XML format to a VTU file. */
18 /* Nodal data needs to be given on FINLEY_NODES or FINLEY_REDUCED_NODES */
19 /*************************************************************************************************/
20
21 #include "Mesh.h"
22 #include "Assemble.h"
23 #include "vtkCellType.h" /* copied from vtk source directory */
24 #include "paso/PasoUtil.h"
25
26 #define INT_FORMAT "%d "
27 #define LEN_INT_FORMAT (unsigned int)(9+2)
28 #define INT_NEWLINE_FORMAT "%d\n"
29 #define SCALAR_FORMAT "%12.6e\n"
30 #define VECTOR_FORMAT "%12.6e %12.6e %12.6e\n"
31 #define TENSOR_FORMAT "%12.6e %12.6e %12.6e %12.6e %12.6e %12.6e %12.6e %12.6e %12.6e\n"
32 /* strlen("-1.234567e+789 ") == 15 */
33 #define LEN_TENSOR_FORMAT (unsigned int)(9*15+2)
34 #define NEWLINE "\n"
35 #define LEN_TMP_BUFFER LEN_TENSOR_FORMAT+(MAX_numNodes*LEN_INT_FORMAT+1)+2
36 #define NCOMP_MAX (unsigned int)9
37
38 #define __STRCAT(dest, chunk, dest_in_use) \
39 do {\
40 strcpy(&dest[dest_in_use], chunk);\
41 dest_in_use += strlen(chunk);\
42 } while(0)
43
44 #ifdef ESYS_MPI
45 /* writes buffer to file catching the empty buffer case which causes problems
46 * with some MPI versions */
47 #define MPI_WRITE_ORDERED(BUF) \
48 do {\
49 int LLEN=0; \
50 LLEN=(int) strlen(BUF); \
51 if (LLEN==0) { strcpy(BUF, ""); LLEN=0; }\
52 MPI_File_write_ordered(mpi_fileHandle_p, BUF, LLEN, MPI_CHAR, &mpi_status);\
53 } while(0)
54
55 /* writes buffer to file on master only */
56 #define MPI_RANK0_WRITE_SHARED(BUF) \
57 do {\
58 int LLEN=0; \
59 if (my_mpi_rank == 0) {\
60 LLEN=(int) strlen(BUF); \
61 if (LLEN==0) { strcpy(BUF,""); LLEN=0; }\
62 MPI_File_iwrite_shared(mpi_fileHandle_p, BUF, LLEN, MPI_CHAR, &mpi_req);\
63 MPI_Wait(&mpi_req, &mpi_status);\
64 }\
65 } while(0)
66
67 /* For reference only. Investigation needed as to which values may improve
68 * performance */
69 #if 0
70 void create_MPIInfo(MPI_Info& info)
71 {
72 MPI_Info_create(&info);
73 MPI_Info_set(info, "access_style", "write_once, sequential");
74 MPI_Info_set(info, "collective_buffering", "true");
75 MPI_Info_set(info, "cb_block_size", "131072");
76 MPI_Info_set(info, "cb_buffer_size", "1048567");
77 MPI_Info_set(info, "cb_nodes", "8");
78 MPI_Info_set(info, "striping_factor", "16");
79 MPI_Info_set(info, "striping_unit", "424288");
80 }
81 #endif
82
83 #else
84
85 #define MPI_WRITE_ORDERED(A)
86 #define MPI_RANK0_WRITE_SHARED(A)
87
88 #endif /* ESYS_MPI */
89
90
91 /* Returns one if the node given by coords and idx is within the quadrant
92 * indexed by q and if the element type is Rec9 or Hex27, zero otherwise */
93 int nodeInQuadrant(const double *coords, Finley_ElementTypeId type, int idx, int q)
94 {
95 #define INSIDE_1D(_X_,_C_,_R_) ( ABS((_X_)-(_C_)) <= (_R_) )
96 #define INSIDE_2D(_X_,_Y_,_CX_,_CY_,_R_) ( INSIDE_1D(_X_,_CX_,_R_) && INSIDE_1D(_Y_,_CY_,_R_))
97 #define INSIDE_3D(_X_,_Y_,_Z_,_CX_,_CY_,_CZ_,_R_) ( INSIDE_1D(_X_,_CX_,_R_) && INSIDE_1D(_Y_,_CY_,_R_) && INSIDE_1D(_Z_,_CZ_,_R_) )
98
99 int ret;
100 if ( type == Finley_Line3Macro ) {
101 if (q==0)
102 ret = INSIDE_1D(coords[idx],0.25,0.25);
103 else if (q==1)
104 ret = INSIDE_1D(coords[idx],0.75,0.25);
105 else
106 ret=1;
107 } else if ( (type == Finley_Rec9) || (type == Finley_Rec9Macro) ) {
108 if (q==0)
109 ret = INSIDE_2D(coords[2*idx], coords[2*idx+1], 0.25, 0.25, 0.25);
110 else if (q==1)
111 ret = INSIDE_2D(coords[2*idx], coords[2*idx+1], 0.75, 0.25, 0.25);
112 else if (q==2)
113 ret = INSIDE_2D(coords[2*idx], coords[2*idx+1], 0.25, 0.75, 0.25);
114 else if (q==3)
115 ret = INSIDE_2D(coords[2*idx], coords[2*idx+1], 0.75, 0.75, 0.25);
116 else
117 ret = 0;
118 } else if ((type == Finley_Hex27) || (type == Finley_Hex27Macro) ){
119 if (q==0)
120 ret = INSIDE_3D(coords[3*idx], coords[3*idx+1], coords[3*idx+2],
121 0.25, 0.25, 0.25, 0.25);
122 else if (q==1)
123 ret = INSIDE_3D(coords[3*idx], coords[3*idx+1], coords[3*idx+2],
124 0.75, 0.25, 0.25, 0.25);
125 else if (q==2)
126 ret = INSIDE_3D(coords[3*idx], coords[3*idx+1], coords[3*idx+2],
127 0.25, 0.75, 0.25, 0.25);
128 else if (q==3)
129 ret = INSIDE_3D(coords[3*idx], coords[3*idx+1], coords[3*idx+2],
130 0.75, 0.75, 0.25, 0.25);
131 else if (q==4)
132 ret = INSIDE_3D(coords[3*idx], coords[3*idx+1], coords[3*idx+2],
133 0.25, 0.25, 0.75, 0.25);
134 else if (q==5)
135 ret = INSIDE_3D(coords[3*idx], coords[3*idx+1], coords[3*idx+2],
136 0.75, 0.25, 0.75, 0.25);
137 else if (q==6)
138 ret = INSIDE_3D(coords[3*idx], coords[3*idx+1], coords[3*idx+2],
139 0.25, 0.75, 0.75, 0.25);
140 else if (q==7)
141 ret = INSIDE_3D(coords[3*idx], coords[3*idx+1], coords[3*idx+2],
142 0.75, 0.75, 0.75, 0.25);
143 else
144 ret = 0;
145 } else {
146 ret = 1;
147 }
148 return ret;
149 }
150
151 void Finley_Mesh_saveVTK(const char *filename_p,
152 Finley_Mesh *mesh_p,
153 const dim_t num_data,
154 char **names_p,
155 escriptDataC **data_pp,
156 const char* metadata,
157 const char*metadata_schema)
158 {
159 #ifdef ESYS_MPI
160 MPI_File mpi_fileHandle_p;
161 MPI_Status mpi_status;
162 MPI_Request mpi_req;
163 MPI_Info mpi_info = MPI_INFO_NULL;
164 #endif
165 Esys_MPI_rank my_mpi_rank;
166 FILE *fileHandle_p = NULL;
167 char errorMsg[LenErrorMsg_MAX], *txtBuffer;
168 char tmpBuffer[LEN_TMP_BUFFER];
169 size_t txtBufferSize, txtBufferInUse, maxNameLen;
170 double *quadNodes_p = NULL;
171 dim_t dataIdx, nDim;
172 dim_t numCells=0, globalNumCells=0, numVTKNodesPerElement=0;
173 dim_t myNumPoints=0, globalNumPoints=0;
174 dim_t shape, NN=0, numCellFactor=1, myNumCells=0;
175 bool_t *isCellCentered;
176 bool_t writeCellData=FALSE, writePointData=FALSE, hasReducedElements=FALSE;
177 index_t myFirstNode=0, myLastNode=0, *globalNodeIndex=NULL;
178 index_t myFirstCell=0, k;
179 int mpi_size, i, j, l;
180 int cellType=0, nodeType=FINLEY_NODES, elementType=FINLEY_UNKNOWN;
181 Finley_ElementFile *elements = NULL;
182 Finley_ElementTypeId typeId = Finley_NoRef;
183
184 const char *vtkHeader = \
185 "<?xml version=\"1.0\"?>\n" \
186 "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"%s%s>\n%s%s" \
187 "<UnstructuredGrid>\n" \
188 "<Piece NumberOfPoints=\"%d\" NumberOfCells=\"%d\">\n" \
189 "<Points>\n" \
190 "<DataArray NumberOfComponents=\"%d\" type=\"Float64\" format=\"ascii\">\n";
191 char *vtkFooter = "</Piece>\n</UnstructuredGrid>\n</VTKFile>\n";
192 const char *tag_Float_DataArray="<DataArray Name=\"%s\" type=\"Float64\" NumberOfComponents=\"%d\" format=\"ascii\">\n";
193 char *tags_End_Points_and_Start_Conn = "</DataArray>\n</Points>\n<Cells>\n<DataArray Name=\"connectivity\" type=\"Int32\" format=\"ascii\">\n" ;
194 char *tags_End_Conn_and_Start_Offset = "</DataArray>\n<DataArray Name=\"offsets\" type=\"Int32\" format=\"ascii\">\n";
195 char *tags_End_Offset_and_Start_Type = "</DataArray>\n<DataArray Name=\"types\" type=\"UInt8\" format=\"ascii\">\n";
196 char *tag_End_DataArray = "</DataArray>\n";
197
198 const int VTK_LINE3_INDEX[] =
199 { 0, 2,
200 2, 1 };
201 const int VTK_HEX20_INDEX[] =
202 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 12, 13, 14, 15 };
203 const int VTK_REC9_INDEX[] =
204 { 0, 4, 8, 7, 4, 1, 5, 8, 7, 8, 6, 3, 8, 5, 2, 6 };
205 const int VTK_HEX27_INDEX[] =
206 { 0, 8, 20, 11, 12, 21, 26, 24,
207 8, 1, 9, 20, 21, 13, 22, 26,
208 11, 20, 10, 3, 24, 26, 23, 15,
209 20, 9, 2, 10, 26, 22, 14, 23,
210 12, 21, 26, 24, 4, 16, 25, 19,
211 21, 13, 22, 26, 16, 5, 17, 25,
212 24, 26, 23, 15, 19, 25, 18, 7,
213 26, 22, 14, 23, 25, 17, 6, 18 };
214
215 /* if there is no mesh we just return */
216 if (mesh_p==NULL) return;
217
218 nDim = mesh_p->Nodes->numDim;
219
220 if (nDim != 2 && nDim != 3) {
221 Finley_setError(TYPE_ERROR, "saveVTK: spatial dimension 2 or 3 is supported only.");
222 return;
223 }
224 my_mpi_rank = mesh_p->Nodes->MPIInfo->rank;
225 mpi_size = mesh_p->Nodes->MPIInfo->size;
226
227 /**********************************************************************************************
228 * open the file and check handle *
229 */
230 if (mpi_size > 1) {
231 #ifdef ESYS_MPI
232 const int amode = MPI_MODE_CREATE|MPI_MODE_WRONLY|MPI_MODE_UNIQUE_OPEN;
233 int ierr;
234 if (my_mpi_rank == 0 && Paso_fileExists(filename_p)) {
235 remove(filename_p);
236 }
237 ierr = MPI_File_open(mesh_p->Nodes->MPIInfo->comm, (char*)filename_p,
238 amode, mpi_info, &mpi_fileHandle_p);
239 if (ierr != MPI_SUCCESS) {
240 sprintf(errorMsg, "saveVTK: File %s could not be opened for writing in parallel.", filename_p);
241 Finley_setError(IO_ERROR, errorMsg);
242 } else {
243 ierr=MPI_File_set_view(mpi_fileHandle_p,MPI_DISPLACEMENT_CURRENT,
244 MPI_CHAR, MPI_CHAR, "native", mpi_info);
245 }
246 #endif /* ESYS_MPI */
247 } else {
248 fileHandle_p = fopen(filename_p, "w");
249 if (fileHandle_p==NULL) {
250 sprintf(errorMsg, "saveVTK: File %s could not be opened for writing.", filename_p);
251 Finley_setError(IO_ERROR, errorMsg);
252 }
253 }
254 if (!Esys_MPIInfo_noError(mesh_p->Nodes->MPIInfo)) return;
255
256 /* General note: From this point if an error occurs Finley_setError is
257 * called and subsequent steps are skipped until the end of this function
258 * where allocated memory is freed and the file is closed. */
259
260 /**********************************************************************************************/
261 /* find the mesh type to be written */
262
263 isCellCentered = TMPMEMALLOC(num_data, bool_t);
264 maxNameLen = 0;
265 if (!Finley_checkPtr(isCellCentered)) {
266 for (dataIdx=0; dataIdx<num_data; ++dataIdx) {
267 if (! isEmpty(data_pp[dataIdx])) {
268 switch(getFunctionSpaceType(data_pp[dataIdx]) ) {
269 case FINLEY_NODES:
270 nodeType = (nodeType == FINLEY_REDUCED_NODES) ? FINLEY_REDUCED_NODES : FINLEY_NODES;
271 isCellCentered[dataIdx] = FALSE;
272 if (elementType==FINLEY_UNKNOWN || elementType==FINLEY_ELEMENTS) {
273 elementType = FINLEY_ELEMENTS;
274 } else {
275 Finley_setError(TYPE_ERROR, "saveVTK: cannot write given data in single file.");
276 }
277 break;
278 case FINLEY_REDUCED_NODES:
279 nodeType = FINLEY_REDUCED_NODES;
280 isCellCentered[dataIdx] = FALSE;
281 if (elementType==FINLEY_UNKNOWN || elementType==FINLEY_ELEMENTS) {
282 elementType = FINLEY_ELEMENTS;
283 } else {
284 Finley_setError(TYPE_ERROR, "saveVTK: cannot write given data in single file.");
285 }
286 break;
287 case FINLEY_REDUCED_ELEMENTS:
288 hasReducedElements = TRUE;
289 case FINLEY_ELEMENTS:
290 isCellCentered[dataIdx] = TRUE;
291 if (elementType==FINLEY_UNKNOWN || elementType==FINLEY_ELEMENTS) {
292 elementType = FINLEY_ELEMENTS;
293 } else {
294 Finley_setError(TYPE_ERROR, "saveVTK: cannot write given data in single file.");
295 }
296 break;
297 case FINLEY_REDUCED_FACE_ELEMENTS:
298 hasReducedElements = TRUE;
299 case FINLEY_FACE_ELEMENTS:
300 isCellCentered[dataIdx] = TRUE;
301 if (elementType==FINLEY_UNKNOWN || elementType==FINLEY_FACE_ELEMENTS) {
302 elementType = FINLEY_FACE_ELEMENTS;
303 } else {
304 Finley_setError(TYPE_ERROR, "saveVTK: cannot write given data in single file.");
305 }
306 break;
307 case FINLEY_POINTS:
308 isCellCentered[dataIdx]=TRUE;
309 if (elementType==FINLEY_UNKNOWN || elementType==FINLEY_POINTS) {
310 elementType = FINLEY_POINTS;
311 } else {
312 Finley_setError(TYPE_ERROR, "saveVTK: cannot write given data in single file.");
313 }
314 break;
315 case FINLEY_REDUCED_CONTACT_ELEMENTS_1:
316 hasReducedElements = TRUE;
317 case FINLEY_CONTACT_ELEMENTS_1:
318 isCellCentered[dataIdx] = TRUE;
319 if (elementType==FINLEY_UNKNOWN || elementType==FINLEY_CONTACT_ELEMENTS_1) {
320 elementType = FINLEY_CONTACT_ELEMENTS_1;
321 } else {
322 Finley_setError(TYPE_ERROR, "saveVTK: cannot write given data in single file.");
323 }
324 break;
325 case FINLEY_REDUCED_CONTACT_ELEMENTS_2:
326 hasReducedElements = TRUE;
327 case FINLEY_CONTACT_ELEMENTS_2:
328 isCellCentered[dataIdx] = TRUE;
329 if (elementType==FINLEY_UNKNOWN || elementType==FINLEY_CONTACT_ELEMENTS_1) {
330 elementType = FINLEY_CONTACT_ELEMENTS_1;
331 } else {
332 Finley_setError(TYPE_ERROR, "saveVTK: cannot write given data in single file.");
333 }
334 break;
335 default:
336 sprintf(errorMsg, "saveVTK: unknown function space type %d",getFunctionSpaceType(data_pp[dataIdx]));
337 Finley_setError(TYPE_ERROR, errorMsg);
338 }
339 if (isCellCentered[dataIdx]) {
340 writeCellData = TRUE;
341 } else {
342 writePointData = TRUE;
343 }
344 maxNameLen = MAX(maxNameLen, strlen(names_p[dataIdx]));
345 }
346 }
347 }
348
349 /**********************************************************************************************/
350 /* select number of points and the mesh component */
351
352 if (Finley_noError()) {
353 if (nodeType == FINLEY_REDUCED_NODES) {
354 myFirstNode = Finley_NodeFile_getFirstReducedNode(mesh_p->Nodes);
355 myLastNode = Finley_NodeFile_getLastReducedNode(mesh_p->Nodes);
356 globalNumPoints = Finley_NodeFile_getGlobalNumReducedNodes(mesh_p->Nodes);
357 globalNodeIndex = Finley_NodeFile_borrowGlobalReducedNodesIndex(mesh_p->Nodes);
358 } else {
359 myFirstNode = Finley_NodeFile_getFirstNode(mesh_p->Nodes);
360 myLastNode = Finley_NodeFile_getLastNode(mesh_p->Nodes);
361 globalNumPoints = Finley_NodeFile_getGlobalNumNodes(mesh_p->Nodes);
362 globalNodeIndex = Finley_NodeFile_borrowGlobalNodesIndex(mesh_p->Nodes);
363 }
364 myNumPoints = myLastNode - myFirstNode;
365 if (elementType==FINLEY_UNKNOWN) elementType=FINLEY_ELEMENTS;
366 switch(elementType) {
367 case FINLEY_ELEMENTS:
368 elements = mesh_p->Elements;
369 break;
370 case FINLEY_FACE_ELEMENTS:
371 elements = mesh_p->FaceElements;
372 break;
373 case FINLEY_POINTS:
374 elements = mesh_p->Points;
375 break;
376 case FINLEY_CONTACT_ELEMENTS_1:
377 elements = mesh_p->ContactElements;
378 break;
379 }
380 if (elements==NULL) {
381 Finley_setError(SYSTEM_ERROR, "saveVTK: undefined element file");
382 } else {
383 /* map finley element type to VTK element type */
384 numCells = elements->numElements;
385 globalNumCells = Finley_ElementFile_getGlobalNumElements(elements);
386 myNumCells = Finley_ElementFile_getMyNumElements(elements);
387 myFirstCell = Finley_ElementFile_getFirstElement(elements);
388 NN = elements->numNodes;
389 if (hasReducedElements) {
390 quadNodes_p=elements->referenceElementSet->referenceElementReducedQuadrature->Parametrization->QuadNodes;
391 } else {
392 quadNodes_p=elements->referenceElementSet->referenceElement->Parametrization->QuadNodes;
393 }
394 if (nodeType==FINLEY_REDUCED_NODES) {
395 typeId = elements->referenceElementSet->referenceElement->LinearType->TypeId;
396 } else {
397 typeId = elements->referenceElementSet->referenceElement->Type->TypeId;
398 }
399 switch (typeId) {
400 case Finley_Point1:
401 case Finley_Line2Face:
402 case Finley_Line3Face:
403 case Finley_Point1_Contact:
404 case Finley_Line2Face_Contact:
405 case Finley_Line3Face_Contact:
406 cellType = VTK_VERTEX;
407 numVTKNodesPerElement = 1;
408 break;
409
410 case Finley_Line2:
411 case Finley_Tri3Face:
412 case Finley_Rec4Face:
413 case Finley_Line2_Contact:
414 case Finley_Tri3_Contact:
415 case Finley_Tri3Face_Contact:
416 case Finley_Rec4Face_Contact:
417 cellType = VTK_LINE;
418 numVTKNodesPerElement = 2;
419 break;
420
421 case Finley_Line3Macro:
422 cellType = VTK_LINE;
423 numCellFactor = 2;
424 numVTKNodesPerElement = 2;
425 break;
426
427 case Finley_Tri3:
428 case Finley_Tet4Face:
429 case Finley_Tet4Face_Contact:
430 cellType = VTK_TRIANGLE;
431 numVTKNodesPerElement = 3;
432 break;
433
434 case Finley_Rec4:
435 case Finley_Hex8Face:
436 case Finley_Rec4_Contact:
437 case Finley_Hex8Face_Contact:
438 cellType = VTK_QUAD;
439 numVTKNodesPerElement = 4;
440 break;
441
442 case Finley_Rec9Macro:
443 case Finley_Rec9:
444 numCellFactor = 4;
445 cellType = VTK_QUAD;
446 numVTKNodesPerElement = 4;
447 break;
448
449 case Finley_Tet4:
450 cellType = VTK_TETRA;
451 numVTKNodesPerElement = 4;
452 break;
453
454 case Finley_Hex8:
455 cellType = VTK_HEXAHEDRON;
456 numVTKNodesPerElement = 8;
457 break;
458
459 case Finley_Line3:
460 case Finley_Tri6Face:
461 case Finley_Rec8Face:
462 case Finley_Line3_Contact:
463 case Finley_Tri6Face_Contact:
464 case Finley_Rec8Face_Contact:
465 cellType = VTK_QUADRATIC_EDGE;
466 numVTKNodesPerElement = 3;
467 break;
468
469 case Finley_Tri6:
470 case Finley_Tri6Macro:
471 case Finley_Tet10Face:
472 case Finley_Tri6_Contact:
473 case Finley_Tet10Face_Contact:
474 cellType = VTK_QUADRATIC_TRIANGLE;
475 numVTKNodesPerElement = 6;
476 break;
477
478
479 case Finley_Rec8:
480 case Finley_Hex20Face:
481 case Finley_Rec8_Contact:
482 case Finley_Hex20Face_Contact:
483 cellType = VTK_QUADRATIC_QUAD;
484 numVTKNodesPerElement = 8;
485 break;
486
487 case Finley_Tet10Macro:
488 case Finley_Tet10:
489 cellType = VTK_QUADRATIC_TETRA;
490 numVTKNodesPerElement = 10;
491 break;
492
493 case Finley_Hex20:
494 cellType = VTK_QUADRATIC_HEXAHEDRON;
495 numVTKNodesPerElement = 20;
496 break;
497
498 case Finley_Hex27Macro:
499 case Finley_Hex27:
500 numCellFactor = 8;
501 cellType = VTK_HEXAHEDRON;
502 numVTKNodesPerElement = 8;
503 break;
504
505 default:
506 sprintf(errorMsg, "saveVTK: Element type %s is not supported by VTK.", elements->referenceElementSet->referenceElement->Type->Name);
507 Finley_setError(VALUE_ERROR, errorMsg);
508 }
509 }
510 }
511
512 /* allocate enough memory for text buffer */
513
514 txtBufferSize = strlen(vtkHeader) + 3*LEN_INT_FORMAT + (30+3*maxNameLen)+strlen(metadata)+strlen(metadata_schema);
515 if (mpi_size > 1) {
516 txtBufferSize = MAX(txtBufferSize, myNumPoints * LEN_TMP_BUFFER);
517 txtBufferSize = MAX(txtBufferSize, numCellFactor * myNumCells *
518 (LEN_INT_FORMAT * numVTKNodesPerElement + 1));
519 txtBufferSize = MAX(txtBufferSize,
520 numCellFactor * myNumCells * LEN_TENSOR_FORMAT);
521 txtBufferSize = MAX(txtBufferSize, myNumPoints * LEN_TENSOR_FORMAT);
522 }
523 txtBuffer = TMPMEMALLOC(txtBufferSize+1, char);
524
525 /* sets error if memory allocation failed */
526 Finley_checkPtr(txtBuffer);
527
528 /**********************************************************************************************/
529 /* write number of points and the mesh component */
530
531 if (Finley_noError()) {
532 const index_t *nodeIndex;
533 if (FINLEY_REDUCED_NODES == nodeType) {
534 nodeIndex = elements->referenceElementSet->referenceElement->Type->linearNodes;
535 } else if (Finley_Line3Macro == typeId) {
536 nodeIndex = VTK_LINE3_INDEX;
537 } else if ( (Finley_Rec9 == typeId) || (Finley_Rec9Macro == typeId) ) {
538 nodeIndex = VTK_REC9_INDEX;
539 } else if (Finley_Hex20 == typeId) {
540 nodeIndex = VTK_HEX20_INDEX;
541 } else if ( (Finley_Hex27 == typeId) || (Finley_Hex27Macro == typeId) ){
542 nodeIndex = VTK_HEX27_INDEX;
543 } else if (numVTKNodesPerElement != elements->referenceElementSet->referenceElement->Type->numNodes) {
544 nodeIndex = elements->referenceElementSet->referenceElement->Type->relevantGeoNodes;
545 } else {
546 nodeIndex = NULL;
547 }
548
549 if (strlen(metadata)>0) {
550 if (strlen(metadata_schema)>0) {
551 sprintf(txtBuffer, vtkHeader," ",metadata_schema,metadata,"\n",globalNumPoints, numCellFactor*globalNumCells, 3);
552 } else {
553 sprintf(txtBuffer, vtkHeader,"","",metadata,"\n",globalNumPoints, numCellFactor*globalNumCells, 3);
554 }
555 } else {
556 if (strlen(metadata_schema)>0) {
557 sprintf(txtBuffer, vtkHeader," ",metadata_schema,"","",globalNumPoints, numCellFactor*globalNumCells, 3);
558 } else {
559 sprintf(txtBuffer, vtkHeader,"","","","",globalNumPoints, numCellFactor*globalNumCells, 3);
560 }
561 }
562
563 if (mpi_size > 1) {
564 /* write the nodes */
565 MPI_RANK0_WRITE_SHARED(txtBuffer);
566 txtBuffer[0] = '\0';
567 txtBufferInUse = 0;
568 if (nDim==2) {
569 for (i = 0; i < mesh_p->Nodes->numNodes; i++) {
570 if ( (myFirstNode <= globalNodeIndex[i]) && (globalNodeIndex[i] < myLastNode) ) {
571 sprintf(tmpBuffer, VECTOR_FORMAT,
572 mesh_p->Nodes->Coordinates[INDEX2(0, i, nDim)],
573 mesh_p->Nodes->Coordinates[INDEX2(1, i, nDim)],
574 0.);
575 __STRCAT(txtBuffer, tmpBuffer, txtBufferInUse);
576 }
577 }
578 } else {
579 for (i = 0; i < mesh_p->Nodes->numNodes; i++) {
580 if ( (myFirstNode <= globalNodeIndex[i]) && (globalNodeIndex[i] < myLastNode) ) {
581 sprintf(tmpBuffer, VECTOR_FORMAT,
582 mesh_p->Nodes->Coordinates[INDEX2(0, i, nDim)],
583 mesh_p->Nodes->Coordinates[INDEX2(1, i, nDim)],
584 mesh_p->Nodes->Coordinates[INDEX2(2, i, nDim)]);
585 __STRCAT(txtBuffer, tmpBuffer, txtBufferInUse);
586 }
587 }
588 } /* nDim */
589 MPI_WRITE_ORDERED(txtBuffer);
590
591 /* write the cells */
592 MPI_RANK0_WRITE_SHARED(tags_End_Points_and_Start_Conn);
593 txtBuffer[0] = '\0';
594 txtBufferInUse = 0;
595 if (nodeIndex == NULL) {
596 for (i = 0; i < numCells; i++) {
597 if (elements->Owner[i] == my_mpi_rank) {
598 for (j = 0; j < numVTKNodesPerElement; j++) {
599 sprintf(tmpBuffer, INT_FORMAT, globalNodeIndex[elements->Nodes[INDEX2(j, i, NN)]]);
600 __STRCAT(txtBuffer, tmpBuffer, txtBufferInUse);
601 }
602 __STRCAT(txtBuffer, NEWLINE, txtBufferInUse);
603 }
604 }
605 } else {
606 for (i = 0; i < numCells; i++) {
607 if (elements->Owner[i] == my_mpi_rank) {
608 for (l = 0; l < numCellFactor; l++) {
609 const int* idx=&nodeIndex[l*numVTKNodesPerElement];
610 for (j = 0; j < numVTKNodesPerElement; j++) {
611 sprintf(tmpBuffer, INT_FORMAT, globalNodeIndex[elements->Nodes[INDEX2(idx[j], i, NN)]]);
612 __STRCAT(txtBuffer, tmpBuffer, txtBufferInUse);
613 }
614 __STRCAT(txtBuffer, NEWLINE, txtBufferInUse);
615 }
616 }
617 }
618 } /* nodeIndex */
619 MPI_WRITE_ORDERED(txtBuffer);
620
621 /* write the offsets */
622 MPI_RANK0_WRITE_SHARED(tags_End_Conn_and_Start_Offset);
623 txtBuffer[0] = '\0';
624 txtBufferInUse = 0;
625 for (i = numVTKNodesPerElement*(myFirstCell*numCellFactor+1);
626 i <= (myFirstCell+myNumCells)*numVTKNodesPerElement*numCellFactor; i += numVTKNodesPerElement)
627 {
628 sprintf(tmpBuffer, INT_NEWLINE_FORMAT, i);
629 __STRCAT(txtBuffer, tmpBuffer, txtBufferInUse);
630 }
631 MPI_WRITE_ORDERED(txtBuffer);
632
633 /* write element type */
634 sprintf(tmpBuffer, INT_NEWLINE_FORMAT, cellType);
635 MPI_RANK0_WRITE_SHARED(tags_End_Offset_and_Start_Type);
636 txtBuffer[0] = '\0';
637 txtBufferInUse = 0;
638 for (i = numVTKNodesPerElement*(myFirstCell*numCellFactor+1);
639 i <= (myFirstCell+myNumCells)*numVTKNodesPerElement*numCellFactor; i += numVTKNodesPerElement)
640 {
641 __STRCAT(txtBuffer, tmpBuffer, txtBufferInUse);
642 }
643 MPI_WRITE_ORDERED(txtBuffer);
644 /* finalize cell information */
645 strcpy(txtBuffer, "</DataArray>\n</Cells>\n");
646 MPI_RANK0_WRITE_SHARED(txtBuffer);
647
648 } else { /***** mpi_size == 1 *****/
649
650 /* write the nodes */
651 fputs(txtBuffer, fileHandle_p);
652 if (nDim==2) {
653 for (i = 0; i < mesh_p->Nodes->numNodes; i++) {
654 if ( (myFirstNode <= globalNodeIndex[i]) && (globalNodeIndex[i] < myLastNode) ) {
655 fprintf(fileHandle_p, VECTOR_FORMAT,
656 mesh_p->Nodes->Coordinates[INDEX2(0, i, nDim)],
657 mesh_p->Nodes->Coordinates[INDEX2(1, i, nDim)],
658 0.);
659 }
660 }
661 } else {
662 for (i = 0; i < mesh_p->Nodes->numNodes; i++) {
663 if ( (myFirstNode <= globalNodeIndex[i]) && (globalNodeIndex[i] < myLastNode) ) {
664 fprintf(fileHandle_p, VECTOR_FORMAT,
665 mesh_p->Nodes->Coordinates[INDEX2(0, i, nDim)],
666 mesh_p->Nodes->Coordinates[INDEX2(1, i, nDim)],
667 mesh_p->Nodes->Coordinates[INDEX2(2, i, nDim)]);
668 }
669 }
670 } /* nDim */
671
672 /* write the cells */
673 fputs(tags_End_Points_and_Start_Conn, fileHandle_p);
674 if (nodeIndex == NULL) {
675 for (i = 0; i < numCells; i++) {
676 for (j = 0; j < numVTKNodesPerElement; j++) {
677 fprintf(fileHandle_p, INT_FORMAT, globalNodeIndex[elements->Nodes[INDEX2(j, i, NN)]]);
678 }
679 fprintf(fileHandle_p, NEWLINE);
680 }
681 } else {
682 for (i = 0; i < numCells; i++) {
683 for (l = 0; l < numCellFactor; l++) {
684 const int* idx=&nodeIndex[l*numVTKNodesPerElement];
685 for (j = 0; j < numVTKNodesPerElement; j++) {
686 fprintf(fileHandle_p, INT_FORMAT, globalNodeIndex[elements->Nodes[INDEX2(idx[j], i, NN)]]);
687 }
688 fprintf(fileHandle_p, NEWLINE);
689 }
690 }
691 } /* nodeIndex */
692
693 /* write the offsets */
694 fputs(tags_End_Conn_and_Start_Offset, fileHandle_p);
695 for (i = numVTKNodesPerElement; i <= numCells*numVTKNodesPerElement*numCellFactor; i += numVTKNodesPerElement) {
696 fprintf(fileHandle_p, INT_NEWLINE_FORMAT, i);
697 }
698
699 /* write element type */
700 sprintf(tmpBuffer, INT_NEWLINE_FORMAT, cellType);
701 fputs(tags_End_Offset_and_Start_Type, fileHandle_p);
702 for (i = 0; i < numCells*numCellFactor; i++)
703 fputs(tmpBuffer, fileHandle_p);
704 /* finalize cell information */
705 fputs("</DataArray>\n</Cells>\n", fileHandle_p);
706 } /* mpi_size */
707
708 } /* Finley_noError */
709
710 /**********************************************************************************************/
711 /* write cell data */
712
713 if (writeCellData && Finley_noError()) {
714 bool_t set_scalar=FALSE, set_vector=FALSE, set_tensor=FALSE;
715 /* mark the active data arrays */
716 strcpy(txtBuffer, "<CellData");
717 for (dataIdx = 0; dataIdx < num_data; dataIdx++) {
718 if (!isEmpty(data_pp[dataIdx]) && isCellCentered[dataIdx]) {
719 /* rank == 0 <--> scalar data */
720 /* rank == 1 <--> vector data */
721 /* rank == 2 <--> tensor data */
722 switch (getDataPointRank(data_pp[dataIdx])) {
723 case 0:
724 if (!set_scalar) {
725 strcat(txtBuffer, " Scalars=\"");
726 strcat(txtBuffer, names_p[dataIdx]);
727 strcat(txtBuffer, "\"");
728 set_scalar = TRUE;
729 }
730 break;
731 case 1:
732 if (!set_vector) {
733 strcat(txtBuffer, " Vectors=\"");
734 strcat(txtBuffer, names_p[dataIdx]);
735 strcat(txtBuffer, "\"");
736 set_vector = TRUE;
737 }
738 break;
739 case 2:
740 if (!set_tensor) {
741 strcat(txtBuffer, " Tensors=\"");
742 strcat(txtBuffer, names_p[dataIdx]);
743 strcat(txtBuffer, "\"");
744 set_tensor = TRUE;
745 }
746 break;
747 default:
748 sprintf(errorMsg, "saveVTK: data %s: VTK supports data with rank <= 2 only.", names_p[dataIdx]);
749 Finley_setError(VALUE_ERROR, errorMsg);
750 }
751 }
752 if (!Finley_noError())
753 break;
754 }
755 }
756 /* only continue if no error occurred */
757 if (writeCellData && Finley_noError()) {
758 strcat(txtBuffer, ">\n");
759 if ( mpi_size > 1) {
760 MPI_RANK0_WRITE_SHARED(txtBuffer);
761 } else {
762 fputs(txtBuffer, fileHandle_p);
763 }
764
765 /* write the arrays */
766 for (dataIdx = 0; dataIdx < num_data; dataIdx++) {
767 if (!isEmpty(data_pp[dataIdx]) && isCellCentered[dataIdx]) {
768 dim_t numPointsPerSample=getNumDataPointsPerSample(data_pp[dataIdx]);
769 dim_t rank = getDataPointRank(data_pp[dataIdx]);
770 dim_t nComp = getDataPointSize(data_pp[dataIdx]);
771 dim_t nCompReqd = 1; /* number of components mpi_required */
772 if (rank == 0) {
773 nCompReqd = 1;
774 shape = 0;
775 } else if (rank == 1) {
776 nCompReqd = 3;
777 shape = getDataPointShape(data_pp[dataIdx], 0);
778 if (shape > 3) {
779 Finley_setError(VALUE_ERROR, "saveVTK: rank 1 objects must have 3 components at most.");
780 }
781 } else {
782 nCompReqd = 9;
783 shape = getDataPointShape(data_pp[dataIdx], 0);
784 if (shape > 3 || shape != getDataPointShape(data_pp[dataIdx], 1)) {
785 Finley_setError(VALUE_ERROR, "saveVTK: rank 2 objects of shape 2x2 or 3x3 supported only.");
786 }
787 }
788 /* bail out if an error occurred */
789 if (!Finley_noError())
790 break;
791
792 sprintf(txtBuffer, tag_Float_DataArray, names_p[dataIdx], nCompReqd);
793 if ( mpi_size > 1) {
794 MPI_RANK0_WRITE_SHARED(txtBuffer);
795 } else {
796 fputs(txtBuffer, fileHandle_p);
797 }
798
799 txtBuffer[0] = '\0';
800 txtBufferInUse = 0;
801 for (i=0; i<numCells; i++) {
802 if (elements->Owner[i] == my_mpi_rank) {
803 __const double *values = getSampleDataRO(data_pp[dataIdx], i);
804 for (l = 0; l < numCellFactor; l++) {
805 double sampleAvg[NCOMP_MAX];
806 dim_t nCompUsed = MIN(nComp, NCOMP_MAX);
807
808 /* average over number of points in the sample */
809 if (isExpanded(data_pp[dataIdx])) {
810 dim_t hits=0;
811 for (k=0; k<nCompUsed; k++) sampleAvg[k]=0;
812 for (j=0; j<numPointsPerSample; j++) {
813 if (nodeInQuadrant(quadNodes_p, typeId, j, l)) {
814 hits++;
815 for (k=0; k<nCompUsed; k++) {
816 sampleAvg[k] += values[INDEX2(k,j,nComp)];
817 }
818 }
819 }
820 for (k=0; k<nCompUsed; k++)
821 sampleAvg[k] /= MAX(hits, 1);
822 } else {
823 for (k=0; k<nCompUsed; k++)
824 sampleAvg[k] = values[k];
825 } /* isExpanded */
826
827 /* if the number of required components is more than
828 * the number of actual components, pad with zeros
829 */
830 /* probably only need to get shape of first element */
831 if (nCompReqd == 1) {
832 sprintf(tmpBuffer, SCALAR_FORMAT, sampleAvg[0]);
833 } else if (nCompReqd == 3) {
834 if (shape==1) {
835 sprintf(tmpBuffer, VECTOR_FORMAT,
836 sampleAvg[0], 0.f, 0.f);
837 } else if (shape==2) {
838 sprintf(tmpBuffer, VECTOR_FORMAT,
839 sampleAvg[0], sampleAvg[1], 0.f);
840 } else if (shape==3) {
841 sprintf(tmpBuffer, VECTOR_FORMAT,
842 sampleAvg[0],sampleAvg[1],sampleAvg[2]);
843 }
844 } else if (nCompReqd == 9) {
845 if (shape==1) {
846 sprintf(tmpBuffer, TENSOR_FORMAT,
847 sampleAvg[0], 0.f, 0.f,
848 0.f, 0.f, 0.f,
849 0.f, 0.f, 0.f);
850 } else if (shape==2) {
851 sprintf(tmpBuffer, TENSOR_FORMAT,
852 sampleAvg[0], sampleAvg[1], 0.f,
853 sampleAvg[2], sampleAvg[3], 0.f,
854 0.f, 0.f, 0.f);
855 } else if (shape==3) {
856 sprintf(tmpBuffer, TENSOR_FORMAT,
857 sampleAvg[0],sampleAvg[1],sampleAvg[2],
858 sampleAvg[3],sampleAvg[4],sampleAvg[5],
859 sampleAvg[6],sampleAvg[7],sampleAvg[8]);
860 }
861 }
862 if ( mpi_size > 1) {
863 __STRCAT(txtBuffer, tmpBuffer, txtBufferInUse);
864 } else {
865 fputs(tmpBuffer, fileHandle_p);
866 }
867 } /* for l (numCellFactor) */
868 } /* if I am the owner */
869 } /* for i (numCells) */
870
871 if ( mpi_size > 1) {
872 MPI_WRITE_ORDERED(txtBuffer);
873 MPI_RANK0_WRITE_SHARED(tag_End_DataArray);
874 } else {
875 fputs(tag_End_DataArray, fileHandle_p);
876 }
877 } /* !isEmpty && cellCentered */
878 } /* for dataIdx */
879
880 strcpy(txtBuffer, "</CellData>\n");
881 if ( mpi_size > 1) {
882 MPI_RANK0_WRITE_SHARED(txtBuffer);
883 } else {
884 fputs(txtBuffer, fileHandle_p);
885 }
886 } /* if noError && writeCellData */
887
888 /**********************************************************************************************/
889 /* write point data */
890
891 if (writePointData && Finley_noError()) {
892 /* mark the active data arrays */
893 bool_t set_scalar=FALSE, set_vector=FALSE, set_tensor=FALSE;
894 strcpy(txtBuffer, "<PointData");
895 for (dataIdx = 0; dataIdx<num_data; dataIdx++) {
896 if (!isEmpty(data_pp[dataIdx]) && !isCellCentered[dataIdx]) {
897 switch (getDataPointRank(data_pp[dataIdx])) {
898 case 0:
899 if (!set_scalar) {
900 strcat(txtBuffer, " Scalars=\"");
901 strcat(txtBuffer, names_p[dataIdx]);
902 strcat(txtBuffer, "\"");
903 set_scalar = TRUE;
904 }
905 break;
906 case 1:
907 if (!set_vector) {
908 strcat(txtBuffer, " Vectors=\"");
909 strcat(txtBuffer, names_p[dataIdx]);
910 strcat(txtBuffer, "\"");
911 set_vector = TRUE;
912 }
913 break;
914 case 2:
915 if (!set_tensor) {
916 strcat(txtBuffer, " Tensors=\"");
917 strcat(txtBuffer, names_p[dataIdx]);
918 strcat(txtBuffer, "\"");
919 set_tensor = TRUE;
920 }
921 break;
922 default:
923 sprintf(errorMsg, "saveVTK: data %s: VTK supports data with rank <= 2 only.", names_p[dataIdx]);
924 Finley_setError(VALUE_ERROR, errorMsg);
925 }
926 }
927 if (!Finley_noError())
928 break;
929 }
930 }
931 /* only continue if no error occurred */
932 if (writePointData && Finley_noError()) {
933 strcat(txtBuffer, ">\n");
934 if ( mpi_size > 1) {
935 MPI_RANK0_WRITE_SHARED(txtBuffer);
936 } else {
937 fputs(txtBuffer, fileHandle_p);
938 }
939
940 /* write the arrays */
941 for (dataIdx = 0; dataIdx < num_data; dataIdx++) {
942 if (!isEmpty(data_pp[dataIdx]) && !isCellCentered[dataIdx]) {
943 Finley_NodeMapping* nodeMapping;
944 dim_t rank = getDataPointRank(data_pp[dataIdx]);
945 dim_t nCompReqd = 1; /* number of components mpi_required */
946 if (getFunctionSpaceType(data_pp[dataIdx]) == FINLEY_REDUCED_NODES) {
947 nodeMapping = mesh_p->Nodes->reducedNodesMapping;
948 } else {
949 nodeMapping = mesh_p->Nodes->nodesMapping;
950 }
951 if (rank == 0) {
952 nCompReqd = 1;
953 shape = 0;
954 } else if (rank == 1) {
955 nCompReqd = 3;
956 shape = getDataPointShape(data_pp[dataIdx], 0);
957 if (shape > 3) {
958 Finley_setError(VALUE_ERROR, "saveVTK: rank 1 objects must have 3 components at most.");
959 }
960 } else {
961 nCompReqd = 9;
962 shape=getDataPointShape(data_pp[dataIdx], 0);
963 if (shape > 3 || shape != getDataPointShape(data_pp[dataIdx], 1)) {
964 Finley_setError(VALUE_ERROR, "saveVTK: rank 2 objects of shape 2x2 or 3x3 supported only.");
965 }
966 }
967 /* bail out if an error occurred */
968 if (!Finley_noError())
969 break;
970
971 sprintf(txtBuffer, tag_Float_DataArray, names_p[dataIdx], nCompReqd);
972 if ( mpi_size > 1) {
973 MPI_RANK0_WRITE_SHARED(txtBuffer);
974 } else {
975 fputs(txtBuffer, fileHandle_p);
976 }
977
978 txtBuffer[0] = '\0';
979 txtBufferInUse = 0;
980 for (i=0; i<mesh_p->Nodes->numNodes; i++) {
981 k = globalNodeIndex[i];
982 if ( (myFirstNode <= k) && (k < myLastNode) ) {
983 __const double *values = getSampleDataRO(data_pp[dataIdx], nodeMapping->target[i]);
984 /* if the number of mpi_required components is more than
985 * the number of actual components, pad with zeros.
986 * Probably only need to get shape of first element */
987 if (nCompReqd == 1) {
988 sprintf(tmpBuffer, SCALAR_FORMAT, values[0]);
989 } else if (nCompReqd == 3) {
990 if (shape==1) {
991 sprintf(tmpBuffer, VECTOR_FORMAT,
992 values[0], 0.f, 0.f);
993 } else if (shape==2) {
994 sprintf(tmpBuffer, VECTOR_FORMAT,
995 values[0], values[1], 0.f);
996 } else if (shape==3) {
997 sprintf(tmpBuffer, VECTOR_FORMAT,
998 values[0], values[1], values[2]);
999 }
1000 } else if (nCompReqd == 9) {
1001 if (shape==1) {
1002 sprintf(tmpBuffer, TENSOR_FORMAT,
1003 values[0], 0.f, 0.f,
1004 0.f, 0.f, 0.f,
1005 0.f, 0.f, 0.f);
1006 } else if (shape==2) {
1007 sprintf(tmpBuffer, TENSOR_FORMAT,
1008 values[0], values[1], 0.f,
1009 values[2], values[3], 0.f,
1010 0.f, 0.f, 0.f);
1011 } else if (shape==3) {
1012 sprintf(tmpBuffer, TENSOR_FORMAT,
1013 values[0], values[1], values[2],
1014 values[3], values[4], values[5],
1015 values[6], values[7], values[8]);
1016 }
1017 }
1018 if ( mpi_size > 1) {
1019 __STRCAT(txtBuffer, tmpBuffer, txtBufferInUse);
1020 } else {
1021 fputs(tmpBuffer, fileHandle_p);
1022 }
1023 } /* if this is my node */
1024 } /* for i (numNodes) */
1025
1026 if ( mpi_size > 1) {
1027 MPI_WRITE_ORDERED(txtBuffer);
1028 MPI_RANK0_WRITE_SHARED(tag_End_DataArray);
1029 } else {
1030 fputs(tag_End_DataArray, fileHandle_p);
1031 }
1032 } /* !isEmpty && !isCellCentered */
1033 } /* for dataIdx */
1034
1035 strcpy(txtBuffer, "</PointData>\n");
1036 if ( mpi_size > 1) {
1037 MPI_RANK0_WRITE_SHARED(txtBuffer);
1038 } else {
1039 fputs(txtBuffer, fileHandle_p);
1040 }
1041 } /* if noError && writePointData */
1042
1043 /* Final write to VTK file */
1044 if (Finley_noError()) {
1045 if (mpi_size > 1) {
1046 MPI_RANK0_WRITE_SHARED(vtkFooter);
1047 } else {
1048 fputs(vtkFooter, fileHandle_p);
1049 }
1050 }
1051
1052 if ( mpi_size > 1) {
1053 #ifdef ESYS_MPI
1054 MPI_File_close(&mpi_fileHandle_p);
1055 MPI_Barrier(mesh_p->Nodes->MPIInfo->comm);
1056 #endif
1057 } else {
1058 fclose(fileHandle_p);
1059 }
1060 TMPMEMFREE(isCellCentered);
1061 TMPMEMFREE(txtBuffer);
1062 }
1063

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.26