diff --git a/docs/content/getting-started.ipynb b/docs/content/getting-started.ipynb
index e8d2309ea..b32b0e177 100644
--- a/docs/content/getting-started.ipynb
+++ b/docs/content/getting-started.ipynb
@@ -16,6 +16,8 @@
"\n",
"Before continuing, see the page on [](installation.md).\n",
"\n",
+ "If you are coming from FASTSim-2, check out our [](migration-guide.ipynb).\n",
+ "\n",
"## Key Concepts\n",
"\n",
"A FASTSim simulation is built on three main components:\n",
diff --git a/docs/content/migration-guide.ipynb b/docs/content/migration-guide.ipynb
new file mode 100644
index 000000000..0d3027f0e
--- /dev/null
+++ b/docs/content/migration-guide.ipynb
@@ -0,0 +1,716 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "cell-1",
+ "metadata": {},
+ "source": [
+ "# FASTSim 2 to FASTSim 3 Migration Guide\n",
+ "\n",
+ "FASTSim 3 is the newest version of FASTSim. This guide is for existing FASTSim 2 users migrating to FASTSim 3.\n",
+ "\n",
+ "You will learn how to:\n",
+ "\n",
+ "- Install and import FASTSim 3\n",
+ "- Load vehicles and drive cycles (including converting your existing FASTSim 2 vehicle files)\n",
+ "- Run simulations\n",
+ "- Read scalar parameters and time-series results\n",
+ "- Modify vehicle parameters\n",
+ "- Identify name and path changes for FASTSim vehicle fields, with provided FASTSim 2 to FASTSim 3 reference guide mapping FASTSim 2 fields to their FASTSim 3 counterparts"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-2",
+ "metadata": {},
+ "source": [
+ "## What Changed?\n",
+ "\n",
+ "The biggest change is how vehicle data is stored:\n",
+ "\n",
+ "- **FASTSim 2** used a flat structure - every parameter (`fc_max_kw`, `ess_max_kwh`, `mc_max_kw`, …) was a top-level attribute on the `Vehicle` object, and every powertrain field existed on every vehicle regardless of whether it applied (e.g. conventional vehicles still had a battery field).\n",
+ "- **FASTSim 3** uses a **nested hierarchical structure** where each vehicle only contains the fields relevant to its powertrain (`Conv`, `HEV`, `PHEV`, or `BEV`). Combining incompatible fields (e.g. a conventional vehicle with a battery) is now impossible. This allows for safer, clearer data handling.\n",
+ "\n",
+ "Other important differences:\n",
+ "\n",
+ "- **SI units are baked into field names** (`_watts`, `_joules`, `_kilograms`, `_meters`, `_seconds`). This means some variable units have been updated (no more kW or mph units), and all variables now have clear and uniformly labeled units.\n",
+ "- **Simulation results are accessed via `to_dataframe()` and `to_pydict()`** rather than as direct array attributes on the `SimDrive` object.\n",
+ "- **Method to modify vehicle attributes has changed.** Modifying a field now requires first changing to a pydict, modifying, then changing back.\n",
+ "- **Configurable save intervals** (`set_save_interval`) - disabling per-step recording gives roughly a 10× speedup and decreased memory usage.\n",
+ "- **Thermal modeling** (cabin, HVAC, battery, engine) is now supported."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-3",
+ "metadata": {},
+ "source": [
+ "## Quick Reference\n",
+ "\n",
+ "The table below covers common FASTSim actions.\n",
+ "\n",
+ "| Task | FASTSim 2 | FASTSim 3 |\n",
+ "| --- | --- | --- |\n",
+ "| Import | `import fastsim as fsim` | `import fastsim as fsim` |\n",
+ "| Load vehicle from resource | `fsim.Vehicle.from_resource(\"2012_Ford_Fusion.yaml\")` | `fsim.Vehicle.from_resource(\"2012_Ford_Fusion.yaml\")` |\n",
+ "| Load vehicle from database | `fsim.vehicle.Vehicle.from_vehdb` | `fsim.Vehicle.from_db` (see [](user-guide/vehicle-models/loading-vehicles.ipynb) for more information) |\n",
+ "| Vehicle from file | `fsim.vehicle.Vehicle.from_file(\"veh.yaml\")` | `fsim.Vehicle.from_file(\"veh.yaml\")` |\n",
+ "| Load a FASTSim 2 file into FASTSim 3 | N/A | `fsim.Vehicle.from_file(\"veh_f2.yaml\")` |\n",
+ "| List vehicles in resources | `fsim.Vehicle.list_resources()` | `fsim.Vehicle.list_resources()` |\n",
+ "| Load cycle from resource | `fsim.cycle.Cycle.from_file(\"udds\")` | `fsim.Cycle.from_resource(\"udds.csv\")`|\n",
+ "| Load cycle from file | `fsim.cycle.Cycle.from_file(\"cycle.csv\")` | `fsim.Cycle.from_file(\"cycle.csv\")` |\n",
+ "| Access Powertrain type | `veh.veh_pt_type` (string) | `veh.veh_type()` → `\"Conv\"` / `\"HEV\"` / `\"PHEV\"` / `\"BEV\"` |\n",
+ "| Read a vehicle variable value | `veh.fc_max_kw` | `veh.to_pydict(flatten=True)[\"pt_type.Conv.fc.pwr_out_max_watts\"]` |\n",
+ "| Modify a parameter | `veh.fc_max_kw = 100` | `d = veh.to_pydict(flatten=False)`
`d[\"pt_type\"][\"Conv\"][\"fc\"][\"pwr_out_max_watts\"] = 100`
`veh = fsim.Vehicle.from_pydict(d)` |\n",
+ "| Create simulation | `fsim.simdrive.SimDrive(cyc, veh)` | `fsim.SimDrive(veh, cyc)` (**argument order reversed**) |\n",
+ "| Run simulation | `sd.sim_drive()` | `sd.walk()` |\n",
+ "| Access time-series result | `sd.fc_kw_in_ach` (array attribute) | `sd.to_dataframe()[\"veh.pt_type.Conv.fc.history.pwr_fuel_watts\"]` |\n",
+ "| Access scalar cumulative result | `sd.fs_kwh_out_ach[-1]` | `sd.to_pydict(flatten=True)[\"veh.pt_type.Conv.fc.state.energy_fuel_joules\"]` |\n",
+ "| Configure save interval | (save interval always 1) | `veh.set_save_interval(1)` / `veh.set_save_interval(None)` |\n",
+ "| Save vehicle | `veh.to_file(\"veh.yaml\")` | `veh.to_file(\"veh.yaml\")` |"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-4",
+ "metadata": {},
+ "source": [
+ "## Installation and Imports\n",
+ "\n",
+ "FASTSim 3 is installed the same way as FASTSim 2:\n",
+ "\n",
+ "```bash\n",
+ "pip install fastsim\n",
+ "```\n",
+ "\n",
+ "The top-level import is unchanged, but many classes have moved to the `fastsim` root namespace (they used to live in submodules like `fastsim.vehicle` and `fastsim.simdrive`):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-5",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Vehicle : \n",
+ "Cycle : \n",
+ "SimDrive: \n"
+ ]
+ }
+ ],
+ "source": [
+ "import fastsim as fsim\n",
+ "\n",
+ "# FASTSim 2: fsim.vehicle.Vehicle, fsim.cycle.Cycle, fsim.simdrive.SimDrive\n",
+ "# FASTSim 3: fsim.Vehicle, fsim.Cycle, fsim.SimDrive\n",
+ "\n",
+ "# Accessing FASTSim 3 classes\n",
+ "print(\"Vehicle :\", fsim.Vehicle)\n",
+ "print(\"Cycle :\", fsim.Cycle)\n",
+ "print(\"SimDrive:\", fsim.SimDrive)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-6",
+ "metadata": {},
+ "source": [
+ "## Loading Vehicles\n",
+ "\n",
+ "FASTSim 2 used YAML resource files, custom CSV files, or integer database IDs (`from_vehdb(10)`). FASTSim 3 uses named YAML resources, customized YAML files, or a YAML vehicle database accessible through `from_vehdb()` (see more in [](user-guide/vehicle-models/loading-vehicles.ipynb))."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# List all vehicles in FASTSim 3 resources\n",
+ "for name in fsim.Vehicle.list_resources():\n",
+ " print(name)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Load a vehicle from FASTSim 3 resources\n",
+ "veh = fsim.Vehicle.from_resource(\"2012_Ford_Fusion.yaml\")\n",
+ "\n",
+ "# You can also load from a YAML file on disk:\n",
+ "# veh = fsim.Vehicle.from_file(\"my_vehicle.yaml\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-9",
+ "metadata": {},
+ "source": [
+ "### Converting a FASTSim 2 vehicle file\n",
+ "\n",
+ "If you have existing FASTSim 2 vehicle YAMLs, use `Vehicle.from_file` to load them directly as FASTSim 3 vehicles. This is the same function to load regular FASTSim 3 vehicle YAML files, and will automatically detect and read in both FASTSim 2 and FASTSim 3 vehicle files. You can then re-serialize them as FASTSim 3 YAMLs (via `veh.to_file(...)`) for future use.\n",
+ "\n",
+ "Note that not every FASTSim 2 field has a 1-to-1 match in FASTSim 3. See the [Field-Mapping Reference](#field-mapping-reference-guide) tables at the end of this guide for details on how FASTSim 2 vehicle parameters line up with FASTSim 3 parameters."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a31d42b8",
+ "metadata": {},
+ "source": [
+ "How to read a FASTSim 2 vehicle into FASTSim 3:\n",
+ "```python\n",
+ "veh_from_f2 = fsim.Vehicle.from_file(\"fastsim_2_vehicle.yaml\")\n",
+ "```\n",
+ "\n",
+ "Then, save it to a FASTSim 3 vehicle YAML file for future use:\n",
+ "```python\n",
+ "veh_from_f2.to_file(\"converted_vehicle.yaml\")\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-11",
+ "metadata": {},
+ "source": [
+ "## Reading Vehicle Parameters\n",
+ "\n",
+ "In FASTSim 2 you accessed parameters as flat attributes on the `Vehicle` object:\n",
+ "\n",
+ "```python\n",
+ "# FASTSim 2\n",
+ "veh.fc_max_kw # 130.5\n",
+ "veh.ess_max_kwh # not applicable - 0.0 for conventional\n",
+ "veh.drag_coef # 0.393\n",
+ "veh.veh_kg # 1644\n",
+ "```\n",
+ "\n",
+ "In FASTSim 3 the recommended approach is to call `to_pydict(flatten=True)`, which returns a flat `dict` whose keys use dot-separated paths matching the nested vehicle structure. See the [Field-Mapping Reference](#field-mapping-reference-guide) section of this guide for a list of FASTSim 2 vehicle variables and their corresponding FASTSim 3 variable paths/names, since in many cases both paths to variables and names have been updated."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-12",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "d = veh.to_pydict(flatten=True)\n",
+ "\n",
+ "print(\"name :\", d[\"name\"])\n",
+ "print(\"year :\", d[\"year\"])\n",
+ "print(\"mass_kilograms :\", d[\"mass_kilograms\"], \"kg\")\n",
+ "print(\"drag_coef :\", d[\"chassis.drag_coef\"])\n",
+ "print(\"frontal area :\", d[\"chassis.frontal_area_square_meters\"], \"m^2\")\n",
+ "print(\"FC peak power :\", d[\"pt_type.Conv.fc.pwr_out_max_watts\"] / 1e3, \"kW\")\n",
+ "print(\"FS energy capac. :\", d[\"pt_type.Conv.fs.energy_capacity_joules\"] / 3.6e6, \"kWh\")\n",
+ "print(\"aux base load :\", d[\"pwr_aux_base_watts\"], \"W\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-13",
+ "metadata": {},
+ "source": [
+ "For quick inspection, FASTSim 3 exposes convenience attributes for the main powertrain components:\n",
+ "\n",
+ "- `veh.fc` - fuel converter (Conv, HEV, PHEV)\n",
+ "- `veh.res` - reversible energy storage / battery (HEV, PHEV, BEV)\n",
+ "- `veh.em` - electric machine / motor (HEV, PHEV, BEV)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-14",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(veh.fc)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-15",
+ "metadata": {},
+ "source": [
+ "### Unit updates\n",
+ "\n",
+ "FASTSim 3 field names always include the unit as a suffix, so there is no ambiguity. When translating FASTSim 2 code, remember to convert:\n",
+ "\n",
+ "| Quantity | FASTSim 2 unit | FASTSim 3 unit |\n",
+ "| --- | --- | --- |\n",
+ "| Power | kW | W |\n",
+ "| Energy | kWh | J |\n",
+ "| Speed | mph | m/s |\n",
+ "| Mass, length, time, temp | kg, m, s, K | same |\n",
+ "\n",
+ "NOTE: for FASTSim 2 vehicles converted into FASTSim 3 vehicles using `Vehicle.from_file`, these updates happen automatically."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-16",
+ "metadata": {},
+ "source": [
+ "## Modifying Vehicle Parameters\n",
+ "\n",
+ "**In FASTSim 2**, you could assign values to variables directly:\n",
+ "\n",
+ "```python\n",
+ "# FASTSim 2\n",
+ "veh.fc_max_kw = 150\n",
+ "veh.drag_coef = 0.30\n",
+ "```\n",
+ "\n",
+ "**In FASTSim 3**, `Vehicle` objects are immutable from Python. To modify a field, convert to a nested Python dictionary, modify, and then convert back:\n",
+ "\n",
+ "1. `d = veh.to_pydict(flatten=False)` - convert to nested dict\n",
+ "2. Edit `d`\n",
+ "3. `veh = fsim.Vehicle.from_pydict(d)` - convert back to a FASTSim 3 Vehicle"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-17",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Example modifying fuel converter peak power (+15%) and drag coefficient\n",
+ "\n",
+ "# convert vehicle to nested dictionary\n",
+ "d = veh.to_pydict(flatten=False)\n",
+ "\n",
+ "# Modify the nested dictionary\n",
+ "d[\"pt_type\"][\"Conv\"][\"fc\"][\"pwr_out_max_watts\"] *= 1.15\n",
+ "d[\"chassis\"][\"drag_coef\"] = 0.30\n",
+ "\n",
+ "# Convert back to a Vehicle object\n",
+ "veh_modified = fsim.Vehicle.from_pydict(d)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-18",
+ "metadata": {},
+ "source": [
+ "## Loading a Drive Cycle\n",
+ "\n",
+ "In FASTSim 2, cycles in FASTSim resources and custom cycles were loaded using `from_file`:\n",
+ "\n",
+ "```python\n",
+ "resource_cyc = fsim.cycle.Cycle.from_file(\"udds\") # loading a cycle from resource\n",
+ "custom_cyc = fsim.cycle.Cycle.from_file(\"path/to/custom_cycle.csv\") # loading a custom cycle from a file\n",
+ "```\n",
+ "\n",
+ "FASTSim 3 uses separate `from_resource` / `from_file` methods to load cycles, similar to how vehicles are loaded. You can use `list_resources` to view the cycles available in FASTSim resources:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-19",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# List cycles in resources\n",
+ "print(\"Cycles provided in FASTSim resources:\", fsim.Cycle.list_resources())\n",
+ "\n",
+ "# loading a cycle from resources\n",
+ "cyc = fsim.Cycle.from_resource(\"udds.csv\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0e9ee254",
+ "metadata": {},
+ "source": [
+ "Cycles can also be loaded from file:\n",
+ "```python\n",
+ "cyc = fsim.Cycle.from_file(\"custom_cycle.csv\")\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-20",
+ "metadata": {},
+ "source": [
+ "## Running a Simulation\n",
+ "\n",
+ "Four things changed:\n",
+ "\n",
+ "1. **Class name:** `fsim.SimDrive` (was `fsim.simdrive.SimDrive`)\n",
+ "2. **Argument order:** `SimDrive(veh, cyc)` (was `SimDrive(cyc, veh)` -- order of inputs switched)\n",
+ "3. **Run method:** `sd.walk()` (was `sd.sim_drive()`)\n",
+ "4. **Save intervals:** configurable using `set_save_interval` (not configurable in FASTSim 2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-21",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create simdrive object and run a simulation\n",
+ "sd = fsim.SimDrive(veh, cyc)\n",
+ "sd.walk()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-26",
+ "metadata": {},
+ "source": [
+ "FASTSim 3 lets you configure how much time-series data is recorded via `set_save_interval` (see below). Saving less time-series data (or setting to None) allows for faster simulation when detailed time-series results aren't needed.\n",
+ "\n",
+ "FASTSim 2 always recorded every time step. FASTSim 3 lets you trade time-series detail for speed:\n",
+ "\n",
+ "- `veh.set_save_interval(1)` - record every step (default; needed for time-series plots).\n",
+ "- `veh.set_save_interval(n)` - record every *n*-th step.\n",
+ "- `veh.set_save_interval(None)` - disable per-step recording entirely. About 10× faster than FASTSim 2. Cumulative totals from `sd.to_pydict(flatten=True)` are still available.\n",
+ "\n",
+ "Use `None` for parameter sweeps, large batch runs, and other applications where you only need aggregate results."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Fast run: no per-step recording, cumulative totals only\n",
+ "veh_fast = fsim.Vehicle.from_resource(\"2012_Ford_Fusion.yaml\")\n",
+ "veh_fast.set_save_interval(None)\n",
+ "\n",
+ "sd_fast = fsim.SimDrive(veh_fast, cyc)\n",
+ "sd_fast.walk()\n",
+ "\n",
+ "# to_pydict still works - history arrays will be empty but state totals are populated\n",
+ "sd_dict = sd_fast.to_pydict(flatten=True)\n",
+ "print(\"Fuel energy:\", sd_dict[\"veh.pt_type.Conv.fc.state.energy_fuel_joules\"] / 3.6e6, \"kWh\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-22",
+ "metadata": {},
+ "source": [
+ "## Reading Simulation Results\n",
+ "\n",
+ "FASTSim 2 exposed results as array attributes on the `SimDrive` object:\n",
+ "\n",
+ "```python\n",
+ "# FASTSim 2\n",
+ "sd.mph_ach # numpy array of achieved speeds (mph)\n",
+ "sd.fc_kw_in_ach # numpy array of fuel power in (kW)\n",
+ "sd.fc_kw_out_ach # numpy array of fuel power out (kW)\n",
+ "sd.fs_kwh_out_ach[-1] # total fuel energy consumed (kWh)\n",
+ "sd.soc # state of charge (for HEV/PHEV/BEV)\n",
+ "```\n",
+ "\n",
+ "FASTSim 3 exposes results through two methods on `SimDrive`:\n",
+ "\n",
+ "- **`sd.to_dataframe()`** - returns a Polars DataFrame (pass `pandas=True` for pandas). Recommended for accessing time series data. Column names are dot-separated paths mirroring the vehicle hierarchy.\n",
+ "- **`sd.to_pydict(flatten=True)`** - returns a flat `dict`. Used to access cumulative end-of-simulation totals which live under `*.state.*`. Available even when `set_save_interval(None)` is used."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-23",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Time-series results as a pandas DataFrame\n",
+ "df = sd.to_dataframe(pandas=True)\n",
+ "\n",
+ "# FASTSim 2: sd.mph_ach\n",
+ "# FASTSim 3 (in m/s):\n",
+ "speed_ms = df[\"veh.history.speed_ach_meters_per_second\"]\n",
+ "\n",
+ "# FASTSim 2: sd.fc_kw_in_ach\n",
+ "# FASTSim 3 (in W):\n",
+ "fc_pwr_fuel_w = df[\"veh.pt_type.Conv.fc.history.pwr_fuel_watts\"]\n",
+ "\n",
+ "# FASTSim 2: sd.fc_kw_out_ach\n",
+ "# FASTSim 3 (in W):\n",
+ "fc_pwr_prop_w = df[\"veh.pt_type.Conv.fc.history.pwr_prop_watts\"]\n",
+ "\n",
+ "print(\n",
+ " df[\n",
+ " [\n",
+ " \"cyc.time_seconds\",\n",
+ " \"veh.history.speed_ach_meters_per_second\",\n",
+ " \"veh.pt_type.Conv.fc.history.pwr_fuel_watts\",\n",
+ " \"veh.pt_type.Conv.fc.history.pwr_prop_watts\",\n",
+ " ]\n",
+ " ].head(10)\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-24",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Scalar cumulative totals via to_pydict(flatten=True).\n",
+ "# These are the FASTSim 3 equivalents of cumulative scalars accessed as the\n",
+ "# last element of an array in FASTSim 2 (e.g. sd.fs_kwh_out_ach[-1]).\n",
+ "sd_dict = sd.to_pydict(flatten=True)\n",
+ "\n",
+ "fuel_energy_kwh = sd_dict[\"veh.pt_type.Conv.fc.state.energy_fuel_joules\"] / 3.6e6\n",
+ "distance_km = sd_dict[\"veh.state.dist_meters\"] / 1e3\n",
+ "cyc_met = sd_dict[\"veh.state.cyc_met_overall\"]\n",
+ "\n",
+ "print(f\"Fuel energy consumed : {fuel_energy_kwh:.2f} kWh\")\n",
+ "print(f\"Distance driven : {distance_km:.2f} km\")\n",
+ "print(f\"Fuel economy : {distance_km / fuel_energy_kwh:.2f} km/kWh\")\n",
+ "print(f\"Cycle met throughout : {cyc_met}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-25",
+ "metadata": {},
+ "source": [
+ "### Updating Result Paths\n",
+ "\n",
+ "Common FASTSim 2 result attributes and their FASTSim 3 equivalents:\n",
+ "\n",
+ "| FASTSim 2 | FASTSim 3 |\n",
+ "| --- | --- |\n",
+ "| `sd.cyc.mps` (target speed) | `sd.to_dataframe(pandas=True)[\"cyc.speed_meters_per_second\"]` |\n",
+ "| `sd.mph_ach` | `sd.to_dataframe(pandas=True)[\"veh.history.speed_ach_meters_per_second\"]` |\n",
+ "| `sd.dist_mi[-1]` | `sd.to_pydict(flatten=True)[\"veh.state.dist_meters\"]` (in meters) |\n",
+ "| `sd.fc_kw_out_ach` | `sd.to_dataframe(pandas=True)[\"veh.pt_type..fc.history.pwr_prop_watts\"]` |\n",
+ "| `sd.fc_kw_in_ach` | `sd.to_dataframe(pandas=True)[\"veh.pt_type..fc.history.pwr_fuel_watts\"]` |\n",
+ "| `sd.fs_kwh_out_ach[-1]` | `sd.to_pydict(flatten=True)[\"veh.pt_type..fc.state.energy_fuel_joules\"]` |\n",
+ "| `sd.soc` | `sd.to_dataframe(pandas=True)[\"veh.pt_type..res.history.soc\"]` |\n",
+ "| `sd.ess_kw_out_ach` | `sd.to_dataframe(pandas=True)[\"veh.pt_type..res.history.pwr_out_electrical_watts\"]` |\n",
+ "| `sd.mc_kw_out_ach` | `sd.to_dataframe(pandas=True)[\"veh.pt_type..em.history.pwr_prop_watts\"]` |\n",
+ "\n",
+ "Replace `` with the actual powertrain variant returned by `veh.veh_type()`.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-30",
+ "metadata": {},
+ "source": "(field-mapping-reference-guide)=\n## Field-Mapping Reference Guide\n\nThe tables below map every FASTSim 2 `Vehicle` field to its FASTSim 3 equivalent. FASTSim 3 paths are the keys returned by `veh.to_pydict(flatten=True)`. Paths with `` change based on the powertrain type: `Conv`, `HEV`, `PHEV`, or `BEV`."
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-31",
+ "metadata": {},
+ "source": [
+ "### Vehicle top-level attributes\n",
+ "\n",
+ "*Present in all powertrain types.*\n",
+ "\n",
+ "| FASTSim 2 field | Description | FASTSim 3 path | Notes |\n",
+ "| --- | --- | --- | --- |\n",
+ "| `scenario_name` | Vehicle name | `name` | |\n",
+ "| `veh_year` | Model year | `year` | |\n",
+ "| `veh_pt_type` | Powertrain type string | `pt_type` | Use `veh.veh_type()` to read it as a string. |\n",
+ "| `doc` | Free-form doc string | `doc` | |\n",
+ "| `selection` | Vehicle database ID | N/A | Not in FASTSim 3. |\n",
+ "| `veh_kg` | Total vehicle mass | `mass_kilograms` | In FASTSim 3, mass can be set at the top level (`mass_kilograms`) **or** derived automatically by summing all component masses (chassis + powertrain parts). |\n",
+ "| `veh_override_kg` | Override for total mass | N/A | Not in FASTSim 3. |\n",
+ "| `comp_mass_multiplier` | Multiplier used by FASTSim 2 mass calc | N/A | Not in FASTSim 3. |"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-32",
+ "metadata": {},
+ "source": [
+ "### Chassis\n",
+ "\n",
+ "*Present in all powertrain types. Fields live under `chassis.*`.*\n",
+ "\n",
+ "| FASTSim 2 field | Description | FASTSim 3 path | Notes |\n",
+ "| --- | --- | --- | --- |\n",
+ "| `drag_coef` | Aerodynamic drag coefficient | `chassis.drag_coef` | |\n",
+ "| `frontal_area_m2` | Frontal area | `chassis.frontal_area_square_meters` | |\n",
+ "| `glider_kg` | Glider mass | `chassis.glider_mass_kilograms` | |\n",
+ "| `cargo_kg` | Cargo + passenger mass | `chassis.cargo_mass_kilograms` | |\n",
+ "| `veh_cg_m` | CG height (sign encodes drive type in F2) | `chassis.cg_height_meters` + `chassis.drive_type` | FASTSim 3 stores `abs(veh_cg_m)` as `cg_height_meters`; sign decoded into `drive_type` (`FWD`/`RWD`/`AWD`). |\n",
+ "| `drive_axle_weight_frac` | Weight fraction on drive axle | `chassis.drive_axle_weight_frac` | |\n",
+ "| `wheel_base_m` | Wheelbase | `chassis.wheel_base_meters` | |\n",
+ "| `wheel_inertia_kg_m2` | Per-wheel rotational inertia | `chassis.wheel_inertia_kilogram_square_meters` | |\n",
+ "| `num_wheels` | Number of wheels | `chassis.num_wheels` | |\n",
+ "| `wheel_rr_coef` | Rolling-resistance coefficient | `chassis.wheel_rr_coef` | |\n",
+ "| `wheel_radius_m` | Wheel radius | `chassis.wheel_radius_meters` | |\n",
+ "| `wheel_coef_of_fric` | Wheel–road friction coefficient | `chassis.wheel_fric_coef` | |\n",
+ "| N/A | Tire designation | `chassis.tire_code` | New in FASTSim 3. |"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-33",
+ "metadata": {},
+ "source": [
+ "### Fuel storage\n",
+ "\n",
+ "*Present in: `Conv`, `HEV`, `PHEV`. Not present in: `BEV`.*\n",
+ "\n",
+ "| FASTSim 2 field | Description | FASTSim 3 path | Notes |\n",
+ "| --- | --- | --- | --- |\n",
+ "| `fs_max_kw` | FS peak output power | `pt_type..fs.pwr_out_max_watts` | kW → W. |\n",
+ "| `fs_secs_to_peak_pwr` | FS ramp-up time | `pt_type..fs.pwr_ramp_lag_seconds` | |\n",
+ "| `fs_kwh` | FS energy capacity | `pt_type..fs.energy_capacity_joules` | kWh → J. |\n",
+ "| `fs_kwh_per_kg` | Fuel specific energy | `pt_type..fs.specific_energy_joules_per_kilogram` ||\n",
+ "| `fs_mass_kg` | Derived FS mass | `pt_type..fs.mass_kilograms` ||"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-34",
+ "metadata": {},
+ "source": [
+ "### Fuel converter\n",
+ "\n",
+ "*Present in: `Conv`, `HEV`, `PHEV`. Not present in: `BEV`.*\n",
+ "\n",
+ "| FASTSim 2 field | Description | FASTSim 3 path | Notes |\n",
+ "| --- | --- | --- | --- |\n",
+ "| `fc_max_kw` | FC peak continuous power | `pt_type..fc.pwr_out_max_watts` | kW → W. |\n",
+ "| `fc_sec_to_peak_pwr` | FC ramp-up time | `pt_type..fc.pwr_ramp_lag_seconds` | |\n",
+ "| `fc_eff_map` | FC efficiency map (y values) | `pt_type..fc.eff_interp_from_pwr_out` (values) | |\n",
+ "| `fc_pwr_out_perc` | FC output-power fraction x-grid | `pt_type..fc.eff_interp_from_pwr_out` (grid) | |\n",
+ "| `fc_eff_type` | `SI`/`Atkinson`/`Diesel`/`H2FC`/`HD_Diesel` | N/A | Not in FASTSim 3. |\n",
+ "| `fc_base_kg`, `fc_kw_per_kg` | FC mass model | N/A | Not in FASTSim 3. |\n",
+ "| `fc_mass_kg` | Derived FC mass | `pt_type..fc.mass_kilograms` | |\n",
+ "| `idle_fc_kw` | FC idle fuel power | `pt_type..fc.pwr_idle_fuel_watts` | |\n",
+ "| `min_fc_time_on` | Min FC on-time before shutoff | `pt_type..pt_cntrl.RGWDB.fc_min_time_on_seconds` | Lives in the powertrain controller, not on the FC itself. |\n",
+ "| `fc_peak_eff_override` | Curve-scaling override | N/A | Not in FASTSim 3. |"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-35",
+ "metadata": {},
+ "source": [
+ "### Reversible energy storage (battery)\n",
+ "\n",
+ "*Present in: `HEV`, `PHEV`, `BEV`. Not present in: `Conv`.*\n",
+ "\n",
+ "| FASTSim 2 field | Description | FASTSim 3 path | Notes |\n",
+ "| --- | --- | --- | --- |\n",
+ "| `ess_max_kw` | ESS peak power | `pt_type..res.pwr_out_max_watts` | kW → W. |\n",
+ "| `ess_max_kwh` | ESS energy capacity | `pt_type..res.energy_capacity_joules` | kWh → J. |\n",
+ "| `ess_round_trip_eff` | Round-trip efficiency | `pt_type..res.eff_interp` | Stored as a constant one-way efficiency `sqrt(ess_round_trip_eff)`. |\n",
+ "| `min_soc` / `max_soc` | SOC limits | `pt_type..res.min_soc` / `.max_soc` | |\n",
+ "| `ess_kg_per_kwh`, `ess_base_kg` | ESS mass model | N/A | Not in FASTSim 3. |\n",
+ "| `ess_mass_kg` | Derived ESS mass | `pt_type..res.mass_kilograms` | |\n",
+ "| `ess_life_coef_a`, `ess_life_coef_b` | Battery life fit | N/A | Not in FASTSim 3. |\n",
+ "| `ess_dischg_to_fc_max_eff_perc`, `ess_chg_to_fc_max_eff_perc`, `ess_to_fuel_ok_error` | Hybrid SOC-balancing knobs | N/A | Not in FASTSim 3. |\n",
+ "| `max_regen`, `max_regen_kwh`, `regen_a`, `regen_b` | Regen model | N/A | Not in FASTSim 3; FASTSim 3 handles regen limits via powertrain controls. |"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-36",
+ "metadata": {},
+ "source": [
+ "### Electric machine (motor)\n",
+ "\n",
+ "*Present in: `HEV`, `PHEV`, `BEV`. Not present in: `Conv`.*\n",
+ "\n",
+ "| FASTSim 2 field | Description | FASTSim 3 path | Notes |\n",
+ "| --- | --- | --- | --- |\n",
+ "| `mc_max_kw` | Motor peak continuous power | `pt_type..em.pwr_out_max_watts` | kW → W. |\n",
+ "| `mc_eff_map` | efficiency array | `pt_type..em.eff_interp_achieved` (values) | |\n",
+ "| `mc_pwr_out_perc` | Motor output-fraction x-grid | `pt_type..em.eff_interp_achieved` (grid) | |\n",
+ "| `mc_sec_to_peak_pwr` | Motor ramp-up time | N/A | Not in FASTSim 3. |\n",
+ "| `mc_mass_kg` | Derived motor mass | `pt_type..em.mass_kilograms` | |\n",
+ "| `mc_pe_base_kg`, `mc_pe_kg_per_kw` | Power-electronics mass model | N/A | Not in FASTSim 3. |\n",
+ "| `mc_peak_eff_override` | Curve-scaling override | N/A | Not in FASTSim 3. |"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-37",
+ "metadata": {},
+ "source": [
+ "### Transmission, aux loads, HEV controls\n",
+ "\n",
+ "**Transmission** (all powertrain types):\n",
+ "\n",
+ "| FASTSim 2 field | FASTSim 3 path | Notes |\n",
+ "| --- | --- | --- |\n",
+ "| `trans_eff` | `pt_type..transmission.eff_interp` | Stored as a constant efficiency. |\n",
+ "| `trans_kg` | `pt_type..transmission.mass_kilograms` | |\n",
+ "\n",
+ "**Auxiliary loads:**\n",
+ "\n",
+ "| FASTSim 2 field | FASTSim 3 path | Notes |\n",
+ "| --- | --- | --- |\n",
+ "| `aux_kw` | `pwr_aux_base_watts` | kW → W. |\n",
+ "| `alt_eff` | `pt_type.Conv.alt_eff` | Only on `Conv`; implicitly `1.0` on others. |\n",
+ "| `chg_eff` | N/A | Not in FASTSim 3. |\n",
+ "\n",
+ "**HEV / PHEV powertrain controls** (present on `HEV`, `PHEV`):\n",
+ "\n",
+ "| FASTSim 2 field | FASTSim 3 path | Notes |\n",
+ "| --- | --- | --- |\n",
+ "| `mph_fc_on` | `pt_type..pt_cntrl.RGWDB.speed_fc_forced_on_meters_per_second` | mph → m/s. |\n",
+ "| `kw_demand_fc_on` | `pt_type..pt_cntrl.RGWDB.frac_pwr_demand_fc_forced_on` | kW → fraction. |\n",
+ "| `min_fc_time_on` | `pt_type..pt_cntrl.RGWDB.fc_min_time_on_seconds` | |\n",
+ "| `stop_start` | `pt_type..pt_cntrl.StopStart.*` | Separate powertrain controller type in FASTSim 3 (for both `Conv` and `HEV`). Activate with `veh.use_stop_start_controller()`. |\n",
+ "| `force_aux_on_fc` | `pt_type..aux_cntrl` | `AuxOnFcPriority` (FC handles aux) or `AuxOnResPriority` (battery handles aux if feasible, default). |\n",
+ "| `max_accel_buffer_mph`, `max_accel_buffer_perc_of_useable_soc`, `perc_high_acc_buf` | See below | |\n",
+ "\n",
+ "The FASTSim 2 acceleration SOC-buffer fields are replaced by six RGWDB tuning fields (all under `pt_type..pt_cntrl.RGWDB.*`). Each buffer is defined by a reference speed (at which the buffer reaches its full size) and a coefficient that scales the buffer magnitude:\n",
+ "\n",
+ "| FASTSim 3 RGWDB field | Description |\n",
+ "| --- | --- |\n",
+ "| `speed_soc_disch_buffer_meters_per_second` | Reference speed for discharge / acceleration buffer |\n",
+ "| `speed_soc_disch_buffer_coeff` | Coefficient scaling the discharge buffer |\n",
+ "| `speed_soc_fc_on_buffer_meters_per_second` | Reference speed for the SOC threshold that forces the FC on |\n",
+ "| `speed_soc_fc_on_buffer_coeff` | Coefficient scaling the FC-on buffer |\n",
+ "| `speed_soc_regen_buffer_meters_per_second` | Reference speed for regen / charging buffer |\n",
+ "| `speed_soc_regen_buffer_coeff` | Coefficient scaling the regen buffer |\n",
+ "\n",
+ "**Validation reference values** (`val_udds_mpgge`, `val_hwy_mpgge`, `val_comb_mpgge`, `val0_to60_mph`, `val_range_miles`, …) are **not** carried over to FASTSim 3."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "fastsim-venv (3.10.11)",
+ "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.10.11"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/docs/content/migration-guide.md b/docs/content/migration-guide.md
deleted file mode 100644
index 860eb5980..000000000
--- a/docs/content/migration-guide.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# FASTSim 2 to 3 Migration Guide
-
-:::{note}
-🚧 This page is under construction.
-:::
diff --git a/docs/content/user-guide/user-guide.md b/docs/content/user-guide/user-guide.md
index f737fa57d..b70c5d777 100644
--- a/docs/content/user-guide/user-guide.md
+++ b/docs/content/user-guide/user-guide.md
@@ -20,4 +20,6 @@ Work with built-in and custom cycles
Execute simulations and inspect results
:::
-::::
\ No newline at end of file
+::::
+
+If you are coming from FASTSim-2, check out our [](../migration-guide.ipynb).
\ No newline at end of file
diff --git a/docs/myst.yml b/docs/myst.yml
index f9785ac2f..5519100ed 100644
--- a/docs/myst.yml
+++ b/docs/myst.yml
@@ -43,13 +43,14 @@ project:
- file: content/developers/vehicle-databases.md
- file: content/developers/making-releases.md
- file: content/developers/updating-docs.md
+ - file: content/migration-guide.ipynb
+ title: Migration Guide
- url: https://github.com/NatLabRockies/fastsim
title: GitHub Repository
- url: https://github.com/NatLabRockies/fastsim-vehicles
title: FASTSim Vehicle Database
- url: https://docs.rs/fastsim-core/latest/fastsim_core/
title: Rust API Documentation
- # - file: content/migration-guide.md
site:
template: book-theme
options: