SIwave log parser – pyedb.workflows.utilities.siwave_log_parser#

SIwave log file parser for extracting simulation results and metrics.

This module provides tools to parse Ansys SIwave batch simulation logs into structured dataclasses, making it easy to extract timing information, warnings, profile data, and simulation status.

Examples#

Basic usage for parsing a SIwave log file:

>>> from pyedb.workflows.utilities.siwave_log_parser import SiwaveLogParser
>>> parser = SiwaveLogParser(r"C:\path  o\siwave.log")
>>> log = parser.parse()
>>> log.summary()
>>> log.to_json("siwave.json")

Check simulation completion status:

>>> if log.is_completed():
...     print("Simulation completed successfully")
... else:
...     print("Simulation failed or was aborted")

Overview#

The SIwave log parser extracts structured data from Ansys SIwave batch solve logs, including version information, batch execution metadata, simulation settings, warnings, profiling data, and completion status.

Key Features:

  • Automatic detection of simulation completion status (Normal Completion vs. Aborted)

  • Extraction of electrical short warnings with precise coordinates

  • Performance profiling data (timing, memory usage)

  • Support for multiple timestamp formats

  • JSON export capability

Quick start#

Basic usage:

from pyedb.workflows.utilities.siwave_log_parser import SiwaveLogParser

# Parse a SIwave log file
parser = SiwaveLogParser("path/to/siwave.log")
log = parser.parse()

# Check simulation status
if log.is_completed():
    print(f"✓ Simulation completed successfully")
else:
    print(f"✗ Simulation failed or was aborted")

# Display summary
log.summary()

# Export to JSON
log.to_json("results.json", indent=2)

Top-level façade#

class pyedb.workflows.utilities.siwave_log_parser.SiwaveLogParser(log_path: str | Path)#

Bases: object

High-level parser that orchestrates all block parsers.

This class provides the main interface for parsing SIwave log files. It coordinates multiple specialized parsers to extract version info, batch metadata, simulation settings, warnings, and profile data.

Parameters:
log_pathstr or pathlib.Path

Path to the SIwave log file to parse.

Examples

Basic usage:

>>> from pyedb.workflows.utilities.siwave_log_parser import SiwaveLogParser
>>> parser = SiwaveLogParser("/tmp/siwave.log")
>>> log = parser.parse()
>>> log.summary()
Project : my_design
Run by  : engineer
...

Check for warnings:

>>> parser = SiwaveLogParser("simulation.log")
>>> log = parser.parse()
>>> if log.warnings:
...     print(f"Found {len(log.warnings)} warnings")
...     for w in log.warnings[:3]:
...         print(f"  {w.category}: {w.message}")

Export to JSON:

>>> parser = SiwaveLogParser("simulation.log")
>>> log = parser.parse()
>>> log.to_json("output.json", indent=2)
parse() ParsedSiwaveLog#

Execute all sub-parsers and return a unified object.

Returns:
ParsedSiwaveLog

Structured representation of the entire log including version info, batch metadata, settings, warnings, and profile data.

Examples

Parse and check completion:

>>> parser = SiwaveLogParser("siwave.log")
>>> log = parser.parse()
>>> if log.is_completed():
...     print("Simulation completed successfully")
... else:
...     print("Simulation did not complete")

Access profile data:

>>> parser = SiwaveLogParser("siwave.log")
>>> log = parser.parse()
>>> for entry in log.profile:
...     print(f"{entry.task}: {entry.real_time}")

Aggregated result object#

class pyedb.workflows.utilities.siwave_log_parser.ParsedSiwaveLog(aedt: ~pyedb.workflows.utilities.siwave_log_parser.AEDTVersion, batch: ~pyedb.workflows.utilities.siwave_log_parser.BatchInfo, settings: ~pyedb.workflows.utilities.siwave_log_parser.SimSettings, warnings: list[~pyedb.workflows.utilities.siwave_log_parser.WarningEntry] = <factory>, profile: list[~pyedb.workflows.utilities.siwave_log_parser.ProfileEntry] = <factory>)#

Bases: object

Root container returned by SiwaveLogParser.parse().

This class holds all parsed information from a SIwave log file and provides convenience methods for checking completion status, generating summaries, and exporting data.

Attributes:
aedtAEDTVersion

AEDT version information extracted from log header.

batchBatchInfo

Batch run metadata including timestamps and user info.

settingsSimSettings

Simulation settings and configuration.

