waves-16-arma

git clone https://git.igankevich.com/waves-16-arma.git
Log | Files | Refs

commit 4cb75df8cdcd34f47801c908914a4f226f04d506
parent 5d5b96bf3b9c7754242aeb1f15be1a8077317822
Author: Ivan Gankevich <igankevich@ya.ru>
Date:   Mon, 29 May 2017 11:14:09 +0300

Insert verification section.

Diffstat:
R/common.R | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
R/transform.R | 23+++++++++++++++++++++++
R/velocity-potentials.R | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
R/waves.R | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arma.org | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 479 insertions(+), 0 deletions(-)

diff --git a/R/common.R b/R/common.R @@ -0,0 +1,168 @@ +source(file.path("R", "waves.R")) +source(file.path("R", "transform.R")) + +arma.qqplot_grid <- function (dir, params, titles, ...) { + wave_params <- arma.load_wave_parameters(dir, params) + i <- 1 + for (name in names(wave_params)) { + arma.qqplot(wave_params[[name]], 100, titles[[i]], ...) + i <- i + 1 + } +} + +arma.wavy_plot <- function (data, t, ...) { + slice <- data[data$t == t,] + x <- unique(slice$x) + y <- unique(slice$y) + z <- with(slice, { + n <- sqrt(length(z)) + out <- matrix(nrow=n, ncol=n) + out[cbind(x, y)] <- z + out + }) + nrz <- nrow(z) + ncz <- ncol(z) + # Create a function interpolating colors in the range of specified colors + jet.colors <- colorRampPalette( c("blue", "green") ) + # Generate the desired number of colors from this palette + nbcol <- 100 + color <- jet.colors(nbcol) + # Compute the z-value at the facet centres + zfacet <- z[-1, -1] + z[-1, -ncz] + z[-nrz, -1] + z[-nrz, -ncz] + # Recode facet z-values into color indices + facetcol <- cut(zfacet, nbcol) + persp(x, y, z, phi=30, theta=30, col=color[facetcol], ...) +} + +arma.skew_normal_1_plot <- function(x, params) { + data <- mapply( + function (s, k) arma.skew_normal_1(x, s, k), + params$skewness, + params$kurtosis + ) + plot.new() + plot.window(xlim=range(x),ylim=range(data)) + axis(1); axis(2); box() + for (i in seq_len(ncol(data))) { + d <- data[,i] + lines(x, d, lty=paste(params$linetypes[[i]])) + } + title(xlab="x", ylab="y") +} + + +arma.skew_normal_2_plot <- function(x, params) { + data <- mapply( + function (a) arma.skew_normal_2(x, a), + params$alpha + ) + plot.new() + plot.window(xlim=range(x),ylim=range(data)) + axis(1); axis(2); box() + for (i in seq_len(ncol(data))) { + d <- data[,i] + lines(x, d, lty=paste(params$linetypes[[i]])) + } + title(xlab="x", ylab="y") +} + +arma.fmt <- function(x, ndigits) { + format(round(x, ndigits), nsmall=ndigits) +} + +arma.plot_partitions <- function() { + library("rgl") + part_alpha <- 0.2 + part_col <- "grey" + part_size <- 2 + sc <- 0.8 + off <- part_size * (1-sc)/2 + bcol <- "grey" + balpha <- 1.0 + sc2 <- 1.0 - sc + off2 <- part_size * sc/2 + ccol <- "red" + calpha <- 1.0 + # whole parts + a1 <- cube3d(color=part_col, alpha=part_alpha) + a2 <- cube3d(color=part_col, alpha=part_alpha) + a3 <- cube3d(color=part_col, alpha=part_alpha) + shade3d(translate3d(a1, 0*part_size, 0, 0)) + shade3d(translate3d(a2, 1*part_size, 0, 0)) + shade3d(translate3d(a3, 2*part_size, 0, 0)) + # stripped parts + b1 <- scale3d(cube3d(color=bcol, alpha=balpha), sc, sc, sc) + b2 <- scale3d(cube3d(color=bcol, alpha=balpha), sc, sc, sc) + b3 <- scale3d(cube3d(color=bcol, alpha=balpha), sc, sc, sc) + shade3d(translate3d(b1, 0 + off, off, off)) + shade3d(translate3d(b2, 2 + off, off, off)) + shade3d(translate3d(b3, 4 + off, off, off)) + # overlap intervals + c1 <- scale3d(cube3d(color=ccol, alpha=calpha), sc2, 1, 1) + c2 <- scale3d(cube3d(color=ccol, alpha=calpha), sc2, 1, 1) + c3 <- scale3d(cube3d(color=ccol, alpha=calpha), sc2, 1, 1) + shade3d(translate3d(c1, 0 + off2, 0, 0)) + shade3d(translate3d(c2, 2 + off2, 0, 0)) + shade3d(translate3d(c3, 4 + off2, 0, 0)) +} + +arma.plot_ramp_up_interval <- function(label="Ramp-up interval") { + zeta <- read.csv(file.path("build", "standing_wave", "zeta.csv")) + t <- round(mean(zeta$t)) + res <- arma.wavy_plot(zeta, t, scale=FALSE) + library("grDevices") + ax <- 7 + ay <- 7 + my <- max(zeta$y) + lines(trans3d( + c(0, 0, ax, ax, 0), + c(0, my, my, 0, 0), + c(0, 0, 0, 0, 0), + pmat=res + ), col="red", lwd=3) + text(trans3d(0, my/2, max(zeta$z)*1.5, pmat=res), label, col="red", font=2) + from <- trans3d(0, my/2, max(zeta$z)*1.4, pmat=res) + to <- trans3d(0, my/2, max(zeta$z)*0.05, pmat=res) + arrows(from$x, from$y, to$x, to$y, lwd=2, angle=10, length=0.1, col="red") +} + +arma.plot_factory_vs_openmp <- function(...) { + args <- list(...) + perf <- read.csv(file.path("data", "performance", "factory-vs-openmp.csv")) + scale <- 10 ** args$power + x <- perf$nt * perf$nx * perf$ny / scale + plot.new() + plot.window(xlim=range(x),ylim=range(perf[c("openmp", "factory")])) + pts <- pretty(x) + axis(1, at=pts, labels=sapply(pts, function(x) {as.expression(bquote(.(x) %.% 10 ** .(args$power)))})) + axis(2) + box() + lines(x, perf$openmp, lty="solid") + lines(x, perf$factory, lty="dashed") + title(xlab=args$xlab, ylab=args$ylab) +} + +arma.plot_factory_vs_openmp_overlap <- function(...) { + args <- list(...) + openmp <- read.csv(file.path("data", "performance", "overlap-openmp.csv"), na.strings="") + factory <- read.csv(file.path("data", "performance", "overlap-factory.csv"), na.strings="") + openmp$t <- (openmp$t - min(openmp$t)) / args$scale + factory$t <- (factory$t - min(factory$t)) / args$scale + plot.new() + plot.window(xlim=range(c(factory$t, openmp$t)),ylim=range(0, 5)) + axis(1) + axis(2, at=c(1, 3), labels=args$labels, las=1, hadj=1) + # OpenMP + lines(openmp$t, rep.int(3, length(openmp$t))) + openmp_pts <- openmp[!is.na(openmp$mark),] + openmp_y <- rep.int(3, length(openmp_pts$t)) + points(openmp_pts$t, openmp_y) + text(openmp_pts$t, openmp_y, labels=openmp_pts$mark, pos=c(3, 3, 1, 1)) + # Factory + lines(factory$t, rep.int(1, length(factory$t))) + factory_pts <- factory[!is.na(factory$mark),] + factory_y <- rep.int(1, length(factory_pts$t)) + points(factory_pts$t, factory_y) + text(factory_pts$t, factory_y, labels=factory_pts$mark, pos=c(3, 1, 3, 1)) + title(xlab=args$xlab) +} diff --git a/R/transform.R b/R/transform.R @@ -0,0 +1,23 @@ +arma.skew_normal_1 <- function(z, skewness, kurtosis) { + (24 + 4*z*(-3 + z**2)* skewness + (3 - 6*z**2 + z**4)* kurtosis)/(24*(exp((z**2)/2)*sqrt(2*pi))) +} + +arma.bits.erf <- function(x) { + 2 * pnorm(x * sqrt(2)) - 1 +} + +arma.bits.erfc <- function(x) { + 2 * pnorm(x * sqrt(2), lower = FALSE) +} + +arma.bits.skewness_2 <- function(alpha) { + (sqrt(2) * (4 - pi) * (alpha**3)) / (sqrt(pi + (pi-2) * (alpha**2))**3) +} + +arma.bits.kurtosis_2 <- function(alpha) { + (8*(-3 + pi)*(alpha**4))/ ((pi + (-2 + pi)*(alpha**2))**2) +} + +arma.skew_normal_2 <- function(z, alpha) { + arma.bits.erfc( -((z*alpha)/sqrt(2)) ) / (exp((z**2)/2)*sqrt(2*pi)) +} diff --git a/R/velocity-potentials.R b/R/velocity-potentials.R @@ -0,0 +1,105 @@ +arma.middle_element <- function (x) { + x[round(length(x) + 0.5)/2] +} + +arma.plot_velocity_potential_field <- function (dir, ...) { + args <- list(...) + phi <- read.csv(file.path(dir, 'phi.csv')) + left_top_x <- 0.1 + right_top_x <- max(phi$x) + # slice time and Y ranges through the center + slice_t <- arma.middle_element(unique(phi$t)) + slice_y <- arma.middle_element(unique(phi$y)) + print(paste('Middle elements (TY) = ', slice_t, slice_y)) + phi_slice <- phi[phi$t == slice_t & phi$y == slice_y & phi$x >= left_top_x & phi$z >= -8,] + x <- unique(phi_slice$x) + z <- unique(phi_slice$z) + left_top_z <- max(phi_slice$z) + right_top_z <- left_top_z + print(paste('Velocity field size (XZ) = ', length(x), length(z))) + + # convert data frame to matrix + seq_x <- seq_along(x) + seq_z <- seq_along(z) + indices <- data.matrix(expand.grid(seq_x, seq_z)) + u <- with(phi_slice, { + out <- matrix(nrow=length(seq_x), ncol=length(seq_z)) + out[indices] <- phi + out + }) + + # get wave profile + zeta <- read.csv(file.path(dir, 'zeta.csv')) + zeta_slice <- zeta[zeta$t == slice_t & zeta$y == slice_y & zeta$x >= left_top_x,] + + plot.new() + plot.window(xlim=range(x),ylim=range(z),asp=1) + axis(1); axis(2); box() + + .filled.contour( + x, z, u, + levels=args$levels, + col=args$col + ) + + + contour( + x, z, u, + levels=args$levels, + asp=1, + drawlabels=TRUE, + add=TRUE + ) + + top_area_x <- c(left_top_x*0.99, zeta_slice$x, right_top_x*1.01) + top_area_z <- c(left_top_z*1.10, zeta_slice$z, right_top_z*1.10) + polygon(top_area_x, top_area_z, lwd=4, border=NA, col='white') + lines(zeta_slice$x, zeta_slice$z, lwd=4) + box() + title(xlab="x", ylab="z") +} + +arma.plot_velocity_potential_field_legend <- function (...) { + args <- list(...) + levels <- args$levels + col <- args$col + plot.new() + plot.window( + xlim = c(0, 1), + ylim = range(levels), + xaxs = "i", + yaxs = "i" + ) + rect(0, levels[-length(levels)], 1, levels[-1L], col = col) + axis(4) + box() +} + +arma.plot_velocity <- function(file1, file2, ...) { + args <- list(...) + data1 <- read.table(file1) + data2 <- read.table(file2) + ylim <- range(c(data1, data2)) + if ("ylim" %in% names(args)) { + ylim <- args$ylim + } + plot.new() + plot.window( + xlim = c(0, nrow(data1)-1), + ylim = ylim + ) + lines(data1, lty=args$linetypes[[1]]) + lines(data2, lty=args$linetypes[[2]]) + axis(1) + axis(2) + box() + title(xlab="x",ylab="u(x)") + legend( + "topleft", + c( + as.expression(bquote(u[1](x))), + as.expression(bquote(u[2](x))) + ), + lty = paste(args$linetypes) + ) +} diff --git a/R/waves.R b/R/waves.R @@ -0,0 +1,69 @@ +#!/usr/bin/Rscript + +arma.bits.qweibull <- function (x, param, sh) { + sh <- 2.0 + sc = param$mean / gamma(1.0 + 1.0 / sh) + qweibull(x, shape=sh, scale=sc) +} +arma.bits.qnorm <- function (x, param) { + qnorm(x, mean=param$mean, sd=param$sd) +} + +arma.QFUNCTIONS <- list( + elevation = arma.bits.qnorm, + heights_x = function (x, param) { arma.bits.qweibull(x, param, 2.0) }, + heights_y = function (x, param) { arma.bits.qweibull(x, param, 2.0) }, + lengths_x = function (x, param) { arma.bits.qweibull(x, param, 2.3) }, + lengths_y = function (x, param) { arma.bits.qweibull(x, param, 2.3) }, + periods = function (x, param) { arma.bits.qweibull(x, param, 3.0) } +) + +arma.ALL_WAVE_CHARACTERISTICS <- list( + "elevation", + "heights_x", + "heights_y", + "lengths_x", + "lengths_y", + "periods" +) + +arma.load_wave_parameters <- function ( + dir = "output", + wave_params = arma.ALL_WAVE_CHARACTERISTICS, + qfuncs = arma.QFUNCTIONS +) { + sapply(wave_params, function (filename) { + param <- list() + param$filename = filename + param$data <- read.table(file.path(dir, filename))[[1]] + param$mean <- mean(param$data) + param$sd <- sd(param$data) + param$qfunc <- function (x) { qfuncs[[filename]](x, param) } + param$min <- param$qfunc(.01) + param$max <- param$qfunc(.99) + elem <- list() + elem[[filename]] <- param + elem + }) +} + +arma.qqplot <- function (param, nsamples=100, ttl, ...) { + qdata <- param$qfunc(ppoints(nsamples)) + qqplot( + qdata, + param$data, + asp=1, + xlim=c(param$min, param$max), + ylim=c(param$min, param$max), + ... + ) + title(ttl, line=-2) + qqline(param$data, distribution=param$qfunc) +} + +#wave_params <- arma.load_wave_parameters() +#par(pty="s", mfrow=c(3, 3)) +#for (name in names(wave_params)) { +# print(name) +# arma.qqplot(wave_params[[name]]) +#} diff --git a/arma.org b/arma.org @@ -5,6 +5,7 @@ #+LATEX_CLASS_OPTIONS: #+LATEX_HEADER_EXTRA: \input{preamble} #+OPTIONS: H:5 num:0 todo:nil toc:nil +#+PROPERTY: header-args:R :results graphics :exports results #+begin_abstract Simulation of sea waves is a problem appearing in the framework of developing @@ -542,6 +543,119 @@ steps. trigonometric identities to shift the phase. ** Evaluation +In\nbsp{}cite:degtyarev2011modelling,degtyarev2013synoptic,boukhanovsky1997thesis AR +model the following items are verified experimentally: +- probability distributions of different wave characteristics (wave heights, + lengths, crests, periods, slopes, three-dimensionality), +- dispersion relation, +- retention of integral characteristics for mixed wave sea state. +In this work both AR and MA model are verified by comparing probability +distributions of different wave characteristics. + +*** Verification of wavy surface integral characteristics +In\nbsp{}cite:рожков1990вероятностные the authors show that several ocean wave +characteristics (listed in table\nbsp{}[[tab-weibull-shape]]) have Weibull distribution, +and wavy surface elevation has Gaussian distribution. In order to verify that +distributions corresponding to generated realisation are correct, +quantile-quantile plots are used (plots where analytic quantile values are used +for \(OX\) axis and estimated quantile values for \(OY\) axis). If the estimated +distribution matches analytic then the graph has the form of the straight line. +Tails of the graph may diverge from the straight line, because they can not be +reliably estimated from the finite-size realisation. Different methods of +extracting waves from realisation produce variations in quantile function tails, +it is probably impractical to extract every possible wave from realisation since +they may (and often) overlap. + +#+name: tab-weibull-shape +#+caption: Values of Weibull shape parameter for different wave characteristics. +#+attr_latex: :booktabs t +| Characteristic | Weibull shape (\(k\)) | +|----------------------+---------------------| +| Wave height | 2 | +| Wave length | 2.3 | +| Crest length | 2.3 | +| Wave period | 3 | +| Wave slope | 2.5 | +| Three-dimensionality | 2.5 | + +Verification was performed for standing and propagating waves. The corresponding +ACFs and quantile-quantile plots of wave characteristics distributions are shown +in +fig.\nbsp{}[[propagating-wave-distributions]],\nbsp{}[[standing-wave-distributions]],\nbsp{}[[acf-slices]]. + +#+name: propagating-wave-distributions +#+begin_src R :file build/propagating-wave-qqplots.pdf +source(file.path("R", "common.R")) +par(pty="s", mfrow=c(2, 2)) +arma.qqplot_grid( + file.path("build", "propagating_wave"), + c("elevation", "heights_y", "lengths_y", "periods"), + c("elevation", "height Y", "length Y", "period"), + xlab="x", + ylab="y" +) +#+end_src + +#+caption: Quantile-quantile plots for propagating waves. +#+label: propagating-wave-distributions +#+RESULTS: propagating-wave-distributions +[[file:build/propagating-wave-qqplots.pdf]] + +#+name: standing-wave-distributions +#+begin_src R :file build/standing-wave-qqplots.pdf +source(file.path("R", "common.R")) +par(pty="s", mfrow=c(2, 2)) +arma.qqplot_grid( + file.path("build", "standing_wave"), + c("elevation", "heights_y", "lengths_y", "periods"), + c("elevation", "height Y", "length Y", "period"), + xlab="x", + ylab="y" +) +#+end_src + +#+caption: Quantile-quantile plots for standing waves. +#+label: standing-wave-distributions +#+RESULTS: standing-wave-distributions +[[file:build/standing-wave-qqplots.pdf]] + +#+name: acf-slices +#+header: :width 6 :height 9 +#+begin_src R :file build/acf-slices.pdf +source(file.path("R", "common.R")) +propagating_acf <- read.csv(file.path("build", "propagating_wave", "acf.csv")) +standing_acf <- read.csv(file.path("build", "standing_wave", "acf.csv")) +par(mfrow=c(5, 2), mar=c(0,0,0,0)) +for (i in seq(0, 4)) { + arma.wavy_plot(standing_acf, i, zlim=c(-5,5)) + arma.wavy_plot(propagating_acf, i, zlim=c(-5,5)) +} +#+end_src + +#+caption: Time slices of ACF for standing (left column) and propagating waves (right column). +#+label: acf-slices +#+RESULTS: acf-slices +[[file:build/acf-slices.pdf]] + +Graph tails in fig.\nbsp{}[[propagating-wave-distributions]] deviate from original +distribution for individual wave characteristics, because every wave have to be +extracted from the resulting wavy surface to measure its length, period and +height. There is no algorithm that guarantees correct extraction of all waves, +because they may and often overlap each other. Weibull distribution right tail +represents infrequently occurring waves, so it deviates more than left tail. + +Correspondence rate for standing waves (fig.\nbsp{}[[standing-wave-distributions]]) +is lower for height and length, roughly the same for surface elevation and +higher for wave period distribution tails. Lower correspondence degree for +length and height may be attributed to the fact that Weibull distributions were +obtained empirically for ocean waves which are typically propagating, and +distributions may be different for standings waves. Higher correspondence degree +for wave periods is attributed to the fact that wave periods of standing waves +are extracted more precisely as the waves do not move outside simulated wavy +surface region. The same correspondence degree for wave elevation is obtained, +because this is the characteristic of the wavy surface (and corresponding AR or +MA process) and is not affected by the type of waves. + ** Discussion * Determining wave pressures for discretely given wavy surface ** Two-dimensional case