Metadata-Version: 2.4
Name: maritime-eu-compliance
Version: 0.2.2
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Rust
Classifier: Topic :: Scientific/Engineering
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Requires-Dist: pytest>=7.0 ; extra == 'dev'
Requires-Dist: pytest-xdist>=3.0 ; extra == 'dev'
Provides-Extra: dev
License-File: LICENSE
Summary: Maritime EU compliance (ETS / FuelEU) and IMO CII carbon-intensity calculator
Keywords: maritime,shipping,eu-ets,fueleu,cii,imo,carbon,emissions
Home-Page: https://github.com/maritime-eu-compliance/maritime-eu-compliance
Author: maritime-eu-compliance contributors
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# maritime-eu-compliance

> **Maritime EU compliance (ETS / FuelEU) and IMO CII** — carbon-emissions and
> carbon-intensity calculator for shipping.
> shipped as a Python native extension with type stubs.

| &nbsp; | &nbsp; |
|---|---|
| **PyPI** | `maritime-eu-compliance` |
| **import** | `import maritime_eu_compliance as m` |
| **Python** | ≥ 3.9 |
| **Platforms** | macOS (arm64 / x86_64), Linux (x86_64 / aarch64), Windows |
| **License** | MIT |

Covers three regulatory frameworks / 覆盖三大法规框架：

- **EU ETS**  — shipping CO₂ allowance obligation for vessels ≥ 5 000 GT calling at EU ports.
- **FuelEU Maritime**  — well-to-wake GHG intensity target & penalty.
- **IMO CII**  — annual operational carbon-intensity rating A–E.

---

## Install / 安装

```bash
pip install maritime-eu-compliance
```
---

## 30-second tour / 30 秒上手

Each example below constructs **all** relevant inputs, calls the calculator, and
prints **every** output field with bilingual comments.

### 1. EU ETS — voyage allowance cost / 航次碳配额成本

```python
import maritime_eu_compliance as m

# --- Inputs / 输入 ------------------------------------------------------
ship = m.VesselInfo(
    imo=9999999,          # IMO 号 / IMO number
    gt=12000,             # 总吨 / gross tonnage (≥ 5000 → 受 ETS 约束 / in ETS scope)
)
voyage = m.VoyageInfo(
    dep_port_eu=True,     # 出发港是否欧盟 / departure port is EU
    des_port_eu=False,    # 目的港是否欧盟 / destination port is EU
    total_sea_nm=500,     # 航段总海里 / total leg distance (NM)
    # 可选参数（以下均为默认值）/ optional args (shown with defaults):
    dep_exclude=False,    # 出发港豁免 / departure port exempted
    des_exclude=False,    # 目的港豁免 / destination port exempted
    wind_factor=1.0,      # 风力奖励系数 / wind reward (1.0/0.99/0.97/0.95)
    renewable_credit=0.0, # 可再生抵扣 tCO₂e / renewable credit offset
)
fuel = m.FuelConsumption(
    fuel_type="MGO",      # 燃料类型 / fuel code (支持别名 hsfo/vlsdgo/lng…)
    consumption=1.0,      # 消耗量（吨）/ consumption (mt)
    is_bio=False,         # 是否生物燃料 / is biofuel
)

# --- Calculation / 计算 -------------------------------------------------
ets = m.ETSCalculator(ship, voyage)
r = ets.calc_voyage_ets(
    fuels=[fuel],         # 燃料列表 / fuel list
    report_year=2026,     # 申报年份 / reporting year (决定年度折算比例 / drives year_ratio)
    carbon_price=90.0,    # EUA 单价 EUR/tCO₂e / EUA market price
    free_eua=0.0,         # 免费配额 tCO₂e / free allowance
)

# --- All output fields / 全部输出字段 ----------------------------------
print(f"  leg_category        航段类别     : {r['leg_category']}")
print(f"  area_rate           区域分摊比例 : {r['area_rate']}")
print(f"  total_ttw_ghg       原始 TTW     : {r['total_ttw_ghg']} tCO₂e (未分摊 / unsplit)")
print(f"  taxable_ghg_total   应税排放总量 : {r['taxable_ghg_total']} tCO₂e (TTW × at_sea)")
print(f"  year_ratio          年度折算比例 : {r['year_ratio']}")
print(f"  required_eua        所需配额     : {r['required_eua']} tCO₂e")
print(f"  carbon_price_eur    EUA 单价     : {r['carbon_price_eur']} EUR/tCO₂e")
print(f"  ets_cost_gross      毛成本       : {r['ets_cost_gross']} EUR")
print(f"  free_eua_available  可用免费配额 : {r['free_eua_available']} tCO₂e")
print(f"  free_eua_offset     免费抵扣价值 : {r['free_eua_offset']} EUR")
print(f"  ets_final_cost      最终成本     : {r['ets_final_cost']} EUR")
print(f"  fuel_detail         燃料明细     :")
for fd in r["fuel_detail"]:
    print(f"    - {fd['fuel_type']}: cons={fd['cons_mt']} mt, "
          f"ttw={fd['ttw_tco2e']}, taxable={fd['taxable_ttw_tco2e']} tCO₂e, "
          f"co2={fd['co2_tco2e']}, ch4={fd['ch4_tco2e']}, n2o={fd['n2o_tco2e']}")
```

