ef_moves() uses local
MOVES rate data to evaluate running-exhaust emission factors. It runs in
R on Linux, macOS and Windows. There is no database connection, SQL
query, Java process, network download or MOVES installation involved in
evaluating factors.
VEIN evaluates factors; it does not run MOVES. The bundled data are a
small reference set. To produce factors for other counties, years,
months, weather, fuels, pollutants or processes, use movesr, a standalone R
port of the MOVES rate engine that writes these tables with
movesr_export_vein() (see Generate factors with
movesr).
These inputs are explicit arguments of ef_moves():
| Argument | Meaning | Bundled reference data |
|---|---|---|
source_type_id |
MOVES vehicle category | all 13 on-road types |
fuel_type_id |
MOVES fuel type | every valid combination (names accepted) |
model_year |
Vehicle manufacturing year | 2000–2025 |
road_type_id |
MOVES road category | 5: urban unrestricted |
temperature |
Temperature in degrees C | 10, 20 or 30 |
rel_humidity |
Relative humidity in percent | 50 |
Use moves_vehicles() to list the available source-type
and fuel combinations with their names and IDs. The bundled data include
38 of the 48 MOVES6-valid vehicle/fuel combinations. The five fuels are
gasoline, diesel, E-85, CNG and electricity; not every fuel is valid for
every vehicle type. Combinations with no modelled running-exhaust
output, such as heavy electric trucks and CNG or electric motor homes,
are not listed.
Vehicle age is the inventory year minus model_year. The
bundled inventory year is 2025, so model_year = 2020
represents a five-year-old vehicle. For other datasets, choose the
inventory year with select = list(yearID = ...).
The small dataset shipped with VEIN contains MOVES6 running-exhaust
rates for a documented U.S. reference scenario. The selected model year
describes the vehicle’s year of manufacture; yearID is the
inventory year, which determines vehicle age. They must not be
interchanged.
library(vein)
x <- moves_factors()
moves_vehicles()
#> sourceTypeID sourceTypeName fuelTypeID
#> 1 11 Motorcycle 1
#> 2 21 Passenger Car 1
#> 3 21 Passenger Car 2
#> 4 21 Passenger Car 5
#> 5 21 Passenger Car 9
#> 6 31 Passenger Truck 1
#> 7 31 Passenger Truck 2
#> 8 31 Passenger Truck 5
#> 9 31 Passenger Truck 9
#> 10 32 Light Commercial Truck 1
#> 11 32 Light Commercial Truck 2
#> 12 32 Light Commercial Truck 5
#> 13 32 Light Commercial Truck 9
#> 14 41 Other Buses 1
#> 15 41 Other Buses 2
#> 16 41 Other Buses 3
#> 17 42 Transit Bus 1
#> 18 42 Transit Bus 2
#> 19 42 Transit Bus 3
#> 20 43 School Bus 1
#> 21 43 School Bus 2
#> 22 43 School Bus 3
#> 23 51 Refuse Truck 1
#> 24 51 Refuse Truck 2
#> 25 51 Refuse Truck 3
#> 26 52 Single Unit Short-haul Truck 1
#> 27 52 Single Unit Short-haul Truck 2
#> 28 52 Single Unit Short-haul Truck 3
#> 29 53 Single Unit Long-haul Truck 1
#> 30 53 Single Unit Long-haul Truck 2
#> 31 53 Single Unit Long-haul Truck 3
#> 32 54 Motor Home 1
#> 33 54 Motor Home 2
#> 34 61 Combination Short-haul Truck 1
#> 35 61 Combination Short-haul Truck 2
#> 36 61 Combination Short-haul Truck 3
#> 37 62 Combination Long-haul Truck 2
#> 38 62 Combination Long-haul Truck 3
#> fuelTypeDesc
#> 1 Gasoline
#> 2 Gasoline
#> 3 Diesel Fuel
#> 4 Ethanol (E-85)
#> 5 Electricity
#> 6 Gasoline
#> 7 Diesel Fuel
#> 8 Ethanol (E-85)
#> 9 Electricity
#> 10 Gasoline
#> 11 Diesel Fuel
#> 12 Ethanol (E-85)
#> 13 Electricity
#> 14 Gasoline
#> 15 Diesel Fuel
#> 16 Compressed Natural Gas (CNG)
#> 17 Gasoline
#> 18 Diesel Fuel
#> 19 Compressed Natural Gas (CNG)
#> 20 Gasoline
#> 21 Diesel Fuel
#> 22 Compressed Natural Gas (CNG)
#> 23 Gasoline
#> 24 Diesel Fuel
#> 25 Compressed Natural Gas (CNG)
#> 26 Gasoline
#> 27 Diesel Fuel
#> 28 Compressed Natural Gas (CNG)
#> 29 Gasoline
#> 30 Diesel Fuel
#> 31 Compressed Natural Gas (CNG)
#> 32 Gasoline
#> 33 Diesel Fuel
#> 34 Gasoline
#> 35 Diesel Fuel
#> 36 Compressed Natural Gas (CNG)
#> 37 Diesel Fuel
#> 38 Compressed Natural Gas (CNG)
x$runs[, c("masterVersion", "defaultDatabaseUsed", "massUnits", "distanceUnits")]
#> masterVersion defaultDatabaseUsed massUnits distanceUnits
#> 1 MOVES6.0.0 movesdb20260729 g mi
unique(x$rates[, c("yearID", "hourID", "temperature_C", "relHumidity")])
#> yearID hourID temperature_C relHumidity
#> 1 2025 1 20 50
#> 481 2025 2 10 50
#> 961 2025 3 30 50
range(x$rates$modelYearID)
#> [1] 2000 2025Select a vehicle and fuel by name or numeric ID. This example is a model-year 2020 diesel combination long-haul truck:
ef_moves(
pollutant = "NOx",
source_type_id = "Combination Long-haul Truck",
fuel_type_id = "Diesel Fuel",
model_year = 2020,
speed = c(20, 40, 60),
temperature = 20
)
#> Units: [g/km]
#> [1] 6.788542 3.318675 2.208248Here is NOx from a model-year 2020 gasoline passenger car at the hour-1 reference conditions. Numeric input speeds use km/h; results have units of g/km.
ef_moves("NOx", model_year = 2020, speed = c(20, 40, 60),
factors = x, select = list(hourID = 1))
#> Units: [g/km]
#> [1] 0.011671836 0.010784581 0.009399917temperature (degrees C) and rel_humidity
(percent) can select meteorological points directly. Any remaining
varying dimensions must be selected explicitly using
select. The function never averages together different
scenarios, model years, fuels, road types or temperatures.
The reference fleet and fuel assumptions describe the U.S. scenario recorded in the dataset. Application to Ecuador requires a suitable vehicle/technology mapping and local fuel, meteorology, road load and inspection assumptions. The input metadata and production notes are installed with the data:
Omitting speed returns a function of speed giving
numeric g/km. Build one function per model year in the same order as the
columns of the vehicle matrix.
years <- c(2020, 2010)
curves <- EmissionFactorsList(lapply(years, function(y) {
ef_moves("NOx", model_year = y, factors = x, select = list(hourID = 1))
}))
veh <- data.frame(MY2020 = c(100, 200), MY2010 = c(30, 50))
lengths <- units::set_units(c(0.5, 1), "km")
speeds <- data.frame(H1 = c(30, 50))
emissions <- emis(veh, lengths, ef = curves, speed = speeds,
profile = matrix(1, 1, 1), simplify = TRUE, verbose = FALSE)
emissions
#> This EmissionsArray has
#> 2 streets
#> 2 vehicle categories
#> 1 hours
#> , , 1
#>
#> [,1] [,2]
#> [1,] 0.5585133 0.4211443
#> [2,] 1.9508197 1.2258597The default method = "bin" selects the exported MOVES
rate for the corresponding speed bin. It preserves valid zeros and fails
if a requested bin is absent. Positive speeds up to 75 mph (120.7008
km/h) are accepted. Stationary idle needs an hour-based factor and
matching activity; a distance factor cannot describe it.
With method = "linear", factors are interpolated between
nominal MOVES bin speeds: 2.5, 5, 10, …, 75 mph. Both neighboring bins
must exist. Extrapolation is disabled. This is an approximation between
exported rates, so speed-bin lookup is the appropriate method for exact
reproduction of the reference table.
f <- ef_moves("NOx", model_year = 2020, factors = x,
select = list(hourID = 1), method = "linear")
f(c(20, 40, 60))
#> [1] 0.011547791 0.010795777 0.009323479
attr(f, "moves_metadata")$scenario
#> MOVESScenarioID MOVESRunID yearID monthID dayID hourID pollutantID
#> 76178 vein-reference-2025 4 2025 1 2 1 3
#> processID sourceTypeID regClassID SCC fuelTypeID modelYearID roadTypeID
#> 76178 1 21 0 NA 1 2020 5
#> temperature relHumidity temperature_C locationID
#> 76178 68 50 20 zone:261610Meteorology, model year and vehicle category are selected exactly; this first version does not interpolate those dimensions.
Start exhaust is grams per engine start, not g/km. Use the separate start data and function; there is deliberately no speed argument:
starts <- moves_start_factors()
#> Warning in require_bit64_if_needed(ans): Some columns are type 'integer64' but
#> package bit64 is not installed. Those columns will print as strange looking
#> floating point data. There is no need to reload the data. Simply
#> install.packages('bit64') to obtain the integer64 print method and print the
#> data again.
ef_moves_start(
"NOx", model_year = 2020,
source_type_id = "Passenger Car", fuel_type_id = "Gasoline",
select = list(hourID = 1)
)
#> MOVESScenarioID MOVESRunID yearID monthID dayID hourID zoneID
#> 4763 vein-events-2025 1 2025 1 2 1 261610
#> sourceTypeID regClassID SCC fuelTypeID modelYearID pollutantID processID
#> 4763 21 0 NA 1 2020 3 2
#> temperature relHumidity ratePerStart gperstart temperature_C basis
#> 4763 68 50 0.12535 0.12535 20 startThe evaporative data contain THC permeation (process 11), fuel vapor venting (process 12) and fuel leaks (process 13) of parked vehicles. All three are grams per vehicle in the hour: MOVES divides each hour’s emissions by the vehicle population. MOVES writes venting to a separate table (RatePerProfile) labelled with its temperature-profile ID, but its rate has the same basis.
evap <- moves_evap_factors()
#> Warning in require_bit64_if_needed(ans): Some columns are type 'integer64' but
#> package bit64 is not installed. Those columns will print as strange looking
#> floating point data. There is no need to reload the data. Simply
#> install.packages('bit64') to obtain the integer64 print method and print the
#> data again.
#> Warning in require_bit64_if_needed(ans): Some columns are type 'integer64' but
#> package bit64 is not installed. Those columns will print as strange looking
#> floating point data. There is no need to reload the data. Simply
#> install.packages('bit64') to obtain the integer64 print method and print the
#> data again.
#> Warning in require_bit64_if_needed(ans): Some columns are type 'integer64' but
#> package bit64 is not installed. Those columns will print as strange looking
#> floating point data. There is no need to reload the data. Simply
#> install.packages('bit64') to obtain the integer64 print method and print the
#> data again.
ef_moves_evap(
"THC", model_year = 2020, process = "all",
source_type_id = "Passenger Car", fuel_type_id = "Gasoline",
select = list(hourID = 1)
)
#> MOVESScenarioID MOVESRunID yearID monthID dayID hourID zoneID pollutantID
#> 837 vein-events-2025 1 2025 1 2 1 261610 1
#> 1899 vein-events-2025 1 2025 NA 2 1 NA 1
#> 2961 vein-events-2025 1 2025 1 2 1 261610 1
#> processID sourceTypeID regClassID SCC fuelTypeID modelYearID temperature
#> 837 11 21 0 NA 1 2020 68
#> 1899 12 21 0 NA 1 2020 68
#> 2961 13 21 0 NA 1 2020 68
#> relHumidity ratePerVehicle gpervehicle temperature_C temperatureProfileID
#> 837 50 0.00734352 0.00734352 20 NA
#> 1899 50 0.00264464 0.00264464 20 1.292525e-314
#> 2961 50 0.00728413 0.00728413 20 NA
#> basis
#> 837 vehicle
#> 1899 profile
#> 2961 vehicleThese event-based factors cannot be passed to emis(),
whose factors are g/km. Multiply start factors by the number of starts,
and evaporative factors by the number of vehicles in each hour. Start
and evaporative data are separate MOVES runs; their provenance is
recorded in movesrun_events.csv.
MOVES builds vapor venting only from the hours selected in a run: a vehicle whose cold soak started outside those hours contributes nothing. The bundled venting comes from a three-hour run with artificial temperatures and is illustrative only; generate full-day factors (all 24 hours) for inventories.
Brakewear (process 9), tirewear (10) and evaporative emissions while
driving (11–13) are also distance factors in MOVES
RatePerDistance. Select them with process;
PM2.5 and PM10 then refer to brake or tire particles (pollutants 116/106
and 117/107). The bundled reference set has running exhaust only, so
this example needs factors exported by movesr or MOVES:
x <- moves_factors("factors/rateperdistance.csv", "factors/movesrun.csv",
"factors/vehicles.csv")
ef_moves("PM2.5", model_year = 2020, speed = 50, factors = x,
process = "brake", select = list(hourID = 16))
ef_moves("THC", model_year = 2020, speed = 50, factors = x,
process = "venting", select = list(hourID = 16))movesr reproduces MOVES6 rates in R (running and start exhaust, brake and tire wear, evaporative permeation, vapor venting and leaks, HC species, CO2, SO2 and PM species) from the MOVES default database stored as Parquet, without Java, MariaDB or MOVES. It reproduces the running and start factors bundled with VEIN. Local weather, fuel supply, barometric pressure and I/M program can replace the U.S. county defaults.
# remotes::install_github("atmoschem/movesr")
library(movesr)
db <- movesr_database("movesdb-parquet")
met <- movesr_default_meteorology(db, county_id = 11001, month_id = 7)
running <- movesr_running_rates(db, county_id = 11001, month_id = 7,
meteorology = met, pollutant_id = c(2, 3, 87))
start <- movesr_start_rates(db, county_id = 11001, month_id = 7,
meteorology = met, pollutant_id = c(2, 3, 87))
evap <- movesr_evap(db, county_id = 11001, month_id = 7)
movesr_export_vein("factors", running = running, start = start, evap = evap,
database = db)
x <- vein::moves_factors("factors/rateperdistance.csv", "factors/movesrun.csv",
"factors/vehicles.csv")
s <- vein::moves_start_factors("factors/rateperstart.csv",
"factors/movesrun_events.csv",
"factors/vehicles.csv")
e <- vein::moves_evap_factors("factors/ratepervehicle.csv",
"factors/rateperprofile.csv",
"factors/movesrun_events.csv",
"factors/vehicles.csv")Data producers can run MOVES (or movesr) once and export
RatePerDistance and MOVESRun tables. R users
only need those local files or a saved RDS object. The importer reads
units from MOVESRun, preserves all original rate-table
dimensions, converts pollutant mass rates to g/km, and checks for
duplicate keys and missing provenance. It supports plain or
gzip-compressed CSV and TSV files.
x <- moves_factors("my_rateperdistance.csv", "my_movesrun.csv")
saveRDS(x, "my_moves_factors.rds")
# This file can be copied to an R installation on another OS.
x <- readRDS("my_moves_factors.rds")
f <- ef_moves("NOx", model_year = 2020, factors = x,
select = list(MOVESRunID = 1, yearID = 2025, hourID = 1))This interface accepts the distance-based processes (running exhaust 1, brakewear 9, tirewear 10 and evaporative 11–13 while driving), road types 2–5, and pollutant mass rates. Starts and parked evaporative emissions have their own functions; stationary idle and energy need their own rate bases and activity denominators. MOVES base operating-mode rates also need activity weighting and adjustments before they become distance-based factors.
EPA describes external use of rate tables in section 4.2.2 of the MOVES6 technical guidance.