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.
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().
With 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 \times 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.