### 2. FuelEU Maritime — intensity target & penalty / 燃料欧盟强度目标与罚款

```python
fueleu = m.FuelEUCalculator()   # 无状态 / stateless
r = fueleu.calc_voyage_fueleu(
    fuels=[fuel],         # 燃料列表 / fuel list
    voyage=voyage,        # 航次（用 wind_factor / renewable_credit）
    report_year=2025,     # 申报年份（<2025 返回 0 / pre-2025 returns zeros）
)

# --- All output fields / 全部输出字段 ----------------------------------
print(f"  target_intensity_g_mj 目标强度 : {r['target_intensity_g_mj']} gCO₂e/MJ")
print(f"  actual_intensity_g_mj  实际强度 : {r['actual_intensity_g_mj']} gCO₂e/MJ")
print(f"  wind_reward_factor     风奖励   : {r['wind_reward_factor']}")
print(f"  total_energy_mj        总能量   : {r['total_energy_mj']} MJ")
print(f"  wtw_ghg_g              WTW GHG  : {r['wtw_ghg_g']} gCO₂e")
print(f"  wtw_ghg_tco2e          WTW GHG  : {r['wtw_ghg_tco2e']} tCO₂e")
print(f"  raw_balance_tco2e      毛余额   : {r['raw_balance_tco2e']} tCO₂e")
print(f"  credit_offset_tco2e    可再生   : {r['credit_offset_tco2e']} tCO₂e")
print(f"  net_balance_tco2e      净余额   : {r['net_balance_tco2e']} tCO₂e")
print(f"  fueleu_penalty_eur     罚款     : {r['fueleu_penalty_eur']} EUR")
print(f"  fuel_detail            燃料明细 :")
for fd in r["fuel_detail"]:
    print(f"    - {fd['fuel_type']}: cons={fd['cons_mt']} mt, energy={fd['energy_mj']} MJ, "
          f"wtt={fd['wtt_ghg_g']} g, ttw={fd['ttw_ghg_g']} g")

# 静态方法：查任意年份的目标强度 / static helper: year → target intensity
print(m.FuelEUCalculator.get_year_target_intensity(2030))
```

### 3. IMO CII — annual rating / 年度碳强度评级

```python
# --- Inputs / 输入 ------------------------------------------------------
calc = m.CIICalculator(
    vessel_type="Bulk Carrier",  # 船型（支持别名 bulker/tanker/PCC/LNG…）/ vessel type
    dwt=50000,                   # 载重吨 / deadweight tonnage
    gt=0,                        # 总吨（RoRo/Cruise 用 GT）/ gross tonnage
)

# CO₂ 排放（克）/ CO₂ emission in grams
co2_g = m.CIICalculator.calculate_co2(
    consumption=1000,      # 燃料消耗量（吨）/ fuel consumption (mt)
    fuel_type="MGO",       # 燃料类型 / fuel type
)

# --- Calculation / 计算 -------------------------------------------------
r = calc.calculate_cii(
    year=2023,             # 计算年份 / calculation year
    co2_total=co2_g,       # CO₂ 总量（克）/ total CO₂ (g)
    distance=5000,         # 航行距离（海里）/ distance (NM)
)

# --- All output fields / 全部输出字段 ----------------------------------
print(f"  reference_cii   基准 CII (2019) : {r['reference_cii']}")
print(f"  required_cii    达标 CII       : {r['required_cii']}")
print(f"  attained_cii    实际 CII       : {r['attained_cii']}")
print(f"  grade           评级           : {r['grade']} (A 最好 / best, E 最差 / worst)")
print(f"  capacity        载运能力       : {r['capacity']} DWT")
print(f"  year            年份           : {r['year']}")
print(f"  reference_year  基准年         : {r['reference_year']}")

# 单步方法 / step methods（一般不用，calculate_cii 内部已调用）：
# calc.calculate_reference_cii()              # 基准 CII / reference CII
# calc.calculate_required_cii(ref, year)      # 达标 CII / required CII
# calc.calculate_attained_cii(co2_g, dist)    # 实际 CII / attained CII
# calc.calculate_grade(required, attained)    # 评级 / grade
```

### 4. Aggregator — ETS + FuelEU in one shot / 一次算完

```python
agg = m.EUComplianceAggregator(ship, voyage)
r = agg.run_full_calc(
    fuels=[fuel],         # 燃料列表 / fuel list
    year=2026,            # 申报年份 / reporting year
    carbon_price=90.0,    # EUA 单价 / EUA price
    free_eua=0.0,         # 免费配额 / free allowance
)
# r["ets"]      → 与 ETSCalculator.calc_voyage_ets 输出一致 / same as ETS result
# r["fueleu"]   → 与 FuelEUCalculator.calc_voyage_fueleu 输出一致 / same as FuelEU result
print(f"  vessel                   船舶信息 : {r['vessel']}")
print(f"  voyage                   航次信息 : {r['voyage']}")
print(f"  report_year              申报年份 : {r['report_year']}")
print(f"  ets.ets_final_cost       ETS 成本 : {r['ets']['ets_final_cost']} EUR")
print(f"  fueleu.fueleu_penalty    FuelEU   : {r['fueleu']['fueleu_penalty_eur']} EUR")
print(f"  total_compliance_cost    总成本   : {r['total_compliance_cost_eur']} EUR")
```

---

## API Reference / 接口文档

### Helper functions / 辅助函数

```python
m.normalize_fuel("hsdgo")               # → "DGO"      业务名→标准编码 / alias → standard code
m.normalize_fuel("LNG")                 # → "LNG_OTTO_MEDIUM_SPD"
m.normalize_vessel_type("PCC")          # → "RO-RO CARGO VEHICLE SHIP"
m.normalize_vessel_type("Bulk Carrier") # → "BULK CARRIER"
```

### Classes & methods / 类与方法

#### `VesselInfo(imo, gt)`
船舶信息（ETS 用 GT 判断是否受约束 / ETS uses GT for scope check）。

| Parameter | Type | Meaning |
|---|---|---|
| `imo` | int | IMO 号 / IMO number |
| `gt`  | float | 总吨 / gross tonnage |

Settable attributes: `imo`, `gt`.

---

#### `VoyageInfo(dep_port_eu, des_port_eu, total_sea_nm, dep_exclude=False, des_exclude=False, wind_factor=None, renewable_credit=0.0)`
航次信息（ETS 用 EU 港状态算分摊；FuelEU 用 wind_factor 和 renewable_credit）。

| Parameter | Type | Default | Meaning |
|---|---|---|---|
| `dep_port_eu` | bool | — | 出发港是否欧盟 / departure port is EU |
| `des_port_eu` | bool | — | 目的港是否欧盟 / destination port is EU |
| `total_sea_nm` | float | — | 航段总海里 / total leg distance (NM) |
| `dep_exclude` | bool | `False` | 出发港豁免（不计 ETS/FuelEU）/ departure exempted |
| `des_exclude` | bool | `False` | 目的港豁免 / destination exempted |
| `wind_factor` | float \| None | `None` (=1.0) | 风力奖励 ∈ {1.0, 0.99, 0.97, 0.95} / wind reward |
| `renewable_credit` | float | `0.0` | 可再生抵扣（tCO₂e）/ renewable credit |

Settable attributes: same as parameters.

---

#### `FuelConsumption(fuel_type, consumption, is_bio=False, custom_factor=None)`
单条燃料消耗记录。

| Parameter | Type | Default | Meaning |
|---|---|---|---|
| `fuel_type` | str | — | 燃料编码或业务别名 / fuel code or alias (`"HFO"`, `"hsdgo"`, `"LNG"`, …) |
| `consumption` | float | — | 消耗量（吨）/ consumption (mt) |
| `segment` | str | `"AT_SEA"` | `"DEPARTURE"` / `"AT_SEA"` / `"DESTINATION"` |
| `is_bio` | bool | `False` | 是否生物燃料 / is biofuel |

Settable attributes: same as parameters.

---

#### `ETSCalculator(vessel, voyage)`
EU ETS 计算器（按船 + 航次实例化 / instance per vessel+voyage）。

| Parameter | Type | Meaning |
|---|---|---|
| `vessel` | VesselInfo | 船舶信息（含 GT）/ vessel info |
| `voyage` | VoyageInfo | 航次信息 / voyage info |

**Methods:**

