PhaseFieldX Logging Capabilities: A Complete Guide to Simulation Tracing and Reproducibility

PhaseFieldX provides comprehensive logging capabilities through Python's built-in logging module, creating a dedicated simulation_logger that writes structured execution traces to simulation.log in the results folder, capturing system metadata, library versions, input parameters, solver convergence, and timing information for full reproducibility.

PhaseFieldX implements a structured logging system designed for scientific reproducibility and debugging. According to the source code in castillonmiguel/phasefieldx, every simulation run generates a persistent text record that captures the complete computational environment, configuration parameters, and runtime progress in a single, human-readable file.

Centralized Logger Architecture

The logging system revolves around a single simulation logger named simulation_logger that is configured once per analysis and shared across all components.

The set_logger Factory Function

The function set_logger in [src/phasefieldx/Logger/library_versions.py](https://github.com/castillonmiguel/phasefieldx/blob/main/src/phasefieldx/Logger/library_versions.py) creates and configures the logger:

import logging
import os

def set_logger(result_folder_name):
    logger = logging.getLogger('simulation_logger')
    if logger.hasHandlers():
        for handler in logger.handlers:
            logger.removeHandler(handler)
    logger.setLevel(logging.INFO)
    
    simulation_file_handler = logging.FileHandler(
        os.path.join(result_folder_name, 'simulation.log'))
    simulation_formatter = logging.Formatter('%(message)s')
    simulation_file_handler.setFormatter(simulation_formatter)
    logger.addHandler(simulation_file_handler)
    
    return logger

Key characteristics:

  • Output location: <results_folder>/simulation.log
  • Log level: INFO (captures standard operation while allowing optional DEBUG granularity)
  • Format: Plain %(message)s without timestamps, since the code adds its own temporal metadata
  • Singleton pattern: Removes existing handlers to prevent duplicate log entries in repeated runs

System and Library Metadata Capture

Immediately after initialization, PhaseFieldX records three categories of environmental metadata to ensure reproducibility across different machines and software versions.

Environment Information with log_system_info

The log_system_info function (lines 91–115 in [library_versions.py](https://github.com/castillonmiguel/phasefieldx/blob/main/src/phasefieldx/Logger/library_versions.py#L91-L115)) logs:

  • Operating system and architecture
  • User name and machine type
  • Processor details
  • Python version

Dependency Version Tracking with log_library_versions

The log_library_versions function (lines 62–88) records critical library versions for dependency verification:

  • PhaseFieldX version
  • DolfinX version
  • ufl, basix, and numpy versions
  • logging module version

These calls are typically chained right after logger creation in solver entry points:

logger = set_logger(result_folder_name)
log_system_info(logger)
log_library_versions(logger)

Simulation Configuration Logging

Beyond environment metadata, PhaseFieldX captures user-defined simulation parameters through a standardized interface across all physics modules.

Input Class save_log_info Methods

Every simulation input class (Phase-Field, Elasticity, Allen-Cahn) implements a save_log_info(self, logger) method that writes domain-specific parameters. For example, in [src/phasefieldx/Element/Phase_Field/Input.py](https://github.com/castillonmiguel/phasefieldx/blob/main/src/phasefieldx/Element/Phase_Field/Input.py#L52-L61):

def save_log_info(self, logger):
    logger.info("Parameters:")
    logger.info(f"  l: {self.l}")

The Elasticity and Allen-Cahn input classes follow this identical pattern in [src/phasefieldx/Element/Elasticity/Input.py](https://github.com/castillonmiguel/phasefieldx/blob/main/src/phasefieldx/Element/Elasticity/Input.py) and [src/phasefieldx/Element/Allen_Cahn/Input.py](https://github.com/castillonmiguel/phasefieldx/blob/main/src/phasefieldx/Element/Allen_Cahn/Input.py), respectively.

Mesh Metadata with log_model_information

The log_model_information function (lines 127–131 in library_versions.py) records geometric data such as mesh dimension, linking the computational domain properties to the specific run:

log_model_information(msh, logger)

Runtime Execution Monitoring

During the solution phase, solvers emit granular progress messages that enable debugging of convergence behavior and performance bottlenecks.

Newton Solver Convergence Logging

The Newton solver in [src/phasefieldx/solvers/newton.py](https://github.com/castillonmiguel/phasefieldx/blob/main/src/phasefieldx/solvers/newton.py#L54-L71) implements save_log_info to record:

  • Newton and Krylov tolerances
  • Maximum iteration limits
  • Convergence criteria

Phase-Field Fracture Solver Tracing

The variational solver in [src/phasefieldx/Element/Phase_Field_Fracture/solver/solver_ener_variational.py](https://github.com/castillonmiguel/phasefieldx/blob/main/src/phasefieldx/Element/Phase_Field_Fracture/solver/solver_ener_variational.py#L277-L336) logs comprehensive execution data within each time step:

  • Analysis boundaries: "S t a r t i n g A n a l y s i s" markers
  • Physical quantities: Gamma0, tau(t), and time-step adjustments
  • Convergence tracking: Newton iteration counts and residual norms
  • I/O operations: XDMF and VTU file saving events

Example runtime logging pattern:

if rank == 0 and logger:
    logger.info(f"\n\nGamma0 = {gamma0}")
    logger.info(f" start time: {start}")
    logger.info(" S t a r t i n g    A n a l y s i s ")
    # ... during iterations ...

    logger.info(f"Newton iterations: {newton_iterations}")
    logger.info(f"Residual norm: {residual_norm}")

DolfinX Integration

PhaseFieldX also captures messages from the underlying finite-element library by setting the DolfinX C++ logger to INFO level:

dolfinx.log.set_log_level(dolfinx.log.LogLevel.INFO)

This appears in solver files such as solver_ener_variational.py (line 135), ensuring that low-level library warnings and convergence diagnostics appear in the same log stream.

End-of-Run Summary and Cleanup

When simulations complete, log_end_analysis (lines 119–125 in library_versions.py) writes a structured summary block:

def log_end_analysis(logger, totaltime=0.0):
    logger.info("\n\n\n ====================================================")
    logger.info("\n\n End of computations")
    logger.info(" Analysis finished correctly.")
    logger.info(f" total simulation time: {totaltime}")
    logger.info("Analysis finished on %s" % time.strftime('%a %b %d %H:%M:%S %Y',
                                                          time.localtime()))

This provides a clear termination marker and wall-clock timing for benchmarking.

Complete Implementation Example

The following pattern demonstrates the full logging lifecycle as implemented in [src/phasefieldx/Element/Phase_Field_Fracture/solver/solver.py](https://github.com/castillonmiguel/phasefieldx/blob/main/src/phasefieldx/Element/Phase_Field_Fracture/solver/solver.py):

from phasefieldx.Logger.library_versions import (
    set_logger, log_system_info, log_library_versions,
    log_model_information, log_end_analysis
)
from phasefieldx.Element.Phase_Field.Input import Input

# 1. Initialize logger

results_folder = 'simulation_results'
logger = set_logger(results_folder)

# 2. Log environment and dependencies

log_system_info(logger)
log_library_versions(logger)

# 3. Log simulation parameters

sim_input = Input(l=2.5, results_folder_name=results_folder)
sim_input.save_log_info(logger)

# 4. Log mesh information (msh is a dolfinx mesh object)

# log_model_information(msh, logger)

# ... execute simulation ...

# 5. Finalize log with timing

log_end_analysis(logger, totaltime=123.45)

This produces a simulation.log file containing structured sections for environment metadata, parameters, runtime progress, and final timing.

Summary

PhaseFieldX logging capabilities provide a comprehensive audit trail through the following mechanisms:

  • Centralized logger creation via set_logger in library_versions.py, ensuring consistent file output and formatting
  • Environment capture through log_system_info and log_library_versions, recording OS, Python version, and dependency versions (DolfinX, numpy, ufl, basix)
  • Configuration logging via the save_log_info method pattern implemented across all Input classes (Phase-Field, Elasticity, Allen-Cahn)
  • Runtime tracing with detailed Newton solver convergence data and physical quantity monitoring in fracture and phase-field solvers
  • Reproducibility markers including mesh dimensions, start/end timestamps, and total wall-clock time via log_end_analysis
  • External library integration by capturing DolfinX C++ logger output at INFO level

Frequently Asked Questions

Where does PhaseFieldX store simulation logs?

PhaseFieldX writes all log output to a file named simulation.log located inside the results folder specified during logger initialization. The path is constructed as os.path.join(result_folder_name, 'simulation.log') in the set_logger function, ensuring logs are co-located with simulation outputs for easy archival.

How do I add custom parameters to the PhaseFieldX simulation log?

Extend the save_log_info(self, logger) method in your input class. Following the pattern in [src/phasefieldx/Element/Phase_Field/Input.py](https://github.com/castillonmiguel/phasefieldx/blob/main/src/phasefieldx/Element/Phase_Field/Input.py), add logger.info() calls for your custom attributes. The logger instance is passed through the solver hierarchy, making it available in any subclass of the input configuration objects.

Does PhaseFieldX capture internal DolfinX messages?

Yes. PhaseFieldX sets the DolfinX C++ logger to INFO level using dolfinx.log.set_log_level(dolfinx.log.LogLevel.INFO) in solver entry points. This captures finite-element assembly messages, linear solver warnings, and mesh-related notifications in the same simulation.log file alongside Python-level logs.

What log level does PhaseFieldX use by default?

The default log level is logging.INFO, set explicitly in set_logger within library_versions.py. This level captures standard operational messages while filtering routine debug output. You can modify this by calling logger.setLevel(logging.DEBUG) after initialization if you require verbose tracing for troubleshooting convergence issues.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →