/* * Copyright (C) NHR@FAU, University Erlangen-Nuremberg. * All rights reserved. This file is part of nusif-solver. * Use of this source code is governed by a MIT style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "allocate.h" #include "comm.h" #include "vtkWriter.h" // reset fileview for output of string headers static void resetFileview(VtkOptions* o) { MPI_Offset disp; MPI_File_sync(o->fh); MPI_Barrier(o->comm.comm); MPI_File_get_size(o->fh, &disp); MPI_File_set_view(o->fh, disp, MPI_CHAR, MPI_CHAR, "native", MPI_INFO_NULL); } static void writeVersion(VtkOptions* o) { char header[50] = "# vtk DataFile Version 3.0\n"; // always overwrite exiting files MPI_File_set_view(o->fh, 0, MPI_CHAR, MPI_CHAR, "native", MPI_INFO_NULL); if (commIsMaster(&o->comm)) { MPI_File_write(o->fh, header, (int)strlen(header), MPI_CHAR, MPI_STATUS_IGNORE); } } static void writeHeader(VtkOptions* o) { char header[400]; char* cursor = header; cursor += sprintf(cursor, "PAMPI cfd solver output\n"); cursor += sprintf(cursor, "BINARY\n"); cursor += sprintf(cursor, "DATASET STRUCTURED_POINTS\n"); cursor += sprintf(cursor, "DIMENSIONS %d %d %d\n", o->grid->imax, o->grid->jmax, o->grid->kmax); cursor += sprintf(cursor, "ORIGIN %f %f %f\n", o->grid->dx * 0.5, o->grid->dy * 0.5, o->grid->dz * 0.5); cursor += sprintf(cursor, "SPACING %f %f %f\n", o->grid->dx, o->grid->dy, o->grid->dz); cursor += sprintf(cursor, "POINT_DATA %d\n", o->grid->imax * o->grid->jmax * o->grid->kmax); if (commIsMaster(&o->comm)) { MPI_File_write(o->fh, header, (int)strlen(header), MPI_CHAR, MPI_STATUS_IGNORE); } } void vtkOpen(VtkOptions* o, char* problem) { char filename[50]; snprintf(filename, 50, "%s-p%d.vtk", problem, o->comm.size); MPI_File_open(o->comm.comm, filename, MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &o->fh); if (commIsMaster(&o->comm)) { printf("Writing VTK output for %s\n", problem); } writeVersion(o); writeHeader(o); } void vtkScalar(VtkOptions* o, char* name, double* s) { resetFileview(o); if (commIsMaster(&o->comm)) printf("Register scalar %s\n", name); char header[100]; char* cursor = header; cursor += sprintf(cursor, "SCALARS %s double\n", name); if (commIsMaster(&o->comm)) { MPI_File_write(o->fh, header, (int)strlen(header), MPI_CHAR, MPI_STATUS_IGNORE); } int offsets[NDIMS]; commGetOffsets(&o->comm, offsets, o->grid->kmax, o->grid->jmax, o->grid->imax); // set global view in file MPI_Offset disp; MPI_Datatype fileViewType; MPI_File_sync(o->fh); MPI_Barrier(o->comm.comm); MPI_File_get_size(o->fh, &disp); MPI_Type_create_subarray(NDIMS, (int[NDIMS]) { o->grid->kmax, o->grid->jmax, o->grid->imax }, (int[NDIMS]) { o->comm.kmaxLocal, o->comm.jmaxLocal, o->comm.imaxLocal }, offsets, MPI_ORDER_C, MPI_DOUBLE, &fileViewType); MPI_Type_commit(&fileViewType); MPI_File_set_view(o->fh, disp, MPI_DOUBLE, fileViewType, "external32", MPI_INFO_NULL); #ifdef VERBOSE printf("Rank: %d, Disp: %lld, Size(k,j,i): %d %d %d, Offset(k,j,i): %d %d %d\n", o->comm.rank, disp, o->comm.kmaxLocal, o->comm.jmaxLocal, o->comm.imaxLocal, offsets[KDIM], offsets[JDIM], offsets[IDIM]); #endif // create local bulk type MPI_Datatype bulkType; MPI_Type_create_subarray(NDIMS, (int[NDIMS]) { o->comm.kmaxLocal + 2, o->comm.jmaxLocal + 2, o->comm.imaxLocal + 2 }, // oldsizes (int[NDIMS]) { o->comm.kmaxLocal, o->comm.jmaxLocal, o->comm.imaxLocal }, // newsizes (int[NDIMS]) { 1, 1, 1 }, // offsets MPI_ORDER_C, MPI_DOUBLE, &bulkType); MPI_Type_commit(&bulkType); MPI_File_write(o->fh, s, 1, bulkType, MPI_STATUS_IGNORE); MPI_Type_free(&bulkType); MPI_Type_free(&fileViewType); // Binary segment must be terminated with newline character resetFileview(o); if (commIsMaster(&o->comm)) { MPI_File_write(o->fh, "\n", 1, MPI_CHAR, MPI_STATUS_IGNORE); } } #define G(v, i, j, k) \ v[(k) * (imaxLocal + 2) * (jmaxLocal + 2) + (j) * (imaxLocal + 2) + (i)] void vtkVector(VtkOptions* o, char* name, VtkVector vec) { int imaxLocal = o->comm.imaxLocal; int jmaxLocal = o->comm.jmaxLocal; int kmaxLocal = o->comm.kmaxLocal; if (commIsMaster(&o->comm)) printf("Register vector %s\n", name); const size_t MAX_HEADER = 100; char* header = (char*)malloc(MAX_HEADER); sprintf(header, "VECTORS %s double\n", name); resetFileview(o); if (commIsMaster(&o->comm)) { MPI_File_write(o->fh, header, (int)strlen(header), MPI_CHAR, MPI_STATUS_IGNORE); } int offsets[NDIMS]; commGetOffsets(&o->comm, offsets, o->grid->kmax, o->grid->jmax, o->grid->imax); // set global view in file MPI_Offset disp; MPI_Datatype fileViewType, vectorType; MPI_File_sync(o->fh); MPI_Barrier(o->comm.comm); MPI_File_get_size(o->fh, &disp); MPI_Type_contiguous(NDIMS, MPI_DOUBLE, &vectorType); MPI_Type_commit(&vectorType); MPI_Type_create_subarray(NDIMS, (int[NDIMS]) { o->grid->kmax, o->grid->jmax, o->grid->imax }, (int[NDIMS]) { kmaxLocal, jmaxLocal, imaxLocal }, offsets, MPI_ORDER_C, vectorType, &fileViewType); MPI_Type_commit(&fileViewType); MPI_File_set_view(o->fh, disp, MPI_DOUBLE, fileViewType, "external32", MPI_INFO_NULL); size_t cnt = imaxLocal * jmaxLocal * kmaxLocal; double* tmp = allocate(64, cnt * NDIMS * sizeof(double)); int idx = 0; for (int k = 1; k < kmaxLocal + 1; k++) { for (int j = 1; j < jmaxLocal + 1; j++) { for (int i = 1; i < imaxLocal + 1; i++) { tmp[idx++] = (G(vec.u, i, j, k) + G(vec.u, i - 1, j, k)) / 2.0; tmp[idx++] = (G(vec.v, i, j, k) + G(vec.v, i, j - 1, k)) / 2.0; tmp[idx++] = (G(vec.w, i, j, k) + G(vec.w, i, j, k - 1)) / 2.0; } } } if (commIsMaster(&o->comm)) printf("Write %d vectors\n", (int)cnt); MPI_File_write(o->fh, tmp, cnt, vectorType, MPI_STATUS_IGNORE); MPI_Type_free(&fileViewType); MPI_Type_free(&vectorType); // Binary segment must be terminated with newline character resetFileview(o); if (commIsMaster(&o->comm)) { MPI_File_write(o->fh, "\n", 1, MPI_CHAR, MPI_STATUS_IGNORE); } } void vtkClose(VtkOptions* o) { MPI_File_close(&o->fh); }