warningslist of WarningEntry

Warning entries from the log. The default is an empty list.

profilelist of ProfileEntry

Profile/timing entries showing task performance. The default is an empty list.

Examples

>>> from datetime import datetime
>>> from pathlib import Path
>>> log = ParsedSiwaveLog(
...     aedt=AEDTVersion(version="2025.1", build="123", location="C:\AEDT"),
...     batch=BatchInfo(
...         path="C:\project\test.siw",
...         started=datetime(2025, 11, 10, 9, 0, 0),
...         stopped=datetime(2025, 11, 10, 10, 0, 0),
...         run_by="engineer",
...         temp_dir="C:\temp",
...         project_dir="C:\project",
...         status="Normal Completion",
...     ),
...     settings=SimSettings(
...         design_type="SIwave",
...         allow_off_core=True,
...         manual_settings=False,
...         two_level=False,
...         distribution_types=["Local"],
...         machines=[],
...     ),
... )
>>> log.is_completed()
True
is_aborted() bool#

Check if the simulation was aborted.

Returns:
bool

True if simulation did not complete normally, False otherwise.

Examples

>>> log = ParsedSiwaveLog(
...     aedt=AEDTVersion("2025.1", "123", "C:\AEDT"),
...     batch=BatchInfo(
...         path="test.siw",
...         started=datetime(2025, 1, 1),
...         stopped=datetime(2025, 1, 1),
...         run_by="user",
...         temp_dir="",
...         project_dir="",
...         status="Aborted",
...     ),
...     settings=SimSettings("", False, False, False, [], []),
... )
>>> log.is_aborted()
True
is_completed() bool#

Check if the simulation completed normally.

Returns:
bool

True if status is 'Normal Completion', False otherwise.

Examples

>>> log = ParsedSiwaveLog(
...     aedt=AEDTVersion("2025.1", "123", "C:\AEDT"),
...     batch=BatchInfo(
...         path="test.siw",
...         started=datetime(2025, 1, 1),
...         stopped=datetime(2025, 1, 1),
...         run_by="user",
...         temp_dir="",
...         project_dir="",
...         status="Normal Completion",
...     ),
...     settings=SimSettings("", False, False, False, [], []),
... )
>>> log.is_completed()
True
summary() None#

Print a summary of the parsed log to stdout.

Examples

>>> log = ParsedSiwaveLog(aedt=..., batch=..., settings=...)
>>> log.summary()
Project : test_design
Run by  : engineer
Started : Mon Nov 10 09:00:00 2025
Stopped : Mon Nov 10 10:00:00 2025
Status  : Normal Completion
Warnings: 0
Profile entries: 0
to_dict() dict#

Deep-convert the entire object to JSON-serializable primitives.

Returns:
dict

Plain dict/list/scalar structure suitable for JSON serialization.

Examples

>>> log = ParsedSiwaveLog(aedt=..., batch=..., settings=...)
>>> data_dict = log.to_dict()
>>> isinstance(data_dict, dict)
True
>>> "aedt" in data_dict
True
to_json(fp: str, **kw) None#

Serialize parsed log to JSON file.

Parameters:
fpstr

File path to write JSON to.

**kw

Additional keyword arguments passed to json.dumps().

Examples

>>> log = ParsedSiwaveLog(aedt=..., batch=..., settings=...)
>>> log.to_json("output.json", indent=2)

Data containers#

Version information#

class pyedb.workflows.utilities.siwave_log_parser.AEDTVersion(version: str, build: str, location: str)#

Bases: object

AEDT version information extracted from log header.

Attributes:
versionstr

AEDT version number (e.g., '2025.1').

buildstr

Build identifier.

locationstr

Installation path of AEDT.

Examples

>>> version = AEDTVersion(version="2025.1", build="12345", location="C:\Program Files\AnsysEM")
>>> version.version
'2025.1'

Batch execution metadata#

class pyedb.workflows.utilities.siwave_log_parser.BatchInfo(path: str, started: datetime, stopped: datetime, run_by: str, temp_dir: str, project_dir: str, status: str = '')#

Bases: object

Batch simulation run metadata.

Attributes:
pathstr

Full path to the project file.

starteddatetime

Simulation start timestamp.

stoppeddatetime

Simulation stop timestamp.

run_bystr

Username who executed the simulation.

temp_dirstr

Temporary directory used during simulation.

project_dirstr

Project working directory.

