Metadata-Version: 2.4
Name: pysq
Version: 0.1.4
Summary: Python SDK for Siroquant API V5
Author: Siroquant
License: Proprietary
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Chemistry
Classifier: Typing :: Typed
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Requires-Dist: mypy; extra == "dev"

# PYSQ - Siroquant SDK for Python

Python SDK for Siroquant V5 API.

Website: [https://www.siroquant.com/](https://www.siroquant.com/)

>**Siroquant** is a commercial software package designed for quantitative phase analysis using X-ray diffraction (XRD) data, primarily through the Rietveld refinement method. It enables users to determine the composition of crystalline materials—such as minerals, cements, coals, and clays—by fitting full XRD powder patterns without needing physical standards, making it a standardless technique.

## Getting Started

```bash
# create a virtual environment and activate it
python -m venv venv
source venv\Scripts\activate

# Install the package
pip install pysq

# Update the package (optional)
pip install --upgrade pysq
```

## Usage Examples

### Simple Example

```python
from pysq import SQAPI, SQAPIConfig

config = SQAPIConfig(lib_dir=r".\lib", dll_path=r".\lib\sq_api.dll")

with SQAPI(config) as api:
    api.initialize()
    task_info = api.open_task("task.tsk")
    results = api.refine(task_info.job_handle)
    print(f"Results: {results}")
```

### Advanced Example

```python
import os
from pysq import SQAPI, SQAPIConfig, SQAPIError, RefinementParams, ReportResultsFlags, SaveTaskFlags, TaskContext

# Configuration
TASK_FILE = r".\task.tsk"
LIB_DIR = r".\lib"
DLL_PATH = r".\lib\sq_api.dll"

# Output directory for saved tasks
OUTPUT_DIR = r".\output"


def main() -> None:
    """Run a simple refinement example."""
    # Resolve all paths to absolute before any DLL calls.
    # The DLL changes the process CWD to the task file's directory when opening
    # a task (Delphi SetCurrentDir), so any relative path resolved after that
    # point will be wrong.
    task_basename = os.path.splitext(os.path.basename(TASK_FILE))[0]
    save_path = os.path.abspath(os.path.join(OUTPUT_DIR, f"{task_basename}_result.tsk"))

    config = SQAPIConfig(lib_dir=LIB_DIR, dll_path=DLL_PATH)
    print(f"Configuration loaded:")
    print(f"  Library directory: {config.lib_dir}")
    print(f"  DLL path: {config.dll_path}")

    try:
        # Use SQAPI context manager for automatic finalization
        with SQAPI(config) as api:
            print(f"API (init): {api}")
            api.initialize()
            print(f"API (status): {api}")

            # Use TaskContext for automatic task cleanup
            with TaskContext(api, TASK_FILE) as (job_handle, task_info):
                print(f"\nTask: {task_info}")

                # Run refinement
                params = RefinementParams(
                    n_auto_prescale=1,
                    n_refs=1,
                    cutoff=0.5,
                    error_cutoff=1.0,
                    error_pc=0.75,
                    flags=0,
                )
                results = api.refine(job_handle, params=params, report_flags=ReportResultsFlags.CORRECTED)

                print(f"\nResults: {results}")
                if results.phases:
                    print("\nResults Breakdown:")
                    print(f"{'No.':<4} {'Phase Name':<20} {'Weight (%)':<12} {'Error (%)':<10}")
                    print("-" * 50)
                    for i, phase in enumerate(results.phases, 1):
                        print(f"{i:<4} {phase.phase_name:<20} {phase.weight_pc:<12.2f} {phase.error_of_fit:<10.2f}")

                # Save the task with refinement results to the output directory.
                # ENFORCE_DIRECTORIES ensures the output folder is created if it
                # does not already exist.
                api.save_task(
                    job_handle,
                    save_path,
                    SaveTaskFlags.ENFORCE_DIRECTORIES,
                )
                print(f"\nTask saved to: {save_path}")

    except SQAPIError as e:
        print(f"\nSQ API Error: {e}")
        if e.error_code is not None:
            print(f"Error code: {e.error_code}")
    except FileNotFoundError as e:
        print(f"\nFile not found: {e}")
    except Exception as e:
        print(f"\nUnexpected error: {e}")


if __name__ == "__main__":
    main()

```

## Configuration

Set paths via environment variables or code:

- `SQ_LIB_DIR`: Library directory path
- `SQ_DLL_PATH`: DLL path (optional, auto-detected)

## Requirements

- Python 3.8+
- Windows (x64)
- Siroquant V5
