Read a real64 PETSc binary VecView payload.
16def read_petsc_vec_binary(path: str, numpy, index_bytes: int = 4, label: str = "field file"):
17 """!
18 @brief Read a real64 PETSc binary VecView payload.
19 @details The header's class id and count are PetscInt of `index_bytes`, the width of the
20 PETSc that wrote the file, which the file does not record. Either byte order is
21 accepted, with or without the class id; the file length must match exactly.
22 @param[in] path PETSc binary vector path.
23 @param[in] numpy The caller's numpy module.
24 @param[in] index_bytes Bytes of a PetscInt in the writing PETSc, 4 or 8.
25 @param[in] label How the caller names the file in errors.
26 @return NumPy array of scalar values.
27 """
28 if not os.path.isfile(path):
29 raise ValueError(f"{label} not found: {path}")
30 data = open(path, "rb").read()
31 word, code = index_bytes, "i" if index_bytes == 4 else "q"
32 if len(data) < 2 * word:
33 raise ValueError(f"{label} '{path}' is too short to be a PETSc Vec binary.")
34 candidates = []
35 for endian in (">", "<"):
36 _class_id, vec_size = struct.unpack(endian + 2 * code, data[:2 * word])
37 if vec_size > 0 and len(data) == 2 * word + vec_size * 8:
38 candidates.append((endian, vec_size, 2 * word))
39 (vec_size_no_class,) = struct.unpack(endian + code, data[:word])
40 if vec_size_no_class > 0 and len(data) == word + vec_size_no_class * 8:
41 candidates.append((endian, vec_size_no_class, word))
42 if not candidates:
43 raise ValueError(
44 f"{label} '{path}' does not match a PETSc real64 Vec binary with "
45 f"{index_bytes}-byte indices; a file from the other index width does not fit."
46 )
47 endian, vec_size, offset = candidates[0]
48 values = numpy.frombuffer(data, dtype=numpy.dtype(endian + "f8"), count=vec_size, offset=offset)
49 return values.astype(float, copy=False)