statusstr, optional

Simulation completion status such as 'Normal Completion' or 'Aborted'. The default is "".

Examples

>>> from datetime import datetime
>>> batch = BatchInfo(
...     path="C:\project\design.siw",
...     started=datetime(2025, 11, 10, 9, 0, 0),
...     stopped=datetime(2025, 11, 10, 10, 30, 0),
...     run_by="engineer",
...     temp_dir="C:\temp",
...     project_dir="C:\project",
...     status="Normal Completion",
... )
>>> batch.status
'Normal Completion'

Simulation settings#

class pyedb.workflows.utilities.siwave_log_parser.SimSettings(design_type: str, allow_off_core: bool, manual_settings: bool, two_level: bool, distribution_types: list[str], machines: list[str])#

Bases: object

Simulation settings and configuration.

Attributes:
design_typestr

Type of design being simulated.

allow_off_corebool

Whether off-core solving is enabled.

manual_settingsbool

Whether manual settings are being used.

two_levelbool

Whether two-level solving is enabled.

distribution_typeslist of str

Distribution types configured for the simulation.

machineslist of str

Machine specifications (RAM, cores, etc.).

Examples

>>> settings = SimSettings(
...     design_type="SIwave",
...     allow_off_core=True,
...     manual_settings=False,
...     two_level=True,
...     distribution_types=["Local"],
...     machines=["localhost RAM: 32GB"],
... )
>>> settings.allow_off_core
True

Warning entries#

class pyedb.workflows.utilities.siwave_log_parser.WarningEntry(timestamp: datetime, category: str, net1: str, net2: str, layer: str, x: float, y: float, message: str)#

Bases: object

Single warning message from the simulation log.

Attributes:
timestampdatetime

When the warning occurred.

categorystr

Warning category: 'SHORT' for electrical shorts or 'OTHER' for other warnings.

net1str

First net involved (for SHORT warnings).

net2str

Second net involved (for SHORT warnings).

layerstr

Layer name where the issue occurred.

xfloat

X-coordinate in millimeters.

yfloat

Y-coordinate in millimeters.

messagestr

Complete warning message text.

Examples

>>> from datetime import datetime
>>> warning = WarningEntry(
...     timestamp=datetime(2025, 11, 10, 9, 15, 30),
...     category="SHORT",
...     net1="VCC",
...     net2="GND",
...     layer="TOP",
...     x=12.5,
...     y=34.8,
...     message="Nets are electrically shorted",
... )
>>> warning.category
'SHORT'

Profile entries#

class pyedb.workflows.utilities.siwave_log_parser.ProfileEntry(timestamp: ~datetime.datetime, task: str, real_time: str | None = None, cpu_time: str | None = None, memory: str | None = None, extra: dict[str, str] = <factory>)#

Bases: object

Performance profile entry showing task timing and resource usage.

Attributes:
timestampdatetime

When the task completed.

taskstr

Task or operation name.

real_timestr, optional

Wall clock time in human-readable format. The default is None.

cpu_timestr, optional

CPU time consumed. The default is None.

memorystr, optional

Peak memory usage. The default is None.

extradict of str to str, optional

Additional metrics (e.g., number of elements). The default is an empty dict.

Examples

>>> from datetime import datetime
>>> profile = ProfileEntry(
...     timestamp=datetime(2025, 11, 10, 9, 30, 0),
...     task="Mesh Generation",
...     real_time="00:05:30",
...     cpu_time="00:05:25",
...     memory="2.5 GB",
...     extra={"Number of elements": "50000"},
... )
>>> profile.task
'Mesh Generation'

Block parsers (advanced usage)#

These parsers handle specific sections of the log file. Most users does not need to use them directly, as they are orchestrated by SiwaveLogParser.

class pyedb.workflows.utilities.siwave_log_parser.HeaderBlockParser(lines: list[str])#

Bases: BlockParser

Extract AEDT version information from the log header.

This parser searches through log lines to find version, build, and installation location information.

Examples

>>> lines = [
...     "ANSYS Electromagnetics Suite Version 2025.1 Build: 12345",
...     "Location: C:\Program Files\AnsysEM\v251",
... ]
>>> parser = HeaderBlockParser(lines)
>>> version = parser.parse()
>>> version.version
'2025.1'
parse() AEDTVersion#

Parse the stored lines and return an AEDTVersion instance.

Returns:
AEDTVersion

Populated version data object containing version, build, and location.