| Method | Returns | Description |
|---|---|---|
|`calc_voyage_ets(fuels, report_year, carbon_price, free_eua=0.0)` | dict | 完整 ETS 计算 / full ETS calculation |

`calc_voyage_ets` parameters:

| Parameter | Type | Default | Meaning |
|---|---|---|---|
| `fuels` | list[FuelConsumption] | — | 燃料消耗列表 / fuel list |
| `report_year` | int | — | 申报年份 / reporting year |
| `carbon_price` | float | — | EUA 单价 EUR/tCO₂e / EUA price |
| `free_eua` | float | `0.0` | 免费配额（tCO₂e）/ free allowance |

---

#### `FuelEUCalculator()`
FuelEU 计算器（无状态 / stateless）。

**Methods:**

| Method | Returns | Description |
|---|---|---|
| `calc_voyage_fueleu(fuels, voyage, report_year)` | dict | 完整 FuelEU 计算 / full FuelEU calculation |
| `get_year_target_intensity(year)` (static) | float | 年份→目标强度（gCO₂e/MJ）/ year→target intensity |

`calc_voyage_fueleu` parameters:

| Parameter | Type | Meaning |
|---|---|---|
| `fuels` | list[FuelConsumption] | 燃料消耗列表 / fuel list |
| `voyage` | VoyageInfo | 航次（用 wind_factor / renewable_credit）/ voyage |
| `report_year` | int | 申报年份（<2025 返回 0 / pre-2025 returns zeros） |

---

#### `CIICalculator(vessel_type, dwt, gt)`
IMO CII 计算器（按船实例化 / instance per vessel）。

| Parameter | Type | Meaning |
|---|---|---|
| `vessel_type` | str | 船型（12 类之一，支持别名）/ vessel type |
| `dwt` | float | 载重吨（大部分船型用）/ deadweight |
| `gt`  | float | 总吨（RoRo/Cruise 用）/ gross tonnage |

**Methods:**

| Method | Returns | Description |
|---|---|---|
| `calculate_cii(year, co2_total, distance)` | dict | 完整 CII 计算（评级 + 值）/ full CII calculation |
| `calculate_co2(consumption, fuel_type)` (static) | float | CO₂ 排放（克）/ CO₂ emission (g) |
| `calculate_reference_cii()` | float \| None | 2019 基准 CII / reference CII |
| `calculate_required_cii(reference_cii, year)` | float | 年度达标 CII / required CII |
| `calculate_attained_cii(co2_g, distance_nm)` | float | 实际 CII / attained CII |
| `calculate_grade(required_cii, attained_cii)` | str | 评级 A-E / grade |

**Properties:**
- `capacity` (float): 实际使用的载运能力（按船型自动选 DWT 或 GT）/ capacity used

---

#### `EUComplianceAggregator(vessel, voyage, eu_gwp=None, fuel_gwp=None)`
汇总计算器（一次算 ETS + FuelEU / one-shot ETS + FuelEU）。

| Parameter | Type | Meaning |
|---|---|---|
| `vessel` | VesselInfo | 船舶信息 / vessel info |
| `voyage` | VoyageInfo | 航次信息 / voyage info |

**Methods:**

| Method | Returns | Description |
|---|---|---|
| `run_full_calc(fuels, year, carbon_price, free_eua=0.0)` | dict | 合规成本汇总 / aggregated compliance cost |

`run_full_calc` parameters:

| Parameter | Type | Default | Meaning |
|---|---|---|---|
| `fuels` | list[FuelConsumption] | — | 燃料消耗列表 / fuel list |
| `year` | int | — | 申报年份 / reporting year |
| `carbon_price` | float | — | EUA 单价（EUR/tCO₂e）/ EUA price |
| `free_eua` | float | `0.0` | 免费配额（tCO₂e）/ free allowance |

Returns a dict with keys: `vessel`, `voyage`, `report_year`, `ets`, `fueleu`, `total_compliance_cost_eur`.

---

## Output field dictionary / 输出字段字典

### ETS result

| key | type | unit | meaning |
|---|---|---|---|
| `leg_category` | str | — | `NON_EU` / `ARRIVAL_EU` / `DEPARTURE_EU` / `BETWEEN_EU` |
| `area_rate` | dict | ratio | `{departure, at_sea, destination}` split factors |
| `total_ttw_ghg` | float | tCO₂e | sum of TTW (tank-to-wake) emissions, unsplit |
| `taxable_ghg_total` | float | tCO₂e | TTW × `at_sea` (non-EU leg removed) |
| `year_ratio` | float | ratio | annual phase-in ratio |
| `required_eua` | float | tCO₂e | `taxable × year_ratio` |
| `carbon_price_eur` | float | EUR/tCO₂e | input price |
| `ets_cost_gross` | float | EUR | `required_eua × carbon_price` |
| `free_eua_available` | float | tCO₂e | input allowance |
| `free_eua_offset` | float | EUR | `min(free_eua, required_eua) × carbon_price` |
| `ets_final_cost` | float | EUR | `gross − offset` (≥ 0) |
| `fuel_detail` | list[dict] | — | per-fuel breakdown |

