Metadata-Version: 2.4
Name: nicqs
Version: 2026.2.6
Summary: Thermo-electromagnetic modeling tool for No-Insulation HTS magnets
Author-email: Tim Mulder <tim.mulder@cern.ch>
Maintainer-email: Tim Mulder <tim.mulder@cern.ch>
License: MIT
Project-URL: Homepage, https://gitlab.cern.ch/steam/ni-coils
Project-URL: Repository, https://gitlab.cern.ch/steam/ni-coils
Project-URL: Documentation, https://gitlab.cern.ch/steam/ni-coils#readme
Project-URL: Issues, https://gitlab.cern.ch/steam/ni-coils/-/issues
Keywords: superconductor,HTS,electromagnetics,quench,simulation,no-insulation,coils,magnets
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Topic :: Scientific/Engineering
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: C
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Requires-Python: <3.12,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: STEAM-materials>=2024.4.2
Requires-Dist: numpy>=1.24.2
Requires-Dist: matplotlib>=3.5.1
Requires-Dist: pandas>=1.4.1
Requires-Dist: scipy>=1.8.0
Requires-Dist: ezdxf>=0.17.2
Requires-Dist: PyYAML>=6.0
Requires-Dist: pyvista>=0.45.3
Requires-Dist: vtk>=9.4.2
Requires-Dist: pillow
Requires-Dist: psutil>=6.0.0
Provides-Extra: dev
Requires-Dist: pytest>=8.1.1; extra == "dev"
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
Requires-Dist: build>=1.2.1; extra == "dev"
Provides-Extra: all
Requires-Dist: nicqs[dev]; extra == "all"
Dynamic: license-file

# NICQS
**No-Insulation Coil Quench Simulator**

*Thermo-electromagnetic modeling tool for simulating transients in No-Insulation (NI) HTS magnets using a 2D homogenized approach.*

