SDDSlib
Loading...
Searching...
No Matches
SDDSmpi_output.c
Go to the documentation of this file.
1/**
2 * @file SDDSmpi_output.c
3 * @brief MPI-based Parallel I/O Functions for SDDS Datasets
4 *
5 * This file implements a suite of functions to facilitate parallel input/output operations
6 * for SDDS (Self Describing Data Set) datasets using MPI (Message Passing Interface).
7 * It includes functionalities for initializing MPI output, writing dataset layouts and
8 * data pages, handling errors, terminating datasets, and managing MPI file connections.
9 *
10 * @copyright
11 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
12 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
13 *
14 * @license
15 * This file is distributed under the terms of the Software License Agreement
16 * found in the file LICENSE included with this distribution.
17 *
18 * @authors
19 * H. Shang
20 * M. Borland
21 * R. Soliday
22 */
23
24#include "SDDS.h"
25#include "stdio.h"
26
27int32_t SDDS_mpi_error_str_len;
28char SDDS_mpi_error_str[MPI_MAX_ERROR_STRING];
29/*external32 data is written in "big-endian IEEE", use it as default */
30char *SDDS_MPI_FILE_TYPE[2] = {"external32", "native"};
31
32static int32_t terminateMode = 0;
33
34#if MPI_DEBUG
35/**
36 * @brief Opens a debug file for the given SDDS dataset.
37 *
38 * This function checks if the debug file pointer is `NULL`. If it is, it constructs a filename using the dataset's filename and MPI process ID, opens the file for writing, and writes an initial log message indicating that logging has started.
39 *
40 * @param sdds Pointer to the `SDDS_DATASET` structure.
41 */
42void openDebugFile(SDDS_DATASET *sdds) {
43 if (sdds->MPI_dataset->fpdeb == NULL) {
44 char s[1024];
45 sprintf(s, "%s.%04d", sdds->layout.filename, sdds->MPI_dataset->myid);
46 sdds->MPI_dataset->fpdeb = fopen(s, "w");
47 fprintf(sdds->MPI_dataset->fpdeb, "Started log for file %s, core %d\n", sdds->layout.filename, sdds->MPI_dataset->myid);
48 }
49}
50
51/**
52 * @brief Logs a debug message to the dataset's debug file.
53 *
54 * If the `MPI_dataset` exists, the function ensures that the debug file is open by calling `openDebugFile` if necessary. Then, it writes the provided string to the debug file.
55 *
56 * @param string The debug message to log.
57 * @param sdds Pointer to the `SDDS_DATASET` structure.
58 */
59void logDebug(char *string, SDDS_DATASET *sdds) {
60 if (sdds->MPI_dataset) {
61 if (!sdds->MPI_dataset->fpdeb)
62 openDebugFile(sdds);
63 if (sdds->MPI_dataset->fpdeb)
64 fprintf(sdds->MPI_dataset->fpdeb, "%s\n", string);
65 }
66}
67#endif
68
69/**
70 * @brief Converts a blank string to `NULL`.
71 *
72 * This function checks if the input string is `NULL` or consists only of whitespace characters. If so, it returns `NULL`; otherwise, it returns the original string.
73 *
74 * @param string The input string to check.
75 * @return `NULL` if the string is `NULL` or blank, otherwise returns the original string.
76 */
77char *BlankToNull(char *string) {
78 if (!string || SDDS_StringIsBlank(string))
79 return NULL;
80 return string;
81}
82
83/**
84 * @brief Handles MPI errors by printing an error message and optionally exiting.
85 *
86 * Retrieves the MPI error string corresponding to the given error code. If a string is provided, it prints the string followed by the MPI error message to the specified file pointer. If `exit_code` is non-zero, the program exits with a status of 1.
87 *
88 * @param fp File pointer to write the error message to.
89 * @param str Custom error message to prefix to the MPI error string. Can be `NULL`.
90 * @param mpierr The MPI error code.
91 * @param exit_code If non-zero, the function will terminate the program.
92 */
93void SDDS_MPI_GOTO_ERROR(FILE *fp, char *str, int32_t mpierr, int32_t exit_code) {
94 MPI_Error_string(mpierr, SDDS_mpi_error_str, &SDDS_mpi_error_str_len);
95 if (str)
96 fprintf(fp, "%s: ", str);
97 if (SDDS_mpi_error_str_len > 0)
98 fprintf(fp, "%s\n", SDDS_mpi_error_str);
99 if (exit_code)
100 exit(1);
101}
102
103/**
104 * @brief Opens an MPI file with the specified flags.
105 *
106 * This function opens an MPI file using the given filename and flags, setting the appropriate MPI file mode based on the flags. It also initializes the MPI dataset's debug file pointer and other related fields. If the file is successfully opened, it returns 1; otherwise, it handles the error and may exit the program.
107 *
108 * @param MPI_dataset Pointer to the `MPI_DATASET` structure to initialize.
109 * @param filename The name of the file to open.
110 * @param flags Flags indicating the mode in which to open the file (e.g., read-only, write-only, read-write).
111 * @return `1` if the file was successfully opened, `0` otherwise.
112 */
113int32_t SDDS_MPI_File_Open(MPI_DATASET *MPI_dataset, char *filename, unsigned long flags) {
114 unsigned long file_opened = 0; /* Flag to indicate that the file was successfully opened */
115 int mpi_amode = MPI_MODE_RDWR;
116 int mpi_code; /* mpi return code */
117
118 /* Get the MPI rank of this process and the total number of processes */
119 /*if (MPI_SUCCESS != (mpi_code=MPI_Comm_rank(MPI_dataset->comm, &MPI_dataset->myid)))
120 SDDS_MPI_GOTO_ERROR(stderr, "MPI_Comm_rank failed", mpi_code, 1);
121 if (MPI_SUCCESS != (mpi_code=MPI_Comm_size(MPI_dataset->comm, &MPI_dataset->n_processors)))
122 SDDS_MPI_GOTO_ERROR(stderr, "MPI_Comm_size failed", mpi_code, 1); */
123
124 MPI_dataset->fpdeb = NULL;
125
126 if (flags & SDDS_MPI_WRITE_ONLY)
127 mpi_amode = MPI_MODE_CREATE | MPI_MODE_WRONLY;
128 if (flags & SDDS_MPI_READ_ONLY)
129 mpi_amode = MPI_MODE_RDONLY;
130 if (flags & SDDS_MPI_READ_WRITE)
131 mpi_amode = MPI_MODE_CREATE | MPI_MODE_RDWR;
132 if (MPI_SUCCESS != (mpi_code = MPI_File_open(MPI_dataset->comm, filename, mpi_amode, MPI_INFO_NULL, &(MPI_dataset->MPI_file))))
133 SDDS_MPI_GOTO_ERROR(stderr, "MPI_File_open failed", mpi_code, 1);
134 else
135 file_opened = 1;
136 MPI_dataset->n_page = 0;
137 if (mpi_amode & MPI_MODE_WRONLY)
138 MPI_File_set_size(MPI_dataset->MPI_file, 0);
139 if (mpi_amode != MPI_MODE_RDONLY) {
140 if (MPI_SUCCESS != (mpi_code = MPI_File_sync(MPI_dataset->MPI_file)))
141 SDDS_MPI_GOTO_ERROR(stderr, "MPI_File_sync failed", mpi_code, 1);
142 }
143 /*MPI_dataset->file_offset = 0; */
144 return file_opened;
145}
146
147/**
148 * @brief Creates a namelist field string from a name and value.
149 *
150 * This function allocates and constructs a string representing a namelist field in the format `name=value` or `name="value"` depending on the content of the value. It handles escaping of double quotes within the value and ensures proper formatting based on the presence of special characters.
151 *
152 * @param name The name of the field.
153 * @param value The value of the field.
154 * @return A newly allocated string containing the namelist field, or `NULL` if the name is `NULL` or empty.
155 */
156char *SDDS_CreateNamelistField(char *name, char *value) {
157 char *contents;
158 char *buffer = NULL, *bPtr, *vPtr, buf2[2048];
159
160 contents = NULL;
161 if (!name)
162 return NULL;
163 if (!value || !strlen(name))
164 return NULL;
165 contents = (char *)malloc(sizeof(char) * 2048);
166 contents[0] = 0;
167 if (!strlen(value))
168 sprintf(contents, "%s=\"\", ", name);
169 else {
170 if (strchr(value, '"')) {
171 if (!(buffer = SDDS_Malloc(sizeof(*buffer) * 2 * strlen(value))))
172 return 0;
173 vPtr = value;
174 bPtr = buffer;
175 while (*vPtr) {
176 if (*vPtr == '"')
177 *bPtr++ = '\\';
178 *bPtr++ = *vPtr++;
179 }
180 *bPtr = 0;
181 value = buffer;
182 }
183 if (strpbrk(value, " ,*$\t\n\b")) {
184 //sprintf(contents, "%s%s=\"%s\", ", contents, name, value);
185 sprintf(buf2, "%s=\"%s\", ", name, value);
186 contents = strcat(contents, buf2);
187 } else {
188 ///sprintf(contents, "%s%s=%s, ", contents, name, value);
189 sprintf(buf2, "%s=%s, ", name, value);
190 contents = strcat(contents, buf2);
191 }
192 if (buffer)
193 free(buffer);
194 }
195 return contents;
196}
197
198/**
199 * @brief Creates a description block for the SDDS layout.
200 *
201 * This function allocates and constructs a description block containing the provided text and contents. It formats the description in the SDDS namelist format.
202 *
203 * @param text The descriptive text.
204 * @param contents The contents of the description.
205 * @return A newly allocated string containing the description block, or `NULL` if both `text` and `contents` are `NULL`.
206 */
207char *SDDS_CreateDescription(char *text, char *contents) {
208 char *desc = NULL;
209 if (!text && !contents)
210 return NULL;
211 desc = (char *)malloc(sizeof(char) * 2048);
212 desc[0] = 0;
213 sprintf(desc, "&description ");
214 if (text)
215 strcat(desc, SDDS_CreateNamelistField("text", text));
216 if (contents)
217 strcat(desc, SDDS_CreateNamelistField("contents", contents));
218 //sprintf(desc, "%s&end\n", desc);
219 desc = strcat(desc, "&end\n");
220 return desc;
221}
222
223/**
224 * @brief Creates a parameter definition block for the SDDS layout.
225 *
226 * This function allocates and constructs a parameter definition block based on the provided `PARAMETER_DEFINITION` structure. It includes fields such as `name`, `symbol`, `units`, `description`, `format_string`, `type`, and `fixed_value`.
227 *
228 * @param parameter_definition Pointer to the `PARAMETER_DEFINITION` structure.
229 * @return A newly allocated string containing the parameter definition block.
230 */
232 char *par, *tmpstr;
233 par = (char *)malloc(sizeof(char) * 2048);
234 par[0] = 0;
235 sprintf(par, "&parameter ");
236 strcat(par, SDDS_CreateNamelistField("name", parameter_definition->name));
237 if ((tmpstr = BlankToNull(parameter_definition->symbol)))
238 strcat(par, SDDS_CreateNamelistField("symbol", tmpstr));
239 if ((tmpstr = BlankToNull(parameter_definition->units)))
240 strcat(par, SDDS_CreateNamelistField("units", tmpstr));
241 if ((tmpstr = BlankToNull(parameter_definition->description)))
242 strcat(par, SDDS_CreateNamelistField("description", tmpstr));
243 if ((tmpstr = BlankToNull(parameter_definition->format_string)))
244 strcat(par, SDDS_CreateNamelistField("format_string", tmpstr));
245 strcat(par, SDDS_CreateNamelistField("type", SDDS_type_name[parameter_definition->type - 1]));
246 /*if ((tmpstr=BlankToNull(parameter_definition->fixed_value)))
247 strcat(par, SDDS_CreateNamelistField("fixed_value", tmpstr)); */
248 if (parameter_definition->fixed_value)
249 strcat(par, SDDS_CreateNamelistField("fixed_value", parameter_definition->fixed_value));
250 strcat(par, "&end\n");
251 return par;
252}
253
254/**
255 * @brief Creates a column definition block for the SDDS layout.
256 *
257 * This function allocates and constructs a column definition block based on the provided `COLUMN_DEFINITION` structure. It includes fields such as `name`, `symbol`, `units`, `description`, `format_string`, `type`, and ends the block.
258 *
259 * @param column_definition Pointer to the `COLUMN_DEFINITION` structure.
260 * @return A newly allocated string containing the column definition block.
261 */
263 char *col = NULL, *tmpStr;
264 col = (char *)malloc(sizeof(char) * 2048);
265 col[0] = 0;
266 sprintf(col, "&column ");
267 strcat(col, SDDS_CreateNamelistField("name", column_definition->name));
268 if ((tmpStr = BlankToNull(column_definition->symbol)))
269 strcat(col, SDDS_CreateNamelistField("symbol", tmpStr));
270 if ((tmpStr = BlankToNull(column_definition->units)))
271 strcat(col, SDDS_CreateNamelistField("units", tmpStr));
272 if ((tmpStr = BlankToNull(column_definition->description)))
273 strcat(col, SDDS_CreateNamelistField("description", tmpStr));
274 if ((tmpStr = BlankToNull(column_definition->format_string)))
275 strcat(col, SDDS_CreateNamelistField("format_string", tmpStr));
276 strcat(col, SDDS_CreateNamelistField("type", SDDS_type_name[column_definition->type - 1]));
277 strcat(col, " &end\n");
278 return col;
279}
280
281/**
282 * @brief Creates an array definition block for the SDDS layout.
283 *
284 * This function allocates and constructs an array definition block based on the provided `ARRAY_DEFINITION` structure. It includes fields such as `name`, `symbol`, `units`, `description`, `format_string`, `group_name`, `type`, `dimensions`, and ends the block.
285 *
286 * @param array_definition Pointer to the `ARRAY_DEFINITION` structure.
287 * @return A newly allocated string containing the array definition block.
288 */
290 char *array = NULL, *tmpstr;
291 char buf[40];
292 array = (char *)malloc(sizeof(char) * 2048);
293 array[0] = 0;
294 sprintf(array, "&array ");
295 strcat(array, SDDS_CreateNamelistField("name", array_definition->name));
296 if ((tmpstr = BlankToNull(array_definition->symbol)))
297 strcat(array, SDDS_CreateNamelistField("symbol", tmpstr));
298 if ((tmpstr = BlankToNull(array_definition->units)))
299 strcat(array, SDDS_CreateNamelistField("units", tmpstr));
300 if ((tmpstr = BlankToNull(array_definition->description)))
301 strcat(array, SDDS_CreateNamelistField("description", tmpstr));
302 if ((tmpstr = BlankToNull(array_definition->format_string)))
303 strcat(array, SDDS_CreateNamelistField("format_string", tmpstr));
304 if ((tmpstr = BlankToNull(array_definition->group_name)))
305 strcat(array, SDDS_CreateNamelistField("group_name", tmpstr));
306 strcat(array, SDDS_CreateNamelistField("type", SDDS_type_name[array_definition->type - 1]));
307 if (array_definition->dimensions != 1) /* 1 is default */
308 {
309 //sprintf(array, "%sdimensions=%" PRId32 ", ", array, array_definition->dimensions);
310 sprintf(buf, "dimensions=%" PRId32 ", ", array_definition->dimensions);
311 strcat(array, buf);
312 }
313 strcat(array, " &end\n");
314 return array;
315}
316
317/**
318 * @brief Creates an associate definition block for the SDDS layout.
319 *
320 * This function allocates and constructs an associate definition block based on the provided `ASSOCIATE_DEFINITION` structure. It includes fields such as `name`, `filename`, `contents`, `path`, `description`, and the associated SDDS index.
321 *
322 * @param associate_definition Pointer to the `ASSOCIATE_DEFINITION` structure.
323 * @return A newly allocated string containing the associate definition block.
324 */
326 char *associate = NULL, *tmpstr;
327 char buf[40];
328 associate = (char *)malloc(sizeof(char) * 2048);
329 associate[0] = 0;
330 sprintf(associate, "&associate ");
331 strcat(associate, SDDS_CreateNamelistField("name", associate_definition->name));
332 if ((tmpstr = BlankToNull(associate_definition->filename)))
333 strcat(associate, SDDS_CreateNamelistField("filename", tmpstr));
334 if ((tmpstr = BlankToNull(associate_definition->contents)))
335 strcat(associate, SDDS_CreateNamelistField("contents", tmpstr));
336 if ((tmpstr = BlankToNull(associate_definition->path)))
337 strcat(associate, SDDS_CreateNamelistField("path", tmpstr));
338 if ((tmpstr = BlankToNull(associate_definition->description)))
339 strcat(associate, SDDS_CreateNamelistField("description", tmpstr));
340 //sprintf(associate, "%ssdds=%" PRId32, associate, associate_definition->sdds);
341 sprintf(buf, "sdds=%" PRId32 " &end\n", associate_definition->sdds);
342 strcat(associate, buf);
343 //strcat(associate, " &end\n");
344 return associate;
345 ;
346}
347
348/**
349 * @brief Creates a data mode block for the SDDS layout.
350 *
351 * This function allocates and constructs a data mode block based on the provided `DATA_MODE` structure. It includes fields such as `mode`, `lines_per_row`, `no_row_counts`, `column_major_order`, and ends the block.
352 *
353 * @param data_mode Pointer to the `DATA_MODE` structure.
354 * @return A newly allocated string containing the data mode block, or `NULL` if the mode is invalid.
355 */
357 char *mode = NULL;
358 char buf[40];
359 if (data_mode->mode > SDDS_NUM_DATA_MODES)
360 return NULL;
361 mode = (char *)malloc(sizeof(char) * 2048);
362 mode[0] = 0;
363 sprintf(mode, "&data ");
364 strcat(mode, SDDS_CreateNamelistField("mode", SDDS_data_mode[data_mode->mode - 1]));
365 if (data_mode->lines_per_row > 1) {
366 //sprintf(mode, "%slines_per_row=%" PRId32 ", ", mode, data_mode->lines_per_row);
367 sprintf(buf, "lines_per_row=%" PRId32 ", ", data_mode->lines_per_row);
368 strcat(mode, buf);
369 }
370 if (data_mode->no_row_counts) {
371 //sprintf(mode, "%sno_row_counts=1, ", mode);
372 strcat(mode, "no_row_counts=1, ");
373 }
374 if (data_mode->column_major) {
375 strcat(mode, "column_major_order=1, ");
376 }
377 strcat(mode, "&end\n");
378 return mode;
379}
380
381/**
382 * @brief Writes an ASCII string to the SDDS dataset using MPI.
383 *
384 * This function writes the provided string to the SDDS dataset's MPI file. It handles buffering to optimize writes and manages buffer overflows by writing buffer contents to the file when necessary. Returns `1` on success, `0` on failure.
385 *
386 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure.
387 * @param string The ASCII string to write.
388 * @return `1` if the string was successfully written, `0` otherwise.
389 */
390int32_t SDDS_MPI_WriteAsciiString(SDDS_DATASET *SDDS_dataset, char *string) {
391 SDDS_FILEBUFFER *fBuffer;
392 MPI_DATASET *MPI_dataset = SDDS_dataset->MPI_dataset;
393 int32_t mpi_code;
394 size_t targetSize;
395
396 fBuffer = &(SDDS_dataset->fBuffer);
397 targetSize = strlen(string) * sizeof(char);
398
399 if (!fBuffer->bufferSize) {
400 if ((mpi_code = MPI_File_write(MPI_dataset->MPI_file, string, targetSize, MPI_CHAR, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
401 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_WriteBufferedWrite(MPI_File_write_at failed)", mpi_code, 0);
402 return 0;
403 }
404 return 1;
405 }
406 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
407 memcpy((char *)fBuffer->data, (char *)string, targetSize);
408 fBuffer->data += targetSize;
409 return 1;
410 } else {
411 int32_t lastLeft;
412 /* add back what was subtracted in test above.
413 * lastLeft is the number of bytes left in the buffer before doing anything
414 * and also the number of bytes from the users data that get copied into the buffer.
415 */
416 lastLeft = (fBuffer->bytesLeft += targetSize);
417 /* copy part of the data into the buffer and write the buffer out */
418 memcpy((char *)fBuffer->data, (char *)string, (size_t)fBuffer->bytesLeft);
419 if ((mpi_code = MPI_File_write(MPI_dataset->MPI_file, fBuffer->buffer, (int)(fBuffer->bufferSize), MPI_CHAR, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
420 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_WriteBufferedWrite(MPI_File_write_at failed)", mpi_code, 0);
421 return 0;
422 }
423
424 /* reset the data pointer and the bytesLeft value.
425 * also, determine if the remaining data is too large for the buffer.
426 * if so, just write it out.
427 */
428 fBuffer->data = fBuffer->buffer;
429 if ((targetSize -= lastLeft) > (fBuffer->bytesLeft = fBuffer->bufferSize)) {
430 if ((mpi_code = MPI_File_write_at(MPI_dataset->MPI_file, (MPI_Offset)(MPI_dataset->file_offset), string + lastLeft, targetSize, MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
431 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_WriteBufferedWrite(MPI_File_write_at failed)", mpi_code, 0);
432 return 0;
433 }
434 return 1;
435 }
436 /* copy remaining data into the buffer.
437 * could do this with a recursive call, but this is more efficient.
438 */
439 memcpy((char *)fBuffer->data, (char *)string + lastLeft, targetSize);
440 fBuffer->data += targetSize;
441 fBuffer->bytesLeft -= targetSize;
442 return 1;
443 }
444}
445
446/**
447 * @brief Writes the layout of the SDDS dataset to the MPI file.
448 *
449 * This function writes the SDDS dataset layout information to the associated MPI file. It sets the file view, checks and saves the dataset, determines the byte order, allocates and manages the write buffer, and writes various layout components including description, parameters, arrays, columns, associates, and data mode. It ensures proper synchronization and handles errors appropriately. Only the MPI process with rank 0 performs the actual write operations.
450 *
451 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure.
452 * @return `1` if the layout was successfully written, `0` otherwise.
453 */
454int32_t SDDS_MPI_WriteLayout(SDDS_DATASET *SDDS_dataset) {
455 MPI_DATASET *MPI_dataset;
456 SDDS_LAYOUT *layout;
457 char buf[2048], *field = NULL;
458 int32_t i, data_mode;
459 char *outputEndianess = NULL;
460 SDDS_FILEBUFFER *fBuffer = NULL;
461
462#if MPI_DEBUG
463 logDebug("SDDS_MPI_WriteLayout", SDDS_dataset);
464#endif
465
466 MPI_dataset = SDDS_dataset->MPI_dataset;
467 MPI_File_set_view(MPI_dataset->MPI_file, 0, MPI_CHAR, MPI_CHAR, "native", MPI_INFO_NULL);
468 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteLayout"))
469 return 0;
470 if (!SDDS_SaveLayout(SDDS_dataset))
471 return 0;
472 layout = &SDDS_dataset->layout;
473 if (SDDS_dataset->layout.disconnected) {
474 SDDS_SetError("Can't write layout--file is disconnected (SDDS_MPI_WriteLayout)");
475 return 0;
476 }
477 MPI_dataset->file_offset = 0;
478 if (layout->layout_written) {
479 SDDS_SetError("Can't write layout--already written to file (SDDS_MPI_WriteLayout)");
480 return 0;
481 }
482
483 if ((outputEndianess = getenv("SDDS_OUTPUT_ENDIANESS"))) {
484 if (strncmp(outputEndianess, "big", 3) == 0)
485 layout->byteOrderDeclared = SDDS_BIGENDIAN;
486 else if (strncmp(outputEndianess, "little", 6) == 0)
487 layout->byteOrderDeclared = SDDS_LITTLEENDIAN;
488 }
489
490 if (!layout->byteOrderDeclared)
491 layout->byteOrderDeclared = SDDS_IsBigEndianMachine() ? SDDS_BIGENDIAN : SDDS_LITTLEENDIAN;
492
493 fBuffer = &(SDDS_dataset->fBuffer);
494 /* write out the layout data */
495 if (MPI_dataset->myid == 0) {
496 if (!fBuffer->buffer) {
497 fBuffer->bufferSize = SDDS_SetDefaultWriteBufferSize(-1);
498 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (fBuffer->bufferSize + 1)))) {
499 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_MPI_WriteLayout)");
500 return 0;
501 }
502 fBuffer->bytesLeft = fBuffer->bufferSize;
503 fBuffer->data[0] = 0;
504 }
505 }
506 layout->version = 1;
507 for (i = 0; i < layout->n_parameters; i++) {
508 if ((layout->parameter_definition[i].type == SDDS_ULONG) || (layout->parameter_definition[i].type == SDDS_USHORT)) {
509 layout->version = 2;
510 break;
511 }
512 }
513 for (i = 0; i < layout->n_arrays; i++) {
514 if ((layout->array_definition[i].type == SDDS_ULONG) || (layout->array_definition[i].type == SDDS_USHORT)) {
515 layout->version = 2;
516 break;
517 }
518 }
519 for (i = 0; i < layout->n_columns; i++) {
520 if ((layout->column_definition[i].type == SDDS_ULONG) || (layout->column_definition[i].type == SDDS_USHORT)) {
521 layout->version = 2;
522 break;
523 }
524 }
525 if ((layout->data_mode.column_major) && (layout->data_mode.mode == SDDS_BINARY)) {
526 layout->version = 3;
527 }
528 for (i = 0; i < layout->n_parameters; i++) {
529 if (layout->parameter_definition[i].type == SDDS_LONGDOUBLE) {
530 layout->version = 4;
531 break;
532 }
533 }
534 for (i = 0; i < layout->n_arrays; i++) {
535 if (layout->array_definition[i].type == SDDS_LONGDOUBLE) {
536 layout->version = 4;
537 break;
538 }
539 }
540 for (i = 0; i < layout->n_columns; i++) {
541 if (layout->column_definition[i].type == SDDS_LONGDOUBLE) {
542 layout->version = 4;
543 break;
544 }
545 }
546 if ((LDBL_DIG != 18) && (layout->version == 4)) {
547 SDDS_SetError("Operating system does not support 80bit float variables used by SDDS_LONGDOUBLE (SDDS_MPI_WriteLayout)");
548 return 0;
549 }
550 for (i = 0; i < layout->n_parameters; i++) {
551 if ((layout->parameter_definition[i].type == SDDS_ULONG64) || (layout->parameter_definition[i].type == SDDS_LONG64)) {
552 layout->version = 5;
553 break;
554 }
555 }
556 for (i = 0; i < layout->n_arrays; i++) {
557 if ((layout->array_definition[i].type == SDDS_ULONG64) || (layout->array_definition[i].type == SDDS_LONG64)) {
558 layout->version = 5;
559 break;
560 }
561 }
562 for (i = 0; i < layout->n_columns; i++) {
563 if ((layout->column_definition[i].type == SDDS_ULONG64) || (layout->column_definition[i].type == SDDS_LONG64)) {
564 layout->version = 5;
565 break;
566 }
567 }
568 // force layout version 5 because the row and column indexes are now 64bit long integers
569 //layout->version = 5;
570 sprintf(buf, "SDDS%" PRId32 "\n", layout->version);
571
572 MPI_dataset->file_offset += strlen(buf) * sizeof(char);
573 data_mode = SDDS_dataset->layout.data_mode.mode;
574 if (MPI_dataset->myid == 0 && !SDDS_MPI_WriteAsciiString(SDDS_dataset, buf)) {
575 fprintf(stderr, "SDDS_MPI_WriteLayout(error1): Unable to write layout.\n");
576 return 0;
577 }
578 if (data_mode == SDDS_BINARY) {
579 if (layout->byteOrderDeclared == SDDS_BIGENDIAN)
580 sprintf(buf, "!# big-endian\n");
581 else
582 sprintf(buf, "!# little-endian\n");
583 if (MPI_dataset->myid == 0 && !SDDS_MPI_WriteAsciiString(SDDS_dataset, buf)) {
584 fprintf(stderr, "SDDS_MPI_WriteLayout(error1): Unable to write layout.\n");
585 return 0;
586 }
587 MPI_dataset->file_offset += strlen(buf) * sizeof(char);
588 }
589 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
590 sprintf(buf, "!# fixed-rowcount\n");
591 if (MPI_dataset->myid == 0 && !SDDS_MPI_WriteAsciiString(SDDS_dataset, buf)) {
592 fprintf(stderr, "SDDS_MPI_WriteLayout(error1): Unable to write layout.\n");
593 return 0;
594 }
595 MPI_dataset->file_offset += strlen(buf) * sizeof(char);
596 }
597 field = NULL;
598 if ((field = SDDS_CreateDescription(layout->description, layout->contents)) != NULL) {
599 if (MPI_dataset->myid == 0 && !SDDS_MPI_WriteAsciiString(SDDS_dataset, field)) {
600 fprintf(stderr, "SDDS_MPI_WriteLayout(error1): Unable to write layout.\n");
601 return 0;
602 }
603 MPI_dataset->file_offset += strlen(field) * sizeof(char);
604 free(field);
605 field = NULL;
606 }
607
608 for (i = 0; i < layout->n_parameters; i++) {
609 field = SDDS_CreateParameterDefinition(layout->parameter_definition + i);
610 if (MPI_dataset->myid == 0 && !SDDS_MPI_WriteAsciiString(SDDS_dataset, field)) {
611 fprintf(stderr, "SDDS_MPI_WriteLayout(error1): Unable to write layout.\n");
612 return 0;
613 }
614 MPI_dataset->file_offset += strlen(field) * sizeof(char);
615 free(field);
616 field = NULL;
617 }
618 for (i = 0; i < layout->n_arrays; i++) {
619 field = SDDS_CreateArrayDefinition(layout->array_definition + i);
620 if (MPI_dataset->myid == 0 && !SDDS_MPI_WriteAsciiString(SDDS_dataset, field)) {
621 fprintf(stderr, "SDDS_MPI_WriteLayout(error1): Unable to write layout.\n");
622 return 0;
623 }
624 MPI_dataset->file_offset += strlen(field) * sizeof(char);
625 free(field);
626 field = NULL;
627 }
628 for (i = 0; i < layout->n_columns; i++) {
629 field = SDDS_CreateColumnDefinition(layout->column_definition + i);
630 if (MPI_dataset->myid == 0 && !SDDS_MPI_WriteAsciiString(SDDS_dataset, field)) {
631 fprintf(stderr, "SDDS_MPI_WriteLayout(error1): Unable to write layout.\n");
632 return 0;
633 }
634 MPI_dataset->file_offset += strlen(field) * sizeof(char);
635 free(field);
636 field = NULL;
637 }
638
639#if RW_ASSOCIATES != 0
640 for (i = 0; i < layout->n_associates; i++) {
641 field = SDDS_CreateAssociateDefinition(layout->associate_definition + i);
642 if (MPI_dataset->myid == 0 && !SDDS_MPI_WriteAsciiString(SDDS_dataset, field)) {
643 fprintf(stderr, "SDDS_MPI_WriteLayout(error1): Unable to write layout.\n");
644 return 0;
645 }
646 MPI_dataset->file_offset += strlen(field) * sizeof(char);
647 free(field);
648 field = NULL;
649 }
650#endif
651 if ((field = SDDS_CreateDataMode(&layout->data_mode)) != NULL) {
652 if (MPI_dataset->myid == 0 && !SDDS_MPI_WriteAsciiString(SDDS_dataset, field)) {
653 fprintf(stderr, "SDDS_MPI_WriteLayout(error1): Unable to write layout.\n");
654 return 0;
655 }
656 MPI_dataset->file_offset += strlen(field) * sizeof(char);
657 free(field);
658 field = NULL;
659 }
660 MPI_dataset->column_offset = SDDS_MPI_Get_Column_Size(SDDS_dataset);
661 layout->layout_written = 1;
662 if (MPI_dataset->myid == 0) {
663 if (!SDDS_MPI_FlushBuffer(SDDS_dataset))
664 return 0;
665 }
666 SDDS_dataset->original_layout.version = layout->version;
667 return (1);
668}
669
670/**
671 * @brief Terminates the program after handling errors and cleaning up MPI resources.
672 *
673 * This function prints all accumulated SDDS errors to `stderr` using `SDDS_PrintErrors`.
674 * If a custom error message (`text`) is provided, it is printed to `stderr`.
675 * If an MPI file pointer (`mpi_file`) is provided, the MPI file is closed.
676 * Finally, the MPI environment is finalized, and the program exits with a status of 1.
677 *
678 * @param text A custom error message to display. Can be `NULL`.
679 * @param mpi_file Pointer to an `MPI_File` to be closed. Can be `NULL`.
680 */
681void SDDS_MPI_BOMB(char *text, MPI_File *mpi_file) {
682 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
683 if (text)
684 fprintf(stderr, "Error: %s\n", text);
685 if (mpi_file)
686 MPI_File_close(mpi_file);
687 MPI_Finalize();
688 exit(1);
689}
690
691/**
692 * @brief Writes a page of data to the MPI file associated with the SDDS dataset.
693 *
694 * This function checks the validity of the dataset and ensures that the layout has been written
695 * and that the file is connected. If these conditions are met, it proceeds to write a binary
696 * page using `SDDS_MPI_WriteBinaryPage`.
697 *
698 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure containing the dataset information.
699 * @return `1` if the page was successfully written, `0` otherwise.
700 */
701int32_t SDDS_MPI_WritePage(SDDS_DATASET *SDDS_dataset) {
702 int32_t result;
703
704#if MPI_DEBUG
705 logDebug("SDDS_MPI_WritePage", SDDS_dataset);
706#endif
707
708 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WritePage"))
709 return 0;
710 if (!SDDS_dataset->layout.layout_written) {
711 SDDS_SetError("Unable to write page--layout not written (SDDS_WritePage)");
712 return 0;
713 }
714 if (SDDS_dataset->layout.disconnected) {
715 SDDS_SetError("Can't write page--file is disconnected (SDDS_WritePage)");
716 return 0;
717 }
718 result = SDDS_MPI_WriteBinaryPage(SDDS_dataset);
719 return result;
720}
721
722/**
723 * @brief Converts an SDDS data type to the corresponding MPI data type.
724 *
725 * This function maps custom SDDS data types to their equivalent MPI data types using a switch statement.
726 * If an unknown SDDS data type is provided, the function calls `SDDS_Bomb` to handle the error.
727 *
728 * @param SDDS_type The SDDS data type to convert.
729 * @return The corresponding `MPI_Datatype`.
730 */
731MPI_Datatype Convert_SDDStype_To_MPItype(int32_t SDDS_type) {
732 switch (SDDS_type) {
733 case SDDS_SHORT:
734 return MPI_SHORT;
735 case SDDS_USHORT:
736 return MPI_UNSIGNED_SHORT;
737 case SDDS_LONG:
738 /* SDDS_LONG type is actually int32_t */
739 return MPI_INT;
740 case SDDS_ULONG:
741 return MPI_UNSIGNED;
742 case SDDS_LONG64:
743 return MPI_INT64_T;
744 case SDDS_ULONG64:
745 return MPI_UINT64_T;
746 case SDDS_FLOAT:
747 return MPI_FLOAT;
748 case SDDS_DOUBLE:
749 return MPI_DOUBLE;
750 case SDDS_LONGDOUBLE:
751 return MPI_LONG_DOUBLE;
752 case SDDS_STRING:
753 case SDDS_CHARACTER:
754 return MPI_CHAR;
755 default:
756 SDDS_Bomb("Unknown SDDS datatype provided to ConvertSDDS_To_MPI.");
757 return 0;
758 }
759}
760
761/**
762 * @brief Terminates the SDDS dataset by freeing all allocated resources and closing MPI files.
763 *
764 * This function performs comprehensive cleanup of the `SDDS_DATASET` structure, freeing all
765 * dynamically allocated memory associated with parameters, arrays, columns, and associates.
766 * It also closes the MPI file, finalizes MPI, and resets the dataset's layout and data structures.
767 *
768 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure to terminate.
769 * @return `1` if termination was successful, `0` otherwise.
770 */
771int32_t SDDS_MPI_Terminate(SDDS_DATASET *SDDS_dataset) {
772 MPI_DATASET *MPI_dataset;
773 SDDS_LAYOUT *layout;
774 char **ptr;
775 int32_t i, j;
776
777#if MPI_DEBUG
778 logDebug("SDDS_MPI_Terminate", SDDS_dataset);
779#endif
780
781 MPI_dataset = SDDS_dataset->MPI_dataset;
782 layout = &(SDDS_dataset->original_layout);
783 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_Terminate"))
784 return (0);
785 if (SDDS_dataset->pagecount_offset)
786 free(SDDS_dataset->pagecount_offset);
787 if (SDDS_dataset->row_flag)
788 free(SDDS_dataset->row_flag);
789 if (SDDS_dataset->column_order)
790 free(SDDS_dataset->column_order);
791 if (SDDS_dataset->column_flag)
792 free(SDDS_dataset->column_flag);
793 if (SDDS_dataset->fBuffer.buffer)
794 free(SDDS_dataset->fBuffer.buffer);
795 if (SDDS_dataset->titleBuffer.buffer)
796 free(SDDS_dataset->titleBuffer.buffer);
797 if (SDDS_dataset->parameter) {
798 for (i = 0; i < layout->n_parameters; i++) {
799 if (layout->parameter_definition[i].type == SDDS_STRING && *(char **)(SDDS_dataset->parameter[i]))
800 free(*(char **)(SDDS_dataset->parameter[i]));
801 if (SDDS_dataset->parameter[i])
802 free(SDDS_dataset->parameter[i]);
803 }
804 free(SDDS_dataset->parameter);
805 }
806 if (SDDS_dataset->array) {
807 for (i = 0; i < layout->n_arrays; i++) {
808 if (layout->array_definition[i].type == SDDS_STRING && !(terminateMode & TERMINATE_DONT_FREE_ARRAY_STRINGS)) {
809 for (j = 0; j < SDDS_dataset->array[i].elements; j++)
810 if (((char **)SDDS_dataset->array[i].data)[j])
811 free(((char **)SDDS_dataset->array[i].data)[j]);
812 }
813 /*
814 if (SDDS_dataset->array[i].definition->type==SDDS_STRING &&
815 !(terminateMode&TERMINATE_DONT_FREE_ARRAY_STRINGS)) {
816 for (j=0; j<SDDS_dataset->array[i].elements; j++)
817 if (((char**)SDDS_dataset->array[i].data)[j])
818 free(((char**)SDDS_dataset->array[i].data)[j]);
819 }
820 */
821 if (SDDS_dataset->array[i].data)
822 free(SDDS_dataset->array[i].data);
823 /* should free the subpointers too, but it would be a lot of trouble for little benefit: */
824 if (SDDS_dataset->array[i].pointer && SDDS_dataset->array[i].definition->dimensions != 1)
825 free(SDDS_dataset->array[i].pointer);
826 if (SDDS_dataset->array[i].dimension)
827 free(SDDS_dataset->array[i].dimension);
828 /* don't touch this--it's done below */
829 if (SDDS_dataset->array[i].definition && SDDS_dataset->array[i].definition->name) {
830 if (SDDS_dataset->array[i].definition->name != layout->array_definition[i].name)
831 SDDS_FreeArrayDefinition(SDDS_dataset->array[i].definition);
832 }
833 SDDS_dataset->array[i].definition = NULL;
834 }
835 free(SDDS_dataset->array);
836 }
837 if (SDDS_dataset->data) {
838 for (i = 0; i < layout->n_columns; i++)
839 if (SDDS_dataset->data[i]) {
840 if (layout->column_definition[i].type == SDDS_STRING && !(terminateMode & TERMINATE_DONT_FREE_TABLE_STRINGS)) {
841 ptr = (char **)SDDS_dataset->data[i];
842 for (j = 0; j < SDDS_dataset->n_rows_allocated; j++, ptr++)
843 if (*ptr)
844 free(*ptr);
845 }
846 free(SDDS_dataset->data[i]);
847 }
848 free(SDDS_dataset->data);
849 }
850 if (layout->description)
851 free(layout->description);
852 if (layout->contents == (&SDDS_dataset->layout)->contents)
853 (&SDDS_dataset->layout)->contents = NULL;
854 if (layout->contents)
855 free(layout->contents);
856 if (layout->filename)
857 free(layout->filename);
858 if (layout->column_definition) {
859 for (i = 0; i < layout->n_columns; i++) {
860 if (layout->column_index[i])
861 free(layout->column_index[i]);
862 if (layout->column_definition[i].name)
863 free(layout->column_definition[i].name);
864 if (layout->column_definition[i].symbol)
865 free(layout->column_definition[i].symbol);
866 if (layout->column_definition[i].units)
867 free(layout->column_definition[i].units);
868 if (layout->column_definition[i].description)
869 free(layout->column_definition[i].description);
870 if (layout->column_definition[i].format_string)
871 free(layout->column_definition[i].format_string);
872 }
873 free(layout->column_definition);
874 free(layout->column_index);
875 }
876 if (layout->parameter_definition) {
877 for (i = 0; i < layout->n_parameters; i++) {
878 if (layout->parameter_index[i])
879 free(layout->parameter_index[i]);
880 if (layout->parameter_definition[i].name)
881 free(layout->parameter_definition[i].name);
882 if (layout->parameter_definition[i].symbol)
883 free(layout->parameter_definition[i].symbol);
884 if (layout->parameter_definition[i].units)
885 free(layout->parameter_definition[i].units);
886 if (layout->parameter_definition[i].description)
887 free(layout->parameter_definition[i].description);
888 if (layout->parameter_definition[i].format_string)
889 free(layout->parameter_definition[i].format_string);
890 if (layout->parameter_definition[i].fixed_value)
891 free(layout->parameter_definition[i].fixed_value);
892 }
893 free(layout->parameter_definition);
894 free(layout->parameter_index);
895 }
896 if (layout->array_definition) {
897 for (i = 0; i < layout->n_arrays; i++) {
898 if (layout->array_index[i])
899 free(layout->array_index[i]);
900 if (layout->array_definition[i].name)
901 free(layout->array_definition[i].name);
902 if (layout->array_definition[i].symbol)
903 free(layout->array_definition[i].symbol);
904 if (layout->array_definition[i].units)
905 free(layout->array_definition[i].units);
906 if (layout->array_definition[i].description)
907 free(layout->array_definition[i].description);
908 if (layout->array_definition[i].format_string)
909 free(layout->array_definition[i].format_string);
910 if (layout->array_definition[i].group_name)
911 free(layout->array_definition[i].group_name);
912 }
913 free(layout->array_definition);
914 free(layout->array_index);
915 }
916 if (layout->associate_definition) {
917 for (i = 0; i < layout->n_associates; i++) {
918 if (layout->associate_definition[i].name)
919 free(layout->associate_definition[i].name);
920 if (layout->associate_definition[i].filename)
921 free(layout->associate_definition[i].filename);
922 if (layout->associate_definition[i].path)
923 free(layout->associate_definition[i].path);
924 if (layout->associate_definition[i].description)
925 free(layout->associate_definition[i].description);
926 if (layout->associate_definition[i].contents)
927 free(layout->associate_definition[i].contents);
928 }
929 free(layout->associate_definition);
930 }
931 SDDS_ZeroMemory(&SDDS_dataset->original_layout, sizeof(SDDS_LAYOUT));
932 layout = &SDDS_dataset->layout;
933 if (layout->contents)
934 free(layout->contents);
935 if (layout->column_definition)
936 free(layout->column_definition);
937 if (layout->array_definition)
938 free(layout->array_definition);
939 if (layout->associate_definition)
940 free(layout->associate_definition);
941 if (layout->parameter_definition)
942 free(layout->parameter_definition);
943 if (layout->column_index)
944 free(layout->column_index);
945 if (layout->parameter_index)
946 free(layout->parameter_index);
947 if (layout->array_index)
948 free(layout->array_index);
949 SDDS_ZeroMemory(&SDDS_dataset->layout, sizeof(SDDS_LAYOUT));
950 SDDS_ZeroMemory(SDDS_dataset, sizeof(SDDS_DATASET));
951#if DEBUG
952 fprintf(stderr, "done\n");
953#endif
954 MPI_File_close(&(MPI_dataset->MPI_file));
955 free(MPI_dataset);
956 MPI_dataset = NULL;
957 return (1);
958}
959
960/**
961 * @brief Initializes the SDDS dataset for MPI output.
962 *
963 * This function sets up the SDDS dataset for parallel output using MPI. It initializes the dataset with
964 * the provided description, contents, and filename, sets the column major order if specified, and opens
965 * the MPI file for writing. It also logs the initialization if MPI debugging is enabled.
966 *
967 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure to initialize.
968 * @param description A description of the dataset.
969 * @param contents Additional contents for the dataset description.
970 * @param filename The name of the file to initialize for output.
971 * @param flags Flags indicating the mode in which to open the file (e.g., read-only, write-only, read-write).
972 * @param column_major If non-zero, data will be written in column-major order.
973 * @return `1` if initialization was successful, `0` otherwise.
974 */
975int32_t SDDS_MPI_InitializeOutput(SDDS_DATASET *SDDS_dataset, char *description, char *contents, char *filename, unsigned long flags, short column_major) {
976 MPI_DATASET *MPI_dataset = SDDS_dataset->MPI_dataset;
977
978 if (!SDDS_Parallel_InitializeOutput(SDDS_dataset, description, contents, filename))
979 return 0;
980 if (flags & SDDS_MPI_READ_ONLY) {
981 SDDS_SetError("Wrong flags pass (SDDS_MPI_READ_ONLY) passed to SDDS_MPI_InitializeOutput)!");
982 return 0;
983 }
984 /* SDDS_dataset->MPI_dataset = MPI_dataset; */
985 SDDS_dataset->layout.data_mode.column_major = column_major;
986 if (!SDDS_MPI_File_Open(MPI_dataset, filename, flags)) {
987 SDDS_SetError("Failed in opening file for MPI output!");
988 return 0;
989 }
990#if MPI_DEBUG
991 logDebug("SDDS_MPI_InitializeOutput", SDDS_dataset);
992#endif
993 return 1;
994}
995
996/**
997 * @brief Initializes a copy of an SDDS dataset for MPI output.
998 *
999 * This function creates a new SDDS dataset (`SDDS_target`) by copying the layout from an existing
1000 * dataset (`SDDS_source`). It sets up the target dataset for MPI output, opens the specified file,
1001 * and writes the layout to the file. The function also sets the data mode to column-major if specified.
1002 *
1003 * @param SDDS_target Pointer to the target `SDDS_DATASET` structure to initialize.
1004 * @param SDDS_source Pointer to the source `SDDS_DATASET` structure to copy from.
1005 * @param filename The name of the file to initialize for output.
1006 * @param column_major If non-zero, data will be written in column-major order.
1007 * @return `1` if the copy and initialization were successful, `0` otherwise.
1008 */
1009int32_t SDDS_MPI_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, short column_major) {
1010 MPI_DATASET *MPI_target = SDDS_target->MPI_dataset;
1011
1012 if (!SDDS_CheckDataset(SDDS_source, "SDDS_InitializeCopy"))
1013 return (0);
1014 if (!SDDS_CheckDataset(SDDS_target, "SDDS_InitializeCopy"))
1015 return (0);
1016 /* if (!SDDS_ZeroMemory((void *)SDDS_target, sizeof(SDDS_DATASET))) {
1017 SDDS_SetError("Unable to copy layout--can't zero SDDS_DATASET structure (SDDS_InitializeCopy)");
1018 return(0);
1019 } */
1020 /*has been zeroed in the setup */
1021 SDDS_target->pagecount_offset = NULL;
1022 SDDS_target->mode = SDDS_WRITEMODE;
1023 SDDS_target->layout.popenUsed = 0;
1024 SDDS_target->layout.gzipFile = 0;
1025 SDDS_target->layout.lzmaFile = 0;
1026 if (filename) {
1027 if (!SDDS_CopyString(&SDDS_target->layout.filename, filename)) {
1028 SDDS_SetError("Memory allocation failure (SDDS_InitializeCopy)");
1029 return (0);
1030 }
1031 }
1032 SDDS_target->page_number = SDDS_target->page_started = 0;
1033 if (!SDDS_CopyLayout(SDDS_target, SDDS_source))
1034 return (0);
1035 /* SDDS_target->MPI_dataset = MPI_target; */
1036 SDDS_target->layout.data_mode.column_major = column_major;
1037 if (!SDDS_MPI_File_Open(MPI_target, filename, SDDS_MPI_WRITE_ONLY))
1038 return 0;
1039 SDDS_target->parallel_io = 1;
1040 MPI_target->file_offset = 0;
1041 if (!SDDS_MPI_WriteLayout(SDDS_target))
1042 return 0;
1043 return 1;
1044}
1045
1046/**
1047 * @brief Sets up the SDDS dataset for MPI operations.
1048 *
1049 * This function initializes the `SDDS_DATASET` structure for MPI-based parallel I/O. It zeroes out the dataset,
1050 * allocates and initializes the `MPI_DATASET` structure if parallel I/O is enabled, and sets MPI-related fields
1051 * such as the number of processors, process ID, and MPI communicator.
1052 *
1053 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure to set up.
1054 * @param parallel_io If non-zero, the dataset will be set up for parallel I/O using MPI.
1055 * @param n_processors The total number of MPI processes.
1056 * @param myid The MPI process ID of the current process.
1057 * @param comm The MPI communicator to use for I/O operations.
1058 * @param master_read If non-zero, the master process will handle read operations.
1059 */
1060void SDDS_MPI_Setup(SDDS_DATASET *SDDS_dataset, int32_t parallel_io, int32_t n_processors, int32_t myid, MPI_Comm comm, short master_read) {
1061 MPI_DATASET *MPI_dataset;
1062
1063 if (!SDDS_ZeroMemory((void *)SDDS_dataset, sizeof(SDDS_DATASET)))
1064 SDDS_Bomb("Unable to zero memory for SDDS dataset(SDDS_MPI_Setup)");
1065 if (parallel_io) {
1066 MPI_dataset = malloc(sizeof(*MPI_dataset));
1067 if (!SDDS_ZeroMemory((void *)MPI_dataset, sizeof(MPI_DATASET)))
1068 SDDS_Bomb("Unable to zero memory for MPI_DATASEAT (SDDS_MPI_Setup)");
1069 MPI_dataset->n_processors = n_processors;
1070 MPI_dataset->myid = myid;
1071 MPI_dataset->comm = comm;
1072 MPI_dataset->collective_io = 0;
1073 MPI_dataset->master_read = master_read;
1074 MPI_dataset->fpdeb = NULL;
1075 SDDS_dataset->MPI_dataset = MPI_dataset;
1076 SDDS_dataset->parallel_io = 1;
1077 }
1078}
1079
1080/**
1081 * @brief Disconnects the MPI file associated with the SDDS dataset.
1082 *
1083 * This function checks the validity of the dataset and ensures that the file is connected and has a valid filename.
1084 * It then closes the MPI file and marks the dataset as disconnected.
1085 *
1086 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure whose file is to be disconnected.
1087 * @return `1` if the file was successfully disconnected, `0` otherwise.
1088 */
1090 MPI_DATASET *MPI_dataset;
1091
1092#if MPI_DEBUG
1093 logDebug("SDDS_MPI_DisconnectFile", SDDS_dataset);
1094#endif
1095
1096 MPI_dataset = SDDS_dataset->MPI_dataset;
1097 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_DisconnectFile"))
1098 return 0;
1099 if (!SDDS_dataset->layout.filename) {
1100 SDDS_SetError("Can't disconnect file. No filename or gzip file. (SDDS_MPI_DisconnectFile)");
1101 return 0;
1102 }
1103 if (SDDS_dataset->layout.disconnected) {
1104 SDDS_SetError("Can't disconnect file. Already disconnected. (SDDS_MPI_DisconnectFile)");
1105 return 0;
1106 }
1107 /* if (SDDS_dataset->page_started && !SDDS_WritePage(SDDS_dataset)) {
1108 SDDS_SetError("Can't disconnect file. Problem updating page. (SDDS_MPI_DisconnectFile)");
1109 return 0;
1110 } */
1111 SDDS_dataset->layout.disconnected = 1;
1112 MPI_File_close(&(MPI_dataset->MPI_file));
1113 return 1;
1114}
1115
1116/**
1117 * @brief Reconnects the MPI file associated with the SDDS dataset.
1118 *
1119 * This function checks the validity of the dataset and ensures that the file is currently disconnected
1120 * and has a valid filename. It then reopens the MPI file in read-write mode, updates the file view,
1121 * and marks the dataset as connected.
1122 *
1123 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure whose file is to be reconnected.
1124 * @return `1` if the file was successfully reconnected, `0` otherwise.
1125 */
1126int32_t SDDS_MPI_ReconnectFile(SDDS_DATASET *SDDS_dataset) {
1127 MPI_DATASET *MPI_dataset;
1128
1129#if MPI_DEBUG
1130 logDebug("SDDS_MPI_ReconnectFile", SDDS_dataset);
1131#endif
1132 MPI_dataset = SDDS_dataset->MPI_dataset;
1133 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_ReconnectFile"))
1134 return 0;
1135 if (!SDDS_dataset->layout.disconnected || !SDDS_dataset->layout.filename) {
1136 SDDS_SetError("Can't reconnect file. Not disconnected or missing filename. (SDDS_MPI_ReconnectFile)");
1137 return 0;
1138 }
1139 if (MPI_File_open(MPI_dataset->comm, SDDS_dataset->layout.filename, MPI_MODE_RDWR, MPI_INFO_NULL, &(MPI_dataset->MPI_file)) != MPI_SUCCESS) {
1140 SDDS_SetError("Can't reconnect file, MPI_File_open failed. (SDDS_MPI_ReconnectFile)");
1141 return 0;
1142 }
1143 MPI_File_get_size(MPI_dataset->MPI_file, &(MPI_dataset->file_offset));
1144 MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL);
1145 /* MPI_dataset->file_offset=0; */
1146 SDDS_dataset->layout.disconnected = 0;
1147 return 1;
1148}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_MPI_FlushBuffer(SDDS_DATASET *SDDS_dataset)
Flush the buffer by writing any remaining data to the MPI file.
int32_t SDDS_SetDefaultWriteBufferSize(int32_t newSize)
Set the default write buffer size for SDDS.
MPI_Offset SDDS_MPI_Get_Column_Size(SDDS_DATASET *SDDS_dataset)
Get the total size of all columns in an SDDS dataset.
int32_t SDDS_MPI_WriteBinaryPage(SDDS_DATASET *SDDS_dataset)
Write an SDDS binary page using MPI.
int32_t SDDS_CopyLayout(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:222
int32_t SDDS_SaveLayout(SDDS_DATASET *SDDS_dataset)
Definition SDDS_copy.c:615
char * SDDS_data_mode[SDDS_NUM_DATA_MODES]
Array of supported data modes.
Definition SDDS_data.c:33
char * SDDS_type_name[SDDS_NUM_TYPES]
Array of supported data type names.
Definition SDDS_data.c:43
int32_t SDDS_Parallel_InitializeOutput(SDDS_DATASET *SDDS_dataset, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset for parallel processing.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
int32_t SDDS_ZeroMemory(void *mem, int64_t n_bytes)
Sets a block of memory to zero.
int32_t SDDS_FreeArrayDefinition(ARRAY_DEFINITION *source)
Frees memory allocated for an array definition.
int32_t SDDS_CheckDataset(SDDS_DATASET *SDDS_dataset, const char *caller)
Validates the SDDS dataset pointer.
Definition SDDS_utils.c:552
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:639
int32_t SDDS_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:856
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
int32_t SDDS_MPI_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, short column_major)
Initializes a copy of an SDDS dataset for MPI output.
int32_t SDDS_MPI_Terminate(SDDS_DATASET *SDDS_dataset)
Terminates the SDDS dataset by freeing all allocated resources and closing MPI files.
int32_t SDDS_MPI_WriteAsciiString(SDDS_DATASET *SDDS_dataset, char *string)
Writes an ASCII string to the SDDS dataset using MPI.
int32_t SDDS_MPI_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the layout of the SDDS dataset to the MPI file.
char * SDDS_CreateDataMode(DATA_MODE *data_mode)
Creates a data mode block for the SDDS layout.
void SDDS_MPI_Setup(SDDS_DATASET *SDDS_dataset, int32_t parallel_io, int32_t n_processors, int32_t myid, MPI_Comm comm, short master_read)
Sets up the SDDS dataset for MPI operations.
char * BlankToNull(char *string)
Converts a blank string to NULL.
char * SDDS_CreateParameterDefinition(PARAMETER_DEFINITION *parameter_definition)
Creates a parameter definition block for the SDDS layout.
int32_t SDDS_MPI_File_Open(MPI_DATASET *MPI_dataset, char *filename, unsigned long flags)
Opens an MPI file with the specified flags.
int32_t SDDS_MPI_ReconnectFile(SDDS_DATASET *SDDS_dataset)
Reconnects the MPI file associated with the SDDS dataset.
int32_t SDDS_MPI_DisconnectFile(SDDS_DATASET *SDDS_dataset)
Disconnects the MPI file associated with the SDDS dataset.
char * SDDS_CreateDescription(char *text, char *contents)
Creates a description block for the SDDS layout.
MPI_Datatype Convert_SDDStype_To_MPItype(int32_t SDDS_type)
Converts an SDDS data type to the corresponding MPI data type.
void SDDS_MPI_BOMB(char *text, MPI_File *mpi_file)
Terminates the program after handling errors and cleaning up MPI resources.
char * SDDS_CreateColumnDefinition(COLUMN_DEFINITION *column_definition)
Creates a column definition block for the SDDS layout.
int32_t SDDS_MPI_WritePage(SDDS_DATASET *SDDS_dataset)
Writes a page of data to the MPI file associated with the SDDS dataset.
char * SDDS_CreateAssociateDefinition(ASSOCIATE_DEFINITION *associate_definition)
Creates an associate definition block for the SDDS layout.
char * SDDS_CreateNamelistField(char *name, char *value)
Creates a namelist field string from a name and value.
void SDDS_MPI_GOTO_ERROR(FILE *fp, char *str, int32_t mpierr, int32_t exit_code)
Handles MPI errors by printing an error message and optionally exiting.
int32_t SDDS_MPI_InitializeOutput(SDDS_DATASET *SDDS_dataset, char *description, char *contents, char *filename, unsigned long flags, short column_major)
Initializes the SDDS dataset for MPI output.
char * SDDS_CreateArrayDefinition(ARRAY_DEFINITION *array_definition)
Creates an array definition block for the SDDS layout.
#define SDDS_ULONG
Identifier for the unsigned 32-bit integer data type.
Definition SDDStypes.h:67
#define SDDS_FLOAT
Identifier for the float data type.
Definition SDDStypes.h:43
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_ULONG64
Identifier for the unsigned 64-bit integer data type.
Definition SDDStypes.h:55
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_CHARACTER
Identifier for the character data type.
Definition SDDStypes.h:91
#define SDDS_USHORT
Identifier for the unsigned short integer data type.
Definition SDDStypes.h:79
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_LONGDOUBLE
Identifier for the long double data type.
Definition SDDStypes.h:31
#define SDDS_LONG64
Identifier for the signed 64-bit integer data type.
Definition SDDStypes.h:49