Rfactor calculates rainfall erosivity from timestamped precipitation records.
A typical workflow consists of:
The package focuses specifically on rainfall erosivity. It does not calculate the other USLE or RUSLE factors and does not perform spatial interpolation or mapping.
library(Rfactor)rf_read_rainfall() expects a delimited file containing a timestamp column and a precipitation column.
Precipitation values represent rainfall depth during each observation interval, in millimetres.
The rainfall record does not need to contain every expected timestamp. Sparse records and temporal gaps are accepted when timestamp differences remain aligned with the declared base temporal resolution.
For this vignette, create a small synthetic 1-minute rainfall record containing two rainfall events:
The long dry period between them is deliberately absent from the input file.
event_1_time <- seq(
from = as.POSIXct(
"2025-07-01 12:00:00",
tz = "UTC"
),
by = "1 min",
length.out = 30
)
event_2_time <- seq(
from = as.POSIXct(
"2025-08-01 12:00:00",
tz = "UTC"
),
by = "1 min",
length.out = 30
)
example_rainfall <- data.frame(
datetime = format(
c(
event_1_time,
event_2_time
),
"%Y-%m-%d %H:%M:%S",
tz = "UTC"
),
precip_mm = c(
rep(1.0, 30),
rep(0.1, 30)
)
)
example_file <- tempfile(
fileext = ".csv"
)
utils::write.csv(
example_rainfall,
example_file,
row.names = FALSE
)Read the file through the public Rfactor reader:
rain <- rf_read_rainfall(
example_file,
datetime_col = "datetime",
precip_col = "precip_mm",
tz = "UTC",
expected_interval_min = 1
)
head(rain)
#> datetime precip_mm
#> 1 2025-07-01 12:00:00 1
#> 2 2025-07-01 12:01:00 1
#> 3 2025-07-01 12:02:00 1
#> 4 2025-07-01 12:03:00 1
#> 5 2025-07-01 12:04:00 1
#> 6 2025-07-01 12:05:00 1expected_interval_min = 1 declares that the underlying rainfall resolution is one minute.
The approximately one-month gap between the two synthetic events is accepted because the package does not require a temporally complete rainfall series.
The time zone should describe how the timestamps in the source data are to be interpreted. "UTC" is used here because the synthetic timestamps were created in UTC.
Calculation settings are created with rf_settings().
settings <- rf_settings()
settings
#> <rf_settings>
#> Storm break:
#> hours: 6
#> RIST precipitation setting (mm): 1.27 [metadata]
#> Storm omission:
#> precipitation criterion: enabled
#> precipitation below (mm): 12.7
#> intensity criterion: enabled
#> intensity below (mm/h): 25.4
#> intensity interval (min): 15
#> criterion logic: all
#> Energy equation: brown_foster_1987
#> Calculated intensities (min): 5, 10, 15, 20, 30, 60
#> Single-record energy: calculateThe principal defaults use:
"all" omission logic;With "all" omission logic, an event is omitted only if all enabled omission conditions are satisfied.
The comparisons are strict. For example, exactly 12.70 mm does not satisfy a criterion defined as precipitation less than 12.70 mm.
Independent rainfall events are identified with rf_identify_storms().
storms <- rf_identify_storms(
rain,
settings = settings
)
unique(
storms$storm_id
)
#> [1] 1 2With the default 6-hour break, consecutive positive-rainfall observations separated by 6 hours or less remain in the same event. A gap greater than 6 hours starts a new event.
Any positive rainfall observation resets the storm-break clock in the fixed-interval algorithm validated against RIST 3.99.10.
The object returned by rf_identify_storms() stores the calculation settings and temporal resolution as metadata, so the next calculation can normally use them automatically.
Use rf_calculate_ei30() to calculate event precipitation, maximum rolling rainfall intensities, kinetic energy, EI30, and erosive-event classification.
events <- rf_calculate_ei30(
storms
)
events[
,
c(
"storm_id",
"event_start",
"event_end",
"duration_min",
"precip_mm",
"i15_mm_h",
"i30_mm_h",
"energy_mj_ha",
"ei30",
"omitted",
"erosive"
)
]
#> storm_id event_start event_end duration_min precip_mm
#> 1 1 2025-07-01 12:00:00 2025-07-01 12:29:00 30 30
#> 2 2 2025-08-01 12:00:00 2025-08-01 12:29:00 30 3
#> i15_mm_h i30_mm_h energy_mj_ha ei30 omitted erosive
#> 1 60 60 8.3881338 503.288028 FALSE TRUE
#> 2 6 6 0.4059515 2.435709 TRUE FALSEEvent EI30 is calculated as
[ EI_{30} = E I_{30}, ]
where (E) is total rainfall kinetic energy in MJ/ha and (I_{30}) is the maximum continuous 30-minute rainfall intensity in mm/h.
EI30 therefore has units of MJ mm/(ha h).
The July event contains 30 mm of high-intensity rainfall and is retained as erosive under the default settings.
The August event contains only 3 mm at low intensity. It satisfies both default omission conditions and is therefore classified as non-erosive.
Notice that ei30 is still calculated for the omitted event. The erosive classification determines whether that event contributes to period aggregation.
Use rf_calculate_rfactor() to aggregate contributing event EI30 values by calendar month or year.
monthly <- rf_calculate_rfactor(
events,
period = "monthly"
)
monthly
#> year month R n_events
#> 1 2025 7 503.288 1
#> 2 2025 8 0.000 0Both July and August appear because both months contain identified rainfall events.
August has R = 0 and n_events = 0 because its rainfall event is non-erosive.
Months that are completely absent from the supplied event data are not created.
Yearly aggregation uses the same principle:
yearly <- rf_calculate_rfactor(
events,
period = "yearly"
)
yearly
#> year R n_events
#> 1 2025 503.288 1n_events is the number of erosive events with non-missing EI30 that actually contribute to the reported total.
Because the example rainfall record contains observations from only one year, the resulting yearly value is a period total, not a multi-year mean R-factor.
A yearly R value returned by rf_calculate_rfactor() is the sum of contributing event EI30 values calculated from the rainfall data available for that calendar year.
It should not by itself be interpreted as the climatological long-term mean annual rainfall-runoff erosivity factor used by USLE or RUSLE.
Once monthly or yearly R-factor values have been calculated for several years, rf_calculate_mean_rfactor() can be used to calculate their multi-year arithmetic mean.
For example, consider five yearly R-factor values:
yearly_multi_year <- data.frame(
year = 2020:2024,
R = c(
800,
900,
NA,
700,
0
)
)
annual_mean <- rf_calculate_mean_rfactor(
yearly_multi_year,
period = "yearly"
)
annual_mean
#> mean_R n_years
#> 1 600 4The missing value is excluded from the calculation, while the genuine zero is retained.
The mean is therefore calculated from:
800, 900, 700, 0
and n_years = 4.
A zero is valid information: it represents an available period with no contributing erosive events. An NA value instead represents an unavailable R-factor value and is not included in the mean.
For monthly input, a separate mean is calculated for each available calendar month.
monthly_multi_year <- data.frame(
year = c(
2020,
2021,
2022,
2020,
2021,
2022
),
month = c(
7,
7,
7,
8,
8,
8
),
R = c(
400,
500,
300,
0,
NA,
20
)
)
monthly_mean <- rf_calculate_mean_rfactor(
monthly_multi_year,
period = "monthly"
)
monthly_mean
#> month mean_R n_years
#> 1 7 400 3
#> 2 8 10 2July is calculated from three available yearly values. August is calculated from two available values because its missing value is excluded, while R = 0 remains part of the calculation.
The returned n_years column therefore reports the number of non-missing R-factor values actually used for each calendar month.
Calendar months that are completely absent from the supplied table are not generated.
The mean annual R-factor is calculated directly from yearly R-factor values.
It is not calculated by summing the twelve multi-year monthly means. Those two quantities need not be identical when different calendar months contain different numbers of available years.
rf_calculate_mean_rfactor() also does not determine whether an available monthly or yearly R-factor value was derived from a complete rainfall record.
Deriving a representative climatic R-factor therefore still requires an appropriate multi-year rainfall record together with an assessment of record completeness and representativeness. Rfactor deliberately leaves that assessment to the user.
The omission criteria can be disabled independently.
To include every identified rainfall event:
include_all <- rf_settings(
omit_precip = FALSE,
omit_intensity = FALSE
)
all_storms <- rf_identify_storms(
rain,
settings = include_all
)
all_events <- rf_calculate_ei30(
all_storms
)
all_events[
,
c(
"event_start",
"precip_mm",
"omitted",
"erosive"
)
]
#> event_start precip_mm omitted erosive
#> 1 2025-07-01 12:00:00 30 FALSE TRUE
#> 2 2025-08-01 12:00:00 3 FALSE TRUEWhen both omission criteria are disabled, every identified rainfall event is retained.
Three rainfall kinetic-energy equations are available:
"brown_foster_1987";"mcgregor_1995";"laws_parsons_1943".For example:
mcgregor_settings <- rf_settings(
energy_equation = "mcgregor_1995"
)
mcgregor_settings$energy_equation
#> [1] "mcgregor_1995"The selected equation is subsequently used by rf_calculate_ei30() when calculating event kinetic energy.
Requested rainfall-intensity durations must be compatible with the temporal resolution of the source rainfall data.
Each requested duration must be an exact multiple of the observation interval.
For example, 10-minute rainfall data can support 10-, 20-, 30-, and 60-minute rolling intensities:
settings_10min <- rf_settings(
intensity_durations_min = c(
10,
20,
30,
60
),
omit_intensity_duration_min = 10
)
settings_10min
#> <rf_settings>
#> Storm break:
#> hours: 6
#> RIST precipitation setting (mm): 1.27 [metadata]
#> Storm omission:
#> precipitation criterion: enabled
#> precipitation below (mm): 12.7
#> intensity criterion: enabled
#> intensity below (mm/h): 25.4
#> intensity interval (min): 10
#> criterion logic: all
#> Energy equation: brown_foster_1987
#> Calculated intensities (min): 10, 20, 30, 60
#> Single-record energy: calculateA true 5- or 15-minute intensity cannot be recovered directly from 10-minute rainfall totals.
EI30 additionally requires an exact 30-minute intensity window. Consequently, the source interval must divide 30 minutes exactly.
Fixed-interval Rfactor calculations have been empirically compared with RIST 3.99.10 using 1-, 5-, 10-, 15-, and 30-minute rainfall data.
Temporal aggregation can change maximum rainfall intensity, kinetic energy, and EI30 even when the total precipitation amount is preserved.
rf_read_rainfall() and rf_validate_rainfall() do not require every expected timestamp to be present.
During rainfall-event identification, Rfactor reconstructs the expected regular time grid only from the first through the last positive-rainfall observation belonging to each event.
Observations supplied by the user are preserved. Expected time positions absent from the supplied record are assigned zero recorded rainfall for the calculation.
This inserted zero is a computational representation of an absent source position. It does not assert that the interval was observed and dry, and it does not estimate missing precipitation.
Rfactor does not fill completely absent months or years and does not assess whether a rainfall record is climatologically complete.
The function help pages provide the complete argument and return-value documentation:
?rf_settings
?rf_read_rainfall
?rf_identify_storms
?rf_calculate_ei30
?rf_calculate_rfactor
?rf_calculate_mean_rfactorA separate methodology and validation vignette documents the kinetic-energy equations, event-separation experiments, RIST comparisons, temporal-resolution validation, and interpretation of the resulting erosivity quantities in greater detail.