Examples

>>> lines = ["Version 2025.1 Build: 12345", "Location: C:\AnsysEM"]
>>> parser = HeaderBlockParser(lines)
>>> info = parser.parse()
>>> info.build
'12345'
class pyedb.workflows.utilities.siwave_log_parser.BatchSettingsBlockParser(lines: list[str])#

Bases: BlockParser

Extract batch information and simulation settings from the log.

This parser processes batch run metadata including timestamps, user info, directories, and simulation configuration settings.

Examples

>>> lines = [
...     "Batch Solve/Save: C:\project\design.siw",
...     "Starting Batch Run: 11/10/2025 09:00:00 AM",
...     "Running as user : engineer",
...     "Design type: SIwave",
...     "Allow off core: True",
... ]
>>> parser = BatchSettingsBlockParser(lines)
>>> batch, settings = parser.parse()
>>> batch.run_by
'engineer'
>>> settings.design_type
'SIwave'
parse() tuple[BatchInfo, SimSettings]#

Parse batch information and simulation settings.

Returns:
tuple[BatchInfo, SimSettings]

Tuple containing batch run metadata and simulation settings.

Examples

>>> lines = ["Batch Solve/Save: test.siw", "Design type: SIwave"]
>>> parser = BatchSettingsBlockParser(lines)
>>> batch, settings = parser.parse()
>>> isinstance(batch, BatchInfo)
True
>>> isinstance(settings, SimSettings)
True
class pyedb.workflows.utilities.siwave_log_parser.WarningsBlockParser(lines: list[str])#

Bases: BlockParser

Extract warning entries from the simulation log.

This parser identifies and extracts warning messages, particularly focusing on electrical short warnings with location information.

Examples

>>> lines = [
...     "11/10/2025 09:15:30 AM [warning] Geometry on nets VCC and GND on layer \"TOP\" "
...     "are electrically shorted at approximately (12.5, 34.8)mm"
... ]
>>> parser = WarningsBlockParser(lines)
>>> warnings = parser.parse()
>>> warnings[0].category
'SHORT'
>>> warnings[0].net1
'VCC'
parse() list[WarningEntry]#

Parse warning messages from log lines.

Returns:
list of WarningEntry

List of parsed warning entries with categorization and location data.

Examples

>>> lines = ["No warnings"]
>>> parser = WarningsBlockParser(lines)
>>> warnings = parser.parse()
>>> len(warnings)
0
class pyedb.workflows.utilities.siwave_log_parser.ProfileBlockParser(lines: list[str])#

Bases: BlockParser

Extract profile entries showing task timing and resource usage.

This parser processes [PROFILE] tagged lines to extract performance metrics including real time, CPU time, memory usage, and additional task-specific data.

Examples

>>> lines = [
...     "11/10/2025 09:30:00 AM [PROFILE] Mesh Generation : Real Time 00:05:30 : "
...     "CPU Time 00:05:25 : Memory 2.5 GB : Number of elements: 50000"
... ]
>>> parser = ProfileBlockParser(lines)
>>> profiles = parser.parse()
>>> profiles[0].task
'Mesh Generation'
>>> profiles[0].real_time
'00:05:30'
parse() list[ProfileEntry]#

Parse profile entries showing task timing and resource usage.

Returns:
list of ProfileEntry

List of profile entries with timing and resource consumption data.

Examples

>>> lines = ["Regular log line without profile"]
>>> parser = ProfileBlockParser(lines)
>>> profiles = parser.parse()
>>> len(profiles)
0

Base class#

class pyedb.workflows.utilities.siwave_log_parser.BlockParser(lines: list[str])#

Bases: object

Base class for a single block parser.

Parameters:
lineslist of str

Lines of text to parse from the log file.

Examples

>>> lines = ["Line 1", "Line 2", "Line 3"]
>>> parser = BlockParser(lines)
>>> parser.lines
['Line 1', 'Line 2', 'Line 3']
parse() Any#

Parse the stored lines.

Returns:
Any

Parsed data structure.

Utility helpers#

The functions below are private by convention (leading underscore) but are exposed in the documentation for contributors and advanced users.

pyedb.workflows.utilities.siwave_log_parser._parse_ts(txt: str) datetime#

Convert timestamp strings to datetime objects.

Parse timestamp strings in two different SIwave log formats and return a datetime object. Supports both date-first and time-first formats.

Parameters:
txtstr