**ETS fuel_detail 每条记录字段：**

| Key | Type | Unit | Description |
|-----|------|------|-------------|
| `fuel_type` | str | — | 燃料类型标签 |
| `cons_mt` | float | mt | 总消耗质量 |
| `ttw_tco2e` | float | tCO₂e | TTW 排放总量 (CO₂+CH₄+N₂O) |
| `taxable_ttw_tco2e` | float | tCO₂e | 应税部分 TTW 排放 |
| `co2_tco2e` | float | tCO₂e | CO₂ 分项排放 |
| `ch4_tco2e` | float | tCO₂e | CH₄ 折算排放 |
| `n2o_tco2e` | float | tCO₂e | N₂O 折算排放 |

### FuelEU result

| key | type | unit | meaning |
|---|---|---|---|
| `target_intensity_g_mj` | float | gCO₂e/MJ | year target |
| `actual_intensity_g_mj` | float | gCO₂e/MJ | `(WTT + TTW×wind) / energy` |
| `wind_reward_factor` | float | ratio | 1.0 / 0.99 / 0.97 / 0.95 |
| `total_energy_mj` | float | MJ | `Σ cons_mt × 1000 × LCV` |
| `wtw_ghg_g` | float | gCO₂e | sum of WTT + TTW×wind |
| `wtw_ghg_tco2e` | float | tCO₂e | same / 1e6 |
| `raw_balance_tco2e` | float | tCO₂e | `(target × energy − actual_emissions) / 1e6` |
| `credit_offset_tco2e` | float | tCO₂e | `renewable_credit` (≥ 0) |
| `net_balance_tco2e` | float | tCO₂e | `raw + credit` |
| `fueleu_penalty_eur` | float | EUR | penalty when `net_balance < 0` |
| `fuel_detail` | list[dict] | — | per-fuel energy + WTT/TTW split |

### CII result

| key | type | unit | meaning |
|---|---|---|---|
| `grade` | str | A–E | rating, lower is better |
| `attained_cii` | float | gCO₂/DWT·nm | `CO2_g / (capacity × distance)` |
| `required_cii` | float | gCO₂/DWT·nm | `reference × (1 − Z/100)` |
| `reference_cii` | float | gCO₂/DWT·nm | 2019 baseline `a × capacity^(−c)` |
| `capacity` | float | DWT or GT | used for calculation |
| `year` | int | — | input year |
| `reference_year` | int | — | always 2019 |

---

## Fuel types / 燃料类型

Business aliases accepted by `normalize_fuel` and `FuelConsumption(fuel_type=...)`:

| Business name | Maps to | Note |
|---|---|---|
| `hsfo` | `HFO` | high-sulphur heavy fuel oil |
| `vlsfo`, `ulsfo`, `lsfo` | `LFO` | very/ultra-low-sulphur fuel oil |
| `hsdgo`, `vlsdgo`, `ulsdgo`, `diesel`, `gasoil` | `DGO` | distillate diesel |
| `mgo`, `mdo` | `MGO` / `MDO` | same factor as DGO, kept as-is for traceability |
| `lng` | `LNG_OTTO_MEDIUM_SPD` | default for unspecified LNG engine |
| `LNG_OTTO_SLOW_SPD`, `LNG_DIESEL_SLOW_SPD`, `LNG_LBSI` | matched exactly | different methane slip (cj) |
| `lng_otto_ms`, `lng_lpdi` | aliases | shorthand |

---

## Vessel types (CII) / 船型（CII）

12 IMO standard categories. `normalize_vessel_type` accepts both the official
name (`"BULK CARRIER"`) and common business aliases (`bulker`, `tanker`,
`PCC`, `RoPax`, `LNG`, `reefer`, ...).

Vessels using **DWT** as capacity: BulkCarrier, GasCarrier, Tanker, ContainerShip,
GeneralCargoShip, RefrigeratedCargoCarrier, CombinationCarrier, LngCarrier.

Vessels using **GT**: RoRoCargoShip, RoRoCargoVehicleShip, RoRoPassengerShip,
CruisePassengerShip.

---

## License

MIT