[![Python Version](https://img.shields.io/badge/python-3.10%20%7C%203.11-blue)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Installation

### From PyPI (Recommended)
```bash
pip install nicqs
```

For development dependencies:
```bash
pip install nicqs[dev]
```

### From Source
**Prerequisites:**
- Python 3.10 or 3.11
- C compiler:
  - Windows: Microsoft C++ Build Tools (https://visualstudio.microsoft.com/visual-cpp-build-tools/)
  - Linux/Mac: GCC compiler

**Installation steps:**
```bash
# Clone the repository
git clone https://gitlab.cern.ch/steam/ni-coils.git
cd ni-coils

# Install in editable mode
pip install -e .

# Or install with all optional dependencies
pip install -e .[all]
```

**PyTorch Installation (Required):**

NICQS requires PyTorch for the solver. Install the appropriate version for your system:
```bash
# CPU version (recommended for most users)
pip install torch

# CUDA 11.8 (for NVIDIA GPUs - faster computation)
pip install torch --index-url https://download.pytorch.org/whl/cu118

# For other CUDA versions, visit: https://pytorch.org/get-started/locally/
```

**Note:** PyTorch is not included as a dependency because the installation method varies by system (CPU vs GPU). You must install it separately.

## Quick Start

### Running a simulation
1. Create an input YAML file that defines the coil geometry
2. Run the geometry preprocessor:
   ```bash
   nicqs-geometry path/to/geometry.yaml output_directory
   ```
3. An output folder will be created with all geometry-specific information
4. Edit the generated `solver_input.yaml` file as needed
5. Run the simulation:
   ```bash
   nicqs-solver path/to/solver_input.yaml
   ```

### Python API Usage
```python
from nicqs.geometry import NI_coil_geometry
from nicqs.solver_torch import NI_Coil_Solver

# Create geometry from input YAML
geom = NI_coil_geometry(
    input_yaml_path="path/to/geometry.yaml",
    output_path="output_directory"
)
geom.create_geometry()

# Run solver with generated solver_input.yaml
solver = NI_Coil_Solver(input_yaml_path="output_directory/solver_input.yaml")
solver.run()
```


## Example input for the geometry creation.

Coils are defined as named entries under the `coils` key.  Each entry holds all
per-coil geometry and operational parameters.  Circuit-level resistance
settings are collected under `circuit_config`.

```yaml
# Coil definitions — each entry is a named coil group.
coils:
  sc_coil:                        # Arbitrary name, used for logging only.
    inner_radius: 0.03            # Inner radius [m]
    outer_radius: 0.06            # Outer radius [m]
    thickness: 0.012              # Pancake thickness [m] (commonly the tape width)
    turns: 300                    # Turns per pancake coil [-]
    circuit: 1                    # Circuit number [-]. 0 = unpowered.
    insulated: false              # false = NI coil, true = insulated coil.
    I_initial: 100.0              # Initial current [A]. OPTIONAL, default=1
    T_initial: 20.0               # Initial temperature [K]. OPTIONAL, default=5
    T_ref: 20.0                   # Reference temperature for char. time [K]. OPTIONAL, default=4.5
    B_ref: 5.0                    # Reference field for char. time [T]. OPTIONAL, default=0
    offset: 0.0                   # z-axis offset [m]. OPTIONAL, default=0
    spacing: 0.002                # Spacing between repeated pancakes [m]. OPTIONAL, default=0
    serial: 30                    # Subdivisions per pancake [-]. E.g. 300 turns / serial=30 = 10 turns/block. OPTIONAL, default=1
    parallel: 5                   # Parallel tape elements (screening currents) [-]. OPTIONAL, default=1
    repeat: 2                     # Number of pancakes stacked along z [-]. OPTIONAL, default=1
    inductance_z_divisions: 3     # Improves inductance accuracy. OPTIONAL, default=1
    conductor: 'SC1'              # Conductor name. OPTIONAL, default='Dummy'
    # Choose one characteristic-time option per coil (tau takes priority over resistivity):
    tau: 20.0                     # Characteristic time [s]. OPTIONAL (overwritten by the circuit value)
    # resistivity: 1.0e-5         # Turn-to-turn resistivity [Ohm*m^2]. OPTIONAL

  cu_coil:
    inner_radius: 0.03
    outer_radius: 0.08
    thickness: 0.012
    turns: 50
    circuit: 0                    # Circuit 0 = unpowered / quench-back element.
    insulated: false
    I_initial: 0.0
    T_initial: 20.0
    T_ref: 20.0
    B_ref: 0.0
    serial: 50                    # For normal-conducting coils set serial = turns.
    parallel: 1                   # Keep parallel=1 for quench-back elements.
    repeat: 2
    conductor: 'Cu'

# Circuit-level parameters — keyed by the circuit number used above.
# Priority order when multiple options are set: tau > resistivity.
# Values that are set in a circuit are given priority over coil properites.
circuit_config:
  1:
    tau: 20.0                     # Circuit characteristic time [s]. R_circuit = L_circuit / tau
    # resistivity: 1.0e-5         # Alternative: turn-to-turn resistivity [Ohm*cm^2]
    T_ref: 20.0                   # Reference temperature for char. time [K]. OPTIONAL, default=4.5
    B_ref: 5.0                    # Reference field for char. time [T]. OPTIONAL, default=0

# Conductor properties:
Conductor_type                      : {'SC1': 'Superconductor', 'Cu': 'Normal'}
Conductor_SC_properties             : {'SC1': {'fit-name': 'CFUN_HTS_JcFit_Fujikura_v1', 'n-value': 15, 'Ic': 1500.0, 'Tref': 4.5, 'Bref': 10, 'angle': 0.0, 'parallel': 5}}
Conductor_materials                 : {'SC1': ['Cu100', 'Hastelloy', 'Silver'], 'Cu': ['Cu100']}
Conductor_materials_width           : {'SC1': 12.0e-3, 'Cu': 12.0e-3}
Conductor_materials_thickness       : {'SC1': [20.0e-6, 50.0e-6, 2.0e-6], 'Cu': [1.0e-3]}
Conductor_resistor                  : {'SC1': 'Cu100', 'Cu': 'Cu100'}
Conductor_conductivity_materials    : {'SC1': ['Cu100', 'Hastelloy'], 'Cu': ['Cu100']}
Conductor_conductivity_thickness    : {'SC1': 0.000050, 'Cu': 0.001}
Conductor_conductivity_width        : {'SC1': {'Cu100': 0.01e-3, 'Hastelloy': 11.99e-3}, 'Cu': {'Cu100': 12.0e-3}}

# Plotting options:
inductance_calculation: 'analytic' # 'discrete' or 'analytic', the last one is default, faster and better.
rotate_90: false # rotates the plot 90 degrees.
mirror: true # mirrors the plot, otherwise it plots only half the magnet.
plot_lines: 'outer' # 'outer' or 'all', outer plots the outlines of the pancakes, all plots the outlines of each element.

# Other options
overwrite_yaml: true # Overwrites the solver_input and solver_settings yaml files.

# Some solver settings that are passed on to the solver. This can also be changed manually later in the solver yaml file.
atol: 1.0e-6
rtol: 1.0e-7
max_step: 0.01
max_timestep: 0.1
min_step: 1.0e-99
min_timestep: 0.05
thermal_timer: 9999 # Allows temperature changes after this time step.
t0:
- 0.0
- 2.0

# Magnetic field
xmin:           0.0
xmax:           0.1
ymin:           -0.1
ymax:           0.1
nx:             100
ny:             100
```

> **Backward compatibility:** The old flat-array format (`inner_radius: [...]`,
> `tau_circuit: {...}`, etc.) is still accepted but emits a `DeprecationWarning`
> and will be removed in a future version.

The yaml file above will produce the following geometry:
<p align="center">
    <img src="documentation/images/doc_yaml_field.png" width="640">

</p>

## Solver Configuration

After running `nicqs-geometry`, two configuration files are automatically created in the output folder:
- **`solver_input.yaml`** - Defines initial conditions, circuit data, and simulation parameters
- **`solver_settings.yaml`** - Configures solver tolerances and integration parameters

You should review and modify these files according to your simulation needs. Below is a reference for the key parameters in each file.

### solver_input.yaml Parameters
```yaml
circuit_data: # dictionary with a number of positions that corresponds to the number of circuits that we have in our model. In each position/circuit we need to define the dI/dt rate, and the corresponding time (another 2 positions).
  circuit_name:
    dIdt:
    - 0.0
    - 0.0
    t:
    - 0
    - 1

initial_conditions: # dictionary with a number of positions that correspond to the number of different pieces in our model. In each position we have to define the keys:
  coil_nr:
    file_path: '' # the output file with the results we will use
    I_R: 0.0 # the initial current for the resistor
    I_ind: 0.0 # the initial current of the inductor
    Line_index: -1 # which line of the input file it used as input, -1 is the last one.
    Load_from_file: False # boolean type, set true to load data from the file with the "file_path" path.
    T: 4.5 # Initial temperature, K

path_dict: # This is a dictionary that has some information on which paths, geometry and solver files should be used.
  geometry_yaml_path: geometry\output\magnet_folder\geometry.yaml
  solver_settings_path: geometry\output\magnet_folder\solver_settings.yaml
  specific_output_path: geometry\output\Fmagnet_folder

# Common input parameters:
thermal_timer: 99999 # initial time for the thermal solver to start working, one can set it to a large number to include thermal & loss calculations, but without the temperature actually increasing.
sampling_time_custom:  [initial time, end time, step] # time range with a custom time step. There is still a chance for the solver to step over this range. It is better to add some timesteps in the circuit_data dictionary, even if you dont want any changes in dIdt.
```

    
    It is is important to note that the first time we run the solver script,we have to set file_path : ' ' and Load_from_file : false, so that we create the first simulation file. After that we are free to use the results of this simulation file by using its path as the file_path and by seting the Load_from_file variable to true.

*   **thermal_timer** : initial time for the thermal solver to start working
*   **sampling_time_custom** :  array in a format [initial time, end time, step], for the solver
*   **max_cooling** : boolean type. If set to true we have the maximum cooling possible and all excess heat will be cooled away.
*   **maximum_cooling_value** : It is the value above which, all excess heat will be cooled down.
*   **quench_fraction** : the percentage of the model getting affected
*   **heat_nodes** : array or scalar that indicates which nodes will be heated up
*   **heater_power** : the power applied to the nodes
*   **Cap_discharge** : boolean value indicating whether there is a discharge
*   **Cap_discharge_time** : time of discharge in seconds
*   **Dis_List_Coils** : array or scalar that indicates which coils are discharging
*   **R_multiplier** : Parameter with which we can modify the resistance R = L/tau

### solver_settings.yaml Parameters

*   **atol**: integration parameter (absolute tolerance)
*   **colormap_name**: coolwarm
*   **dt**: timestamp
*   **electrical_part** : option to enable the electrical part
*   **keep_smallest_timestep** : option to set as timestep the smallest value
*   **max_step**
*   **max_timestep** : maximum timestep value which limits the sampling_time_custom attribute
*   **min_step** : 
*   **min_timestep**
*   **rtol**
*   **sampling_time_dI**
*   **sampling_time_dT**
*   **solver**
*   **stop_criterion_E**
*   **stop_criterion_T**
*   **stop_on_E**
*   **stop_on_T**
*   **t0**
*   **thermal_part** : option to enable the thermal part

## Contributing

Contributions are welcome! Please feel free to submit issues or pull requests to the [GitLab repository](https://gitlab.cern.ch/steam/ni-coils).

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Citation

If you use NICQS in your research, please cite:
```
NICQS - No-Insulation Coil Quench Simulator
Tim Mulder, CERN
https://gitlab.cern.ch/steam/ni-coils
```

## Contact

**Author:** Tim Mulder
**Email:** tim.mulder@cern.ch
