接入test_mql高密度事件窗口诊断
This commit is contained in:
1 parent
01b606df30
commit
f8af99ace1
4 files changed
+246
-33
No files matched your search
@@ -47,21 +47,32 @@ _DATA_PATH_RE = re.compile(r"Data_Path=(\S+)")
|
||||
_PARAM_ID_RE = re.compile(r"Param_Id=(\d+)")
|
||||
|
||||
|
||||
def load_test_mql_amesim_results(archive_path: str | Path) -> AmesimResults:
|
||||
def load_test_mql_amesim_results(
|
||||
archive_path: str | Path,
|
||||
*,
|
||||
time_stop_s: float | None = None,
|
||||
) -> AmesimResults:
|
||||
return load_amesim_results_from_archive(
|
||||
archive_path=archive_path,
|
||||
var_member="test_mql_.var",
|
||||
results_member="test_mql_.results",
|
||||
var_member=None,
|
||||
results_member=None,
|
||||
time_stop_s=time_stop_s,
|
||||
)
|
||||
|
||||
|
||||
def load_amesim_results_from_archive(
|
||||
*,
|
||||
archive_path: str | Path,
|
||||
var_member: str,
|
||||
results_member: str,
|
||||
var_member: str | None,
|
||||
results_member: str | None,
|
||||
time_stop_s: float | None = None,
|
||||
) -> AmesimResults:
|
||||
with tarfile.open(archive_path) as archive:
|
||||
var_member, results_member = _resolve_result_members(
|
||||
archive,
|
||||
var_member=var_member,
|
||||
results_member=results_member,
|
||||
)
|
||||
var_file = archive.extractfile(var_member)
|
||||
results_file = archive.extractfile(results_member)
|
||||
if var_file is None:
|
||||
@@ -69,11 +80,113 @@ def load_amesim_results_from_archive(
|
||||
if results_file is None:
|
||||
raise AmesimResultsError(f"Missing AMESim results member: {results_member}")
|
||||
var_lines = var_file.read().decode("latin1").splitlines()
|
||||
variables = tuple(
|
||||
_parse_variable_line(index, line) for index, line in enumerate(var_lines)
|
||||
)
|
||||
if time_stop_s is not None:
|
||||
return _parse_amesim_results_window(
|
||||
results_file,
|
||||
variables,
|
||||
time_stop_s=time_stop_s,
|
||||
)
|
||||
results_data = results_file.read()
|
||||
variables = tuple(_parse_variable_line(index, line) for index, line in enumerate(var_lines))
|
||||
return parse_amesim_results_bytes(results_data, variables)
|
||||
|
||||
|
||||
def _resolve_result_members(
|
||||
archive: tarfile.TarFile,
|
||||
*,
|
||||
var_member: str | None,
|
||||
results_member: str | None,
|
||||
) -> tuple[str, str]:
|
||||
member_names = set(archive.getnames())
|
||||
if var_member is not None or results_member is not None:
|
||||
if var_member is None or results_member is None:
|
||||
raise AmesimResultsError(
|
||||
"var_member and results_member must either both be set or both be omitted."
|
||||
)
|
||||
return var_member, results_member
|
||||
|
||||
preferred = ("test_mql_.var", "test_mql_.results")
|
||||
if preferred[0] in member_names and preferred[1] in member_names:
|
||||
return preferred
|
||||
|
||||
pairs = sorted(
|
||||
(name, f"{name[:-4]}.results")
|
||||
for name in member_names
|
||||
if name.endswith(".var") and f"{name[:-4]}.results" in member_names
|
||||
)
|
||||
if len(pairs) != 1:
|
||||
raise AmesimResultsError(
|
||||
"Unable to identify a unique AMESim .var/.results member pair."
|
||||
)
|
||||
return pairs[0]
|
||||
|
||||
|
||||
def _parse_amesim_results_window(
|
||||
results_file,
|
||||
variables: tuple[AmesimVariable, ...],
|
||||
*,
|
||||
time_stop_s: float,
|
||||
) -> AmesimResults:
|
||||
header = results_file.read(8)
|
||||
if len(header) < 8:
|
||||
raise AmesimResultsError("AMESim results data is too small.")
|
||||
point_count, encoded_saved_variable_count = struct.unpack("<2i", header)
|
||||
saved_variable_count = abs(encoded_saved_variable_count)
|
||||
if point_count <= 0 or saved_variable_count <= 0:
|
||||
raise AmesimResultsError("Invalid AMESim results header.")
|
||||
|
||||
mapping_data = results_file.read(saved_variable_count * 4)
|
||||
if len(mapping_data) != saved_variable_count * 4:
|
||||
raise AmesimResultsError("AMESim results variable mapping is truncated.")
|
||||
saved_variable_indices = struct.unpack(
|
||||
f"<{saved_variable_count}i",
|
||||
mapping_data,
|
||||
)
|
||||
if any(index < 0 or index >= len(variables) for index in saved_variable_indices):
|
||||
raise AmesimResultsError(
|
||||
"AMESim results variable mapping references unknown .var rows."
|
||||
)
|
||||
|
||||
row_length = 1 + saved_variable_count
|
||||
row_byte_count = row_length * 8
|
||||
times: list[float] = []
|
||||
series_lists: dict[str, list[float]] = {}
|
||||
saved_paths: list[tuple[int, str]] = []
|
||||
for column, variable_index in enumerate(saved_variable_indices, start=1):
|
||||
data_path = variables[variable_index].data_path
|
||||
if data_path is None:
|
||||
continue
|
||||
series_lists[data_path] = []
|
||||
saved_paths.append((column, data_path))
|
||||
|
||||
for _row_index in range(point_count):
|
||||
row = results_file.read(row_byte_count)
|
||||
if len(row) != row_byte_count:
|
||||
raise AmesimResultsError("AMESim results matrix is truncated.")
|
||||
time_s = struct.unpack_from("<d", row, 0)[0]
|
||||
times.append(time_s)
|
||||
for column, data_path in saved_paths:
|
||||
series_lists[data_path].append(
|
||||
struct.unpack_from("<d", row, column * 8)[0]
|
||||
)
|
||||
# Keep one real sample after the requested stop so endpoint finite
|
||||
# differences do not silently fall back to a backward-only slope.
|
||||
if time_s > time_stop_s + 1.0e-12:
|
||||
break
|
||||
|
||||
return AmesimResults(
|
||||
times=tuple(times),
|
||||
variables=variables,
|
||||
saved_variable_indices=tuple(saved_variable_indices),
|
||||
series_by_data_path={
|
||||
data_path: tuple(values) for data_path, values in series_lists.items()
|
||||
},
|
||||
final_values_by_data_path={},
|
||||
)
|
||||
|
||||
|
||||
def parse_amesim_results_bytes(
|
||||
results_data: bytes,
|
||||
variables: tuple[AmesimVariable, ...],
|
||||
|
||||
Reference in new issue
Block a user