一部の例外を除けば農業は天気に強く依存する
suppressPackageStartupMessages(library(tidyverse))
suppressPackageStartupMessages(library(lubridate))
# devtools::install_github("KeachMurakami/agrmesh")
library(agrmesh)
ℹ WELCOME to R-AMGSDS interface (ver.0.0.1.4)
ℹ 農研機構は、農業分野や他の分野における研究・開発・教育・試用を目的とする者に、審査に基づきメッシュ農業気象データ(以下、「このデータ」と呼ぶ。)の利用を許可します。
ℹ 特に許可されない限り、このデータを他に転載したり第三者に提供したりすることはできません。
ℹ このデータを利用して作成した情報を販売することはできません。
ℹ 利用者は、利用期間の終了後、速やかに利用報告をすることとします。
ℹ 農研機構は、利用者がこのデータの利用によって生じた結果、ならびに、このデータが利用できないことによって生じた結果について、いかなる責任も負いません。
ℹ このデータを利用して得た成果等を公表する場合は、「農研機構メッシュ農業気象データ(The Agro-Meteorological Grid Square Data, NARO)」を利用した旨を明記してください。
✔ USERID and PASSWORD -> verified
# A tibble: 6,130 × 4
time lat lon SD
<date> <dbl> <dbl> <dbl>
1 2024-02-17 42.6 141. 45
2 2024-02-17 42.6 141. 43
3 2024-02-17 42.6 141. 44
4 2024-02-17 42.6 141. 41
5 2024-02-17 42.6 141. 43
6 2024-02-17 42.6 141. 47
7 2024-02-17 42.6 141. 41
8 2024-02-17 42.6 141. 41
9 2024-02-17 42.6 141. 44
10 2024-02-17 42.6 141. 39
# ℹ 6,120 more rows
# A tibble: 153 × 6
time lat lon site_id TMP_mea TMP_max
<date> <dbl> <dbl> <chr> <dbl> <dbl>
1 2071-05-01 43.1 141. 1 13.8 20.2
2 2071-05-02 43.1 141. 1 16.6 23.8
3 2071-05-03 43.1 141. 1 16.5 21.5
4 2071-05-04 43.1 141. 1 14.5 18.8
5 2071-05-05 43.1 141. 1 12.3 18.2
6 2071-05-06 43.1 141. 1 12.6 17.2
7 2071-05-07 43.1 141. 1 16.3 21.5
8 2071-05-08 43.1 141. 1 15.7 22.2
9 2071-05-09 43.1 141. 1 15.1 18.6
10 2071-05-10 43.1 141. 1 14.8 17.1
# ℹ 143 more rows
# 2011年の観測値ベースの気温を取得
temp_present <-
fetch_amgsds(times = ymd("2011-05-01", "2011-09-30"), elements = c("TMP_mea", "TMP_max"),
lats = site_lat, lons = site_lon)
# データを結合
temps <-
bind_rows(present = temp_present, future = temp_future, .id = "period") |>
mutate(date = yday(time) + ymd("2099-12-31")) # 年の異なるデータを並べて表示するための処理
print(temps)
# A tibble: 306 × 8
period time lat lon site_id TMP_mea TMP_max date
<chr> <date> <dbl> <dbl> <chr> <dbl> <dbl> <date>
1 present 2011-05-01 43.1 141. 1 10.8 13.5 2100-05-01
2 present 2011-05-02 43.1 141. 1 6.27 10.4 2100-05-02
3 present 2011-05-03 43.1 141. 1 6.69 10.0 2100-05-03
4 present 2011-05-04 43.1 141. 1 5.35 6.88 2100-05-04
5 present 2011-05-05 43.1 141. 1 7.15 11.3 2100-05-05
6 present 2011-05-06 43.1 141. 1 9.30 15.4 2100-05-06
7 present 2011-05-07 43.1 141. 1 10.8 13.5 2100-05-07
8 present 2011-05-08 43.1 141. 1 9.44 12.9 2100-05-08
9 present 2011-05-09 43.1 141. 1 10.3 14.0 2100-05-09
10 present 2011-05-10 43.1 141. 1 9.27 13.6 2100-05-10
# ℹ 296 more rows
定植 (5月1日) からの有効積算気温が2200 °C・日で収穫
※ 日付・数字は計算の一例で実態には即しません
\[有効積算気温 = \sum_i{\max(日平均気温_{\textrm{day } i}, 0)}\]
来週の天気もわからないのに50年後の天気なんて…
気象庁のwebページを引用
数値予報結果の誤差の原因は大きく2つに分けられ、ひとつは初期値に含まれる誤差が拡大すること、もうひとつは数値予報モデルが完全ではないことです。 数値予報では、わずかに異なる2つの初期値から予報した2つの予報結果は、初めのうち互いによく似ていますが、その差は時間の経過とともに拡大します。これは、大気の運動にある特徴的な性質「初期値の小さな差が将来大きく増大する」というカオス(混沌)的な振る舞いのひとつです。実際の数値予報では、観測データの誤差や解析手法の限界から、初期値に含まれる誤差をゼロにすることはできず、時間とともに誤差が拡大することを避けることはできません。 また、数値予報では、計算機の性能の限界により、ある大きさの格子を用いた近似式で気温や風等の予測計算を行います。このように近似式を使っていることからも、予報結果に誤差が生じます。
このような誤差の拡大を事前に把握するため、「アンサンブル(集団)予報」という数値予報の手法を利用しています。この手法では、ある時刻に少しずつ異なる初期値を多数用意するなどして多数の予報を行い、平均やばらつきの程度といった統計的な情報を用いて気象現象の発生を確率的に捉えることが可能となります。
気象庁のwebページを引用
数値予報結果の誤差の原因は大きく2つに分けられ、ひとつは初期値に含まれる誤差が拡大すること、もうひとつは数値予報モデルが完全ではないことです。 数値予報では、わずかに異なる2つの初期値から予報した2つの予報結果は、初めのうち互いによく似ていますが、その差は時間の経過とともに拡大します。これは、大気の運動にある特徴的な性質「初期値の小さな差が将来大きく増大する」というカオス(混沌)的な振る舞いのひとつです。実際の数値予報では、観測データの誤差や解析手法の限界から、初期値に含まれる誤差をゼロにすることはできず、時間とともに誤差が拡大することを避けることはできません。 また、数値予報では、計算機の性能の限界により、ある大きさの格子を用いた近似式で気温や風等の予測計算を行います。このように近似式を使っていることからも、予報結果に誤差が生じます。
このような誤差の拡大を事前に把握するため、「アンサンブル(集団)予報」という数値予報の手法を利用しています。この手法では、ある時刻に少しずつ異なる初期値を多数用意するなどして多数の予報を行い、平均やばらつきの程度といった統計的な情報を用いて気象現象の発生を確率的に捉えることが可能となります。
\[y_t = 1.1 \times y_{t-1} + \epsilon\]
sim_chaos <-
function(y0, times = 30){
noise <- rnorm(times, 0, .1)
y <- y0
for(i in 2:times){
y[i] <- 1.1 * y[i-1] + noise[i-1]
}
tibble(time = 1:times, y)
}
set.seed(20240217)
runif(10, min = 0.99, max = 1.01) |>
map_dfr(.id = "id", sim_chaos) |>
ggplot(aes(time, y, col = id, group = id)) +
geom_line(show.legend = FALSE)
個々のメンバーは
「50年に一度の…」のような確率的な影響評価
rNOMADS
パッケージで扱うことができるtidync
パッケージで読み込み# https://d4pdf.diasjp.net/d4PDF.cgiより全球実験の日平均気温 (高度 2 m; sfc_avr_day TA) のアンサンブルデータをダウンロード
# 同ページで提供されている切り出し用Pythonスクリプト (d4pdf-sb.py) を使用
# 昇温実験 (HFB_4K_**) については6気候モデルの15アンサンブルの各1年分
YOUR_DIAS_PW <- "XXX"
YOUR_DIAS_ID <- "XXX"
# 過去実験 (HPB) の90アンサンブルから1年ずつの気温推移を取得
walk(1:90, function(i){
system(
str_glue("
echo {YOUR_DIAS_PW} | python3 d4pdf-sb.py -u {YOUR_DIAS_ID} -o hpb_{i}.tar -f 2010-01 -t 2010-12 -e {i} -W 141 -E 142 -S 42 -N 43 GCM/HPB/sfc_avr_day TA
")
)
})
# 6気候モデルでの昇温実験 (HFB_4K_**) の各15アンサンブルから1年ずつの気温推移を取得
walk(101:115, function(i){
system(
str_glue("
echo {YOUR_DIAS_PW} | python3 d4pdf-sb.py -u {YOUR_DIAS_ID} -o hfb_cc_{i}.tar -f 2071-01 -t 2071-12 -e {i} -W 141 -E 142 -S 42 -N 43 GCM/HFB_4K_CC/sfc_avr_day TA
echo {YOUR_DIAS_PW} | python3 d4pdf-sb.py -u {YOUR_DIAS_ID} -o hfb_ha_{i}.tar -f 2071-01 -t 2071-12 -e {i} -W 141 -E 142 -S 42 -N 43 GCM/HFB_4K_HA/sfc_avr_day TA
echo {YOUR_DIAS_PW} | python3 d4pdf-sb.py -u {YOUR_DIAS_ID} -o hfb_gf_{i}.tar -f 2071-01 -t 2071-12 -e {i} -W 141 -E 142 -S 42 -N 43 GCM/HFB_4K_GF/sfc_avr_day TA
echo {YOUR_DIAS_PW} | python3 d4pdf-sb.py -u {YOUR_DIAS_ID} -o hfb_mi_{i}.tar -f 2071-01 -t 2071-12 -e {i} -W 141 -E 142 -S 42 -N 43 GCM/HFB_4K_MI/sfc_avr_day TA
echo {YOUR_DIAS_PW} | python3 d4pdf-sb.py -u {YOUR_DIAS_ID} -o hfb_mp_{i}.tar -f 2071-01 -t 2071-12 -e {i} -W 141 -E 142 -S 42 -N 43 GCM/HFB_4K_MP/sfc_avr_day TA
echo {YOUR_DIAS_PW} | python3 d4pdf-sb.py -u {YOUR_DIAS_ID} -o hfb_mr_{i}.tar -f 2071-01 -t 2071-12 -e {i} -W 141 -E 142 -S 42 -N 43 GCM/HFB_4K_MR/sfc_avr_day TA
")
)
})
# ダウンロードされたtarファイルを解凍してまとめる
dir(pattern = ".tar$") |>
walk(untar, exdir = "ensembles")
# GrADS -> NetCDF変換関数
# r-bloggersから拝借、元のブログはリンク切れに...
# https://www.r-bloggers.com/2012/01/converting-grads-files-to-netcdf-from-within-r-using-cdo/
# CDO (Climate Data Operators) というコマンドラインツールのインストールが必要
grads2nc <-
function(ctl_input, nc_output, verbose) {
if(Sys.which("cdo")[[1]] == ""){
stop("cdo executable not found. Check PATH or install cdo.")
}
if(verbose){
ext = ""
} else {
ext = "> /dev/null"
}
cmd = sprintf("cdo -f nc import_binary %s %s %s", ctl_input, nc_output, ext)
t = system.time(ret_code <- system(cmd))
if(verbose & (ret_code != 127)){
message(sprintf("Processing \"%s\" to \"%s\" is done, time spent:", ctl_input, nc_output))
print(t)
} else if(ret_code == 127){
stop("Conversion of grads file to nc failed")
}
return(invisible(ret_code))
}
# NetCDF -> tibble変換関数
# grads2ncで出力されたNetCDFを一時ファイルとして受け取り、tidyncで読み込む
read_grads <-
function(input, verbose = FALSE){
tmp <- tempfile()
grads2nc(input, nc_output = tmp, verbose = verbose)
# NetCDFを開いて緯度経度範囲指定で1グリッドの値を抽出する
output <-
tidync::tidync(tmp) |>
tidync::hyper_tibble(lon = between(lon, 141.6, 142),
lat = between(lat, 42.8, 43.2))
file.remove(tmp)
return(output)
}
# GrADSのファイルパスを取得し、文字列から各種情報を抜き出す
ctl_files <- dir("ensembles/", pattern = "ctl", recursive = TRUE, full.names = TRUE)
model <- str_extract(ctl_files, "HPB|HFB_4K_..")
member <- str_extract(ctl_files, "m[:digit:]{3}")
yyyymm <- str_extract(ctl_files, "[:digit:]{6}")
# GrADSファイルを一括で読み込んでtibble形式で整理する
temp_ensembles <-
ctl_files |>
map(read_grads) |>
list(model, member, yyyymm) |>
pmap_dfr(function(x1, x2, x3, x4){
x1 |>
transmute(
model = x2,
member = x3,
date = ymd(paste0(x4, time %/% 24 + 1)), # 時単位 -> 日単位
year = year(date),
TMP_mea = ta - 273.15, # 絶対温度 -> 摂氏
period = if_else(model == "HPB", "present", "future"),
dummy_date = yday(date) + ymd("2999-12-31") # 異なる年のデータを並べて表示するための処理)
)
})
# データ保存@dropbox
write_csv(temp_ensembles, "temp_ensembles.csv")
temp_ensembles <- read_csv("https://www.dropbox.com/scl/fi/wc91b6aif5fxn8gvl2kik/temp_ensembles.csv?rlkey=e0c3f4qgkcwacplm0ewzn6r9y&dl=1")
Rows: 65700 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): model, member, period
dbl (2): year, TMP_mea
date (2): date, dummy_date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# A tibble: 6 × 7
model member date year TMP_mea period dummy_date
<chr> <chr> <date> <dbl> <dbl> <chr> <date>
1 HFB_4K_CC m101 2071-01-01 2071 -3.15 future 3000-01-01
2 HFB_4K_CC m101 2071-01-02 2071 -2.23 future 3000-01-02
3 HFB_4K_CC m101 2071-01-03 2071 -5.68 future 3000-01-03
4 HFB_4K_CC m101 2071-01-04 2071 -4.34 future 3000-01-04
5 HFB_4K_CC m101 2071-01-05 2071 1.23 future 3000-01-05
6 HFB_4K_CC m101 2071-01-06 2071 0.603 future 3000-01-06
temp_ensembles |>
ggplot(aes(dummy_date, TMP_mea, col = model, group = paste(model, member, year))) +
geom_line(linewidth = .1, alpha = .1) +
geom_line(data = \(x) summarise(x, TMP_mea = mean(TMP_mea), .by = c(dummy_date, model)), aes(group = model)) +
scale_x_date(date_labels = "%b", date_breaks = "1 month", name = NULL)
cumtemp_ensembles <-
temp_ensembles |>
filter(month(date) %in% 5:9) |>
group_by(model, member, year) |>
mutate(TMP_cumsum = cumsum(pmax(0, TMP_mea)),
harvest = sum(TMP_cumsum < 2200) + min(dummy_date))
cumtemp_ensembles |>
group_by(period, member, model, year) |>
ggplot(aes(dummy_date, TMP_cumsum, col = model, group = paste(model, member, year))) +
geom_line(linewidth = .5, alpha = .5) +
geom_hline(yintercept = 2200) +
annotate("rect", fill = NA, col = "black", linetype = 2,
xmin = ymd("3000-08-01"), xmax = ymd("3000-09-30"), ymin = 2100, ymax = 2300)
謝辞: 本研究はJSPS科研費 JP23K14051の助成を受けたものです。
2024-02-17 sappoRo.R #11 @keach_sci