{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# HeudiConv Basics: DICOM to BIDS Conversion\n",
    "\n",
    "This notebook demonstrates how to use the HeudiConv runner to convert DICOM files to BIDS format.\n",
    "\n",
    "## Overview\n",
    "\n",
    "HeudiConv is a flexible DICOM converter that creates BIDS-compliant datasets. It uses heuristic files to map DICOM series to BIDS-compliant names.\n",
    "\n",
    "## Prerequisites\n",
    "\n",
    "- Docker installed and running\n",
    "- DICOM data organized by participant\n",
    "- A heuristic file defining the conversion rules"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "from voxelops import (\n",
    "    HeudiconvDefaults,\n",
    "    HeudiconvInputs,\n",
    "    run_heudiconv,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define Paths\n",
    "\n",
    "Update these paths to match your data structure:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Input paths -- update these to match your data\n",
    "dicom_dir = Path(\"/data/raw/dicom/\")\n",
    "participant = \"01\"\n",
    "heuristic_file = Path(\"/config/heuristics/brain_bank.py\")\n",
    "\n",
    "# Output paths (optional -- will use defaults if not specified)\n",
    "output_dir = Path(\"/data/bids/\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic Usage\n",
    "\n",
    "### Option 1: Use Default Configuration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create inputs\n",
    "inputs = HeudiconvInputs(\n",
    "    dicom_dir=dicom_dir,\n",
    "    participant=participant,\n",
    "    session=\"01\",\n",
    "    output_dir=output_dir,\n",
    "    # work_dir=work_dir,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Run with defaults\n",
    "result = run_heudiconv(inputs, heuristic=heuristic_file, overwrite=True)\n",
    "\n",
    "# Check result\n",
    "print(f\"Success: {result['success']}\")\n",
    "print(f\"Duration: {result['duration_human']}\")\n",
    "print(f\"Output: {result['expected_outputs'].bids_dir}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Run with parameter overrides\n",
    "result = run_heudiconv(\n",
    "    inputs,\n",
    "    overwrite=True,  # Overwrite existing output\n",
    "    bids_validate=True,  # Run BIDS validator\n",
    "    docker_image=\"nipy/heudiconv:0.13.1\",  # Use specific version\n",
    ")\n",
    "\n",
    "print(f\"Success: {result['success']}\")\n",
    "print(f\"Exit code: {result['exit_code']}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Option 3: Use Custom Configuration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Run with parameter overrides\n",
    "result = run_heudiconv(\n",
    "    inputs,\n",
    "    overwrite=True,\n",
    "    bids_validator=True,  # Run BIDS validator after conversion\n",
    "    docker_image=\"nipy/heudiconv:1.3.4\",  # Pin specific version\n",
    ")\n",
    "\n",
    "print(f\"Success: {result['success']}\")\n",
    "print(f\"Exit code: {result['exit_code']}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Inspect Execution Record\n",
    "\n",
    "The execution record contains complete information about the run:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create custom configuration\n",
    "config = HeudiconvDefaults(\n",
    "    overwrite=True,\n",
    "    bids_validator=True,\n",
    "    docker_image=\"nipy/heudiconv:1.3.4\",\n",
    ")\n",
    "\n",
    "# Run with custom config\n",
    "result = run_heudiconv(inputs, config)\n",
    "\n",
    "print(f\"Success: {result['success']}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Check Expected Outputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "outputs = result[\"expected_outputs\"]\n",
    "\n",
    "print(\"Expected outputs:\")\n",
    "print(f\"BIDS directory: {outputs.bids_dir}\")\n",
    "print(f\"Participant directory: {outputs.participant_dir}\")\n",
    "print(f\"Work directory: {outputs.work_dir}\")\n",
    "\n",
    "# Check if outputs exist\n",
    "print(\"\\nOutput validation:\")\n",
    "print(f\"BIDS dir exists: {outputs.bids_dir.exists()}\")\n",
    "print(f\"Participant dir exists: {outputs.participant_dir.exists()}\")\n",
    "\n",
    "# List files in participant directory\n",
    "if outputs.participant_dir.exists():\n",
    "    print(f\"\\nFiles in {outputs.participant_dir}:\")\n",
    "    for f in outputs.participant_dir.rglob(\"*\"):\n",
    "        if f.is_file():\n",
    "            print(f\"  {f.relative_to(outputs.participant_dir)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Save Execution Record\n",
    "\n",
    "Save the execution record to a database or file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "outputs = result[\"expected_outputs\"]\n",
    "\n",
    "print(\"Expected outputs:\")\n",
    "print(f\"  BIDS directory: {outputs.bids_dir}\")\n",
    "print(f\"  Participant directory: {outputs.participant_dir}\")\n",
    "print(f\"  Dataset description: {outputs.dataset_description}\")\n",
    "\n",
    "# Check if outputs exist\n",
    "print(\"\\nOutput validation:\")\n",
    "print(f\"  BIDS dir exists: {outputs.bids_dir.exists()}\")\n",
    "print(f\"  Participant dir exists: {outputs.participant_dir.exists()}\")\n",
    "\n",
    "# List files in participant directory\n",
    "if outputs.participant_dir.exists():\n",
    "    print(f\"\\nFiles in {outputs.participant_dir}:\")\n",
    "    for f in outputs.participant_dir.rglob(\"*\"):\n",
    "        if f.is_file():\n",
    "            print(f\"  {f.relative_to(outputs.participant_dir)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Error Handling"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from voxelops.exceptions import (\n",
    "    InputValidationError,\n",
    "    ProcedureExecutionError,\n",
    ")\n",
    "\n",
    "try:\n",
    "    result = run_heudiconv(inputs)\n",
    "    print(f\"Success: {result['success']}\")\n",
    "except InputValidationError as e:\n",
    "    print(f\"Input validation failed: {e}\")\n",
    "except ProcedureExecutionError as e:\n",
    "    print(f\"Execution failed: {e}\")\n",
    "    print(f\"Check logs at: {result.get('log_file')}\")\n",
    "except Exception as e:\n",
    "    print(f\"Unexpected error: {e}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Batch Processing Multiple Participants"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# List of participants to process\n",
    "participants = [\"01\", \"02\", \"03\", \"04\", \"05\"]\n",
    "\n",
    "results = []\n",
    "\n",
    "for participant in participants:\n",
    "    print(f\"\\nProcessing participant {participant}...\")\n",
    "\n",
    "    inputs = HeudiconvInputs(\n",
    "        dicom_dir=dicom_dir,\n",
    "        participant=participant,\n",
    "        heuristic=heuristic_file,\n",
    "        output_dir=output_dir,\n",
    "    )\n",
    "\n",
    "    try:\n",
    "        result = run_heudiconv(inputs)\n",
    "        results.append(result)\n",
    "        print(f\"  ✓ Success in {result['duration_human']}\")\n",
    "    except Exception as e:\n",
    "        print(f\"  ✗ Failed: {e}\")\n",
    "        results.append({\"participant\": participant, \"success\": False, \"error\": str(e)})\n",
    "\n",
    "# Summary\n",
    "successful = sum(1 for r in results if r.get(\"success\"))\n",
    "print(\n",
    "    f\"\\nProcessed {len(results)} participants: {successful} successful, {len(results) - successful} failed\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Next Steps\n",
    "\n",
    "After converting DICOM to BIDS:\n",
    "\n",
    "1. Validate the BIDS dataset using the BIDS validator\n",
    "2. Run quality control checks\n",
    "3. Proceed to preprocessing with QSIPrep (see `02_qsiprep_basics.ipynb`)\n",
    "\n",
    "## Tips\n",
    "\n",
    "- **Heuristic files**: Create a reusable heuristic file for your study protocol\n",
    "- **BIDS validation**: Enable `bids_validate=True` to catch errors early\n",
    "- **Overwrite carefully**: Use `overwrite=True` only when necessary\n",
    "- **Check logs**: If conversion fails, check the log file for detailed error messages\n",
    "- **Docker image**: Pin a specific version for reproducibility"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "VoxelOps",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