Timestamp string from SIwave log. Supports two formats:

  • Date-first: '11/10/2025 05:46:09 PM'

  • Time-first: '11:55:29 AM  Oct 12, 2025'

Returns:
datetime

Parsed datetime object.

Examples

>>> _parse_ts("11/10/2025 05:46:09 PM")
datetime.datetime(2025, 11, 10, 17, 46, 9)
>>> _parse_ts("11:55:29 AM  Oct 12, 2025")
datetime.datetime(2025, 10, 12, 11, 55, 29)
>>> try:
...     _parse_ts("invalid timestamp")
... except ValueError as e:
...     print("Cannot parse")
Cannot parse
pyedb.workflows.utilities.siwave_log_parser._split_kv(line: str, sep: str = ':') tuple[str, str]#

Split a key-value line into key and value strings.

Parse lines in the format 'key: value' and return a tuple of the stripped key and value parts.

Parameters:
linestr

Input line containing a separator.

sepstr, optional

Separator character. The default is ":".

Returns:
tuple[str, str]

Tuple of (key, value) with whitespace stripped from both.

Examples

>>> _split_kv("Real Time: 00:05:30")
('Real Time', '00:05:30')
>>> _split_kv("Number of cores=4", sep="=")
('Number of cores', '4')
>>> _split_kv("Status:  Normal Completion")
('Status', 'Normal Completion')
pyedb.workflows.utilities.siwave_log_parser._as_dict(obj: Any) Any#

Recursively convert dataclasses to JSON-serializable primitives.

Convert dataclass instances, lists, and Path objects to plain Python types that can be serialized to JSON.

Parameters:
objAny

Object to convert. Can be a dataclass, list, Path, or primitive type.

Returns:
Any

Plain Python representation. Dataclasses become dicts, Paths become strings, lists are recursively processed, and primitives pass through.

Examples

>>> from dataclasses import dataclass
>>> from pathlib import Path
>>> @dataclass
... class Sample:
...     name: str
...     value: int
>>> _as_dict(Sample("test", 42))
{'name': 'test', 'value': 42}
>>> _as_dict(Path("/tmp/file.txt"))
'/tmp/file.txt'
>>> _as_dict([1, 2, Path("/test"), "hello"])
[1, 2, '/test', 'hello']

Examples#

Check simulation completion status#

from pyedb.workflows.utilities.siwave_log_parser import SiwaveLogParser

parser = SiwaveLogParser("siwave.log")
log = parser.parse()

if log.is_completed():
    print("Status:", log.batch.status)
    print("Runtime:", log.batch.stopped - log.batch.started)
else:
    print("Simulation was aborted or failed")

Extract warnings#

parser = SiwaveLogParser("siwave.log")
log = parser.parse()

# Get all electrical short warnings
shorts = [w for w in log.warnings if w.category == "SHORT"]

for warning in shorts:
    print(f"Short between {warning.net1} and {warning.net2}")
    print(f"  Layer: {warning.layer}")
    print(f"  Location: ({warning.x:.3f}, {warning.y:.3f}) mm")

Analyze performance#

parser = SiwaveLogParser("siwave.log")
log = parser.parse()

# Display profiling information
for entry in log.profile:
    print(f"Task: {entry.task}")
    print(f"  Real Time: {entry.real_time}")
    print(f"  CPU Time: {entry.cpu_time}")
    print(f"  Memory: {entry.memory}")

Batch processing#

from pathlib import Path
from pyedb.workflows.utilities.siwave_log_parser import SiwaveLogParser

# Process multiple log files
log_dir = Path("simulation_results")
completed = []
failed = []

for log_file in log_dir.glob("**/*.log"):
    try:
        parser = SiwaveLogParser(log_file)
        log = parser.parse()

        if log.is_completed():
            completed.append(
                {
                    "project": log.batch.path,
                    "warnings": len(log.warnings),
                    "runtime": (log.batch.stopped - log.batch.started).total_seconds(),
                }
            )
        else:
            failed.append({"project": log.batch.path, "status": log.batch.status})
    except Exception as e:
        print(f"Failed to parse {log_file}: {e}")

print(f"Completed: {len(completed)}, Failed: {len(failed)}")

Export to JSON#

parser = SiwaveLogParser("siwave.log")
log = parser.parse()

# Export with pretty formatting
log.to_json("results.json", indent=2)

# Convert to dictionary for further processing
data = log.to_dict()

See also#