Peano
Loading...
Searching...
No Matches
merge.py
Go to the documentation of this file.
1# This file is part of the Peano project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3"""!
4
5Merge the partial patch files of a Peano simulation
6
7A parallel run writes one patch file per spacetree (and rank) and snapshot.
8The script merges the files of each snapshot into one file, and writes a new
9meta file merged_meta_file.peano-patch-file next to the original one which
10links to the merged files. It handles files with ASCII and with binary
11quantities. Call it with
12
13 python3 -m tarch.plotter.api.merge --meta-file solution-Euler.peano-patch-file
14
15@ref documentation_tarch_visualisation_merging-data
16
17"""
18import os
19import argparse
20
21
22def merge_partial_files(partial_files, merged_file_path):
23 """!
24
25 Merge the patches of several patch files into one file
26
27 The files are processed as bytes. A file with format Binary holds raw
28 doubles between its text lines, and we copy those verbatim. The header
29 of the merged file is the header of the first partial file, i.e. all
30 partial files have to have the same format. Everything from the first
31 "begin patch" in a file on is a patch, and everything before it is the
32 header: A header holds text only, so the first occurrence is the right
33 one, even in a binary file.
34
35 @param partial_files: [str]
36 Files to merge. Their patches end up in the merged file in this order.
37
38 @param merged_file_path: str
39 File to write.
40
41 """
42 print("Start to merge file:", merged_file_path, end="...")
43 patch_marker = b"begin patch"
44
45 with open(merged_file_path, "wb") as merged_patch_file:
46 # First we need to write the header for our new patch
47 # file. We can open any of the partial patch files
48 # and pass this across
49 with open(partial_files[0], "rb") as patch_file:
50 content = patch_file.read()
51 first_patch = content.find(patch_marker)
52 merged_patch_file.write(content if first_patch < 0 else content[:first_patch])
53
54 for infile in partial_files:
55 with open(infile, "rb") as patch_file:
56 content = patch_file.read()
57 first_patch = content.find(patch_marker)
58 if first_patch >= 0:
59 merged_patch_file.write(b"\n")
60 merged_patch_file.write(content[first_patch:])
61 print("Merged.")
62
63
64def read_meta_file(path_to_metafile, start, end):
65 # merged_files = [] # Stores names of merged files
66 partial_files = [] # Stores partial files that need to be merged
67 # into the same file
68 # timestamps = []
69 merged_file_number = 0
70
71 f = open(
72 os.path.join(
73 os.path.dirname(path_to_metafile), "merged_meta_file.peano-patch-file"
74 ),
75 "w",
76 )
77 f.write(
78 "# \n" "# Peano patch file \n" "# Version 0.2 \n" "# \n" "format ASCII \n" "\n"
79 )
80
81 with open(path_to_metafile, "r") as metafile:
82 for line in metafile.readlines():
83 if "end dataset" in line and (
84 merged_file_number < start or merged_file_number > end
85 ):
86 partial_files.clear()
87 print("jump snapshot", merged_file_number)
88 merged_file_number += 1
89 elif "end dataset" in line:
90 # Merged files will be put in the same dir as the original meta-file
91 merged_file_name = (
92 "merged_patch_file_" + str(merged_file_number) + ".peano-patch-file"
93 )
94
95 if os.path.isabs(path_to_metafile):
96 merged_file_name = os.path.join(
97 os.path.dirname(path_to_metafile), merged_file_name
98 )
99
100 merge_partial_files(partial_files, merged_file_name)
101
102 partial_files.clear()
103 merged_file_number += 1
104 print()
105
106 f.write(
107 "begin dataset\n" + timestamp_line + "\n"
108 f' include "{merged_file_name}"\n'
109 "end dataset\n"
110 "\n"
111 )
112
113 if "timestamp" in line and merged_file_number >= start:
114 timestamp_line = line
115 print(line[0:-2])
116
117 words = line.split()
118
119 if "include" in words:
120 file_path = words[1].strip('"') # This is the input path
121
122 # Where the filepath listed in the meta-file is not
123 # an absolute path with assume the file lives in the
124 # same directory as the meta-file itself:
125 if not os.path.isabs(file_path):
126 file_path = os.path.join(
127 os.path.dirname(path_to_metafile), file_path
128 )
129
130 partial_files.append(file_path)
131
132 f.close()
133
134
135def count_total_snapshot_number(path_to_metafile):
136 count = 0
137 with open(path_to_metafile, "r") as metafile:
138 for line in metafile.readlines():
139 if "timestamp" in line:
140 count += 1
141 return count
142
143
144if __name__ == "__main__":
145 parser = argparse.ArgumentParser(
146 description="Peano 4 - Merge partial patch files "
147 "that are linked to by a meta file"
148 )
149 parser.add_argument(
150 "--meta-file",
151 dest="metafile",
152 help="The main file that links to a set of Peano patch files",
153 required=True,
154 )
155 parser.add_argument(
156 "-start",
157 "--start-snapshot-index",
158 dest="start",
159 type=int,
160 help="Set the snapshot number where the merge starts (all snapshots before will be ignored), default is 0 (starts from beginning)",
161 default=0,
162 )
163 parser.add_argument(
164 "-end",
165 "--end-snapshot-index",
166 dest="end",
167 type=int,
168 help="Set the snapshot number where the merge ends (all snapshots after will be ignored), default is -1 (ends at the last)",
169 default=-1,
170 )
171
172 args = parser.parse_args()
173
174 if not os.path.exists(args.metafile):
175 raise Exception(
176 "specified input file '{}' does not exist, exiting...".format(args.metafile)
177 )
178
179 total_snapshot_number = count_total_snapshot_number(args.metafile)
180 if (args.start > args.end and args.end != -1) or args.start < 0 or args.end < -1:
181 raise Exception("Specified snapshot index is wrong, please check.")
182 elif args.end == -1:
183 start_snapshot = args.start
184 end_snapshot = (
185 total_snapshot_number - 1
186 ) # Processing all snapshot if no end snapshot is specified.
187 elif args.end > (total_snapshot_number - 1):
188 start_snapshot = args.start
189 end_snapshot = total_snapshot_number - 1
190 print(
191 "Warning: specified end snapshot index exceeds the total number, reset to the last snapshot."
192 )
193 else:
194 start_snapshot = args.start
195 end_snapshot = args.end
196
197 print(
198 "The meta file includes",
199 total_snapshot_number,
200 "snapshots, processing snapshot",
201 start_snapshot,
202 "to",
203 end_snapshot,
204 )
205
206 read_meta_file(args.metafile, start_snapshot, end_snapshot)
merge_partial_files(partial_files, merged_file_path)
Merge the patches of several patch files into one file.
Definition merge.py:22
read_meta_file(path_to_metafile, start, end)
Definition merge.py:64
count_total_snapshot_number(path_to_metafile)
Definition merge.py:135