R/AFMPSDAnalyser.R

Defines functions getSimplifiedRoughnessAgainstLenghscale getRoughnessAgainstLengthscaleIntersection getRoughnessAgainstLengthscale10nm getRoughnessAgainstLengthscale getIntersectionForRoughnessAgainstLengthscale getAutoIntersectionForRoughnessAgainstLengthscale saveOnDiskIntersectionForRoughnessAgainstLengthscale performAllPSDCalculation getPaddedAFMImage shiftedPSDuv shiftFFT2D AFMImagePSDAnalysis AFMImagePSDSlopesAnalysis

Documented in AFMImagePSDAnalysis AFMImagePSDSlopesAnalysis getAutoIntersectionForRoughnessAgainstLengthscale getIntersectionForRoughnessAgainstLengthscale getPaddedAFMImage performAllPSDCalculation saveOnDiskIntersectionForRoughnessAgainstLengthscale shiftedPSDuv shiftFFT2D

require("fftwtools")
require("pracma")

require("data.table")

require("gstat")
require(sp)

require("stringr")

# normality tests
require(gridExtra)
require(ggplot2)

#require(reshape2)

require(stats)

if(getRversion() >= "3.1.0") utils::suppressForeignCheck(c("r", "roughness","x","predict.gstat"))


#' @title AFM Image psd slope analysis
#' 
#' @description \code{AFMImagePSDSlopesAnalysis} stores the analysis of the second slope in roughness against lenghtscale
#' 
#' @slot lc to be removed ?
#' @slot wsat to be removed ?
#' @slot slope to be removed ?
#' @slot yintersept to be removed ?
#' @name AFMImagePSDSlopesAnalysis-class
#' @rdname AFMImagePSDSlopesAnalysis-class
#' @exportClass AFMImagePSDSlopesAnalysis
#' @author M.Beauvais
AFMImagePSDSlopesAnalysis<-setClass("AFMImagePSDSlopesAnalysis",
                                    slots = c(lc="numeric", 
                                              wsat="numeric", 
                                              slope="numeric",
                                              yintersept="numeric",
                                              tangente_point1="numeric",
                                              tangente_point2="numeric"),
                                    validity = function(object) { 
                                      return(TRUE)
                                    }
)

#' Constructor method of AFMImagePSDSlopesAnalysis Class.
#' 
#' @param .Object an AFMImagePSDSlopesAnalysis object
#' @rdname AFMImagePSDSlopesAnalysis-class
#' @export
setMethod("initialize",
          "AFMImagePSDSlopesAnalysis",
          function(.Object) {
            .Object@lc<-0
            .Object@wsat<-0
            .Object@slope<-0
            .Object@yintersept<-0
            .Object@tangente_point1<-0
            .Object@tangente_point2<-0
            validObject(.Object) ## valide l'objet
            return(.Object)
          })

#' Wrapper function AFMImagePSDSlopesAnalysis
#'
#' @rdname AFMImagePSDSlopesAnalysis-class
#' @export
AFMImagePSDSlopesAnalysis <- function() {
  return(new("AFMImagePSDSlopesAnalysis"))
}


#' @title AFM image Power Spectrum Density analysis class
#' 
#' @description \code{AFMImagePSDAnalysis} handles an \code{\link{AFMImage}} roughness against lenghscale analysis 
#'
#' @slot roughnessAgainstLengthscale a data.table to store the roughness against lengthscale data
#' @slot intersections a list to store the lengthscales values as the intersections between slopes and the sill in roughness against lenghscale graph
#' @slot updateProgress a function to update a graphical user interface
#' @name AFMImagePSDAnalysis-class
#' @rdname AFMImagePSDAnalysis-class
#' @author M.Beauvais
AFMImagePSDAnalysis<-setClass("AFMImagePSDAnalysis",
                              slots = c(
                                psd1d_breaks="numeric",
                                psd2d_truncHighLengthScale="logical",
                                psd2d_maxHighLengthScale="numeric",
                                psd1d="data.table",
                                psd2d="data.table",
                                roughnessAgainstLengthscale="data.table",
                                intersections="numeric",
                                AFMImagePSDSlopesAnalysis1="AFMImagePSDSlopesAnalysis",
                                AFMImagePSDSlopesAnalysis2="AFMImagePSDSlopesAnalysis",
                                updateProgress="function"),
                              validity = function(object) { 
                                return(TRUE)
                              }
)

#' Constructor method of AFMImagePSDAnalysis Class.
#' 
#' @param .Object an AFMImagePSDAnalysis object
#' @rdname AFMImagePSDAnalysis-class
#' @export
setMethod("initialize",
          "AFMImagePSDAnalysis",
          function(.Object) {
            .Object@psd1d_breaks<-32
            .Object@psd2d_truncHighLengthScale<-TRUE
            .Object@psd2d_maxHighLengthScale<-0
            .Object@psd1d<-data.table()
            .Object@psd2d<-data.table()
            .Object@roughnessAgainstLengthscale<-data.table()
            validObject(.Object) ## valide l'objet
            return(.Object)
          })

#' Wrapper function AFMImagePSDAnalysis
#'
#' @rdname AFMImagePSDAnalysis-class
#' @export
AFMImagePSDAnalysis <- function() {
  return(new("AFMImagePSDAnalysis"))
}


#' Method \code{psd1d_breaks} returns a number of breaks to calculate PSD1D from PSD2D
#' @name AFMImagePSDAnalysis-class
#' @rdname AFMImagePSDAnalysis-class
setGeneric("psd1d_breaks",function(object){standardGeneric("psd1d_breaks")})
setGeneric(name= "psd1d_breaks<-", 
           def= function(AFMImagePSDAnalysis, value) {
             return(standardGeneric("psd1d_breaks<-"))
           })

#' @rdname AFMImagePSDAnalysis-class
#' @aliases psd1d_breaks
#' @param object a \code{\link{AFMImagePSDAnalysis}}
setMethod("psd1d_breaks",signature=signature(object='AFMImagePSDAnalysis'),
          function(object) {
            return(object@psd1d_breaks)
          }
)
setReplaceMethod(f="psd1d_breaks",
                 signature(AFMImagePSDAnalysis = "AFMImagePSDAnalysis", value = "numeric"),
                 definition= function(AFMImagePSDAnalysis, value) {
                   AFMImagePSDAnalysis@psd1d_breaks <- value
                   return(AFMImagePSDAnalysis)
                 })

#' Method \code{psd2d_maxHighLengthScale} returns the maximum lengthscale to be managed by PSD2D
#' @name AFMImagePSDAnalysis-class
#' @rdname AFMImagePSDAnalysis-class
setGeneric("psd2d_maxHighLengthScale",function(object){standardGeneric("psd2d_maxHighLengthScale")})
setGeneric(name= "psd2d_maxHighLengthScale<-", 
           def= function(AFMImagePSDAnalysis, value) {
             return(standardGeneric("psd2d_maxHighLengthScale<-"))
           })

#' @rdname AFMImagePSDAnalysis-class
#' @aliases psd2d_maxHighLengthScale
setMethod("psd2d_maxHighLengthScale",signature=signature(object='AFMImagePSDAnalysis'),
          function(object) {
            return(object@psd2d_maxHighLengthScale)
          }
)
setReplaceMethod(f="psd2d_maxHighLengthScale",
                 signature(AFMImagePSDAnalysis = "AFMImagePSDAnalysis", value = "numeric"),
                 definition= function(AFMImagePSDAnalysis, value) {
                   AFMImagePSDAnalysis@psd2d_maxHighLengthScale <- value
                   return(AFMImagePSDAnalysis)
                 })

#' Method \code{psd2d_truncHighLengthScale} returns if the lengthscale of PSD2D should be truncated
#' @name AFMImagePSDAnalysis-class
#' @rdname AFMImagePSDAnalysis-class
setGeneric("psd2d_truncHighLengthScale",function(object){standardGeneric("psd2d_truncHighLengthScale")})
setGeneric(name= "psd2d_truncHighLengthScale<-", 
           def= function(AFMImagePSDAnalysis, value) {
             return(standardGeneric("psd2d_truncHighLengthScale<-"))
           })

#' @rdname AFMImagePSDAnalysis-class
#' @aliases psd2d_truncHighLengthScale
setMethod("psd2d_truncHighLengthScale",signature=signature(object='AFMImagePSDAnalysis'),
          function(object) {
            return(object@psd2d_truncHighLengthScale)
          }
)
setReplaceMethod(f="psd2d_truncHighLengthScale",
                 signature(AFMImagePSDAnalysis = "AFMImagePSDAnalysis", value = "logical"),
                 definition= function(AFMImagePSDAnalysis, value) {
                   AFMImagePSDAnalysis@psd2d_truncHighLengthScale <- value
                   return(AFMImagePSDAnalysis)
                 })




#' Method \code{psd1d} returns a data.table of psd in 1D
#' @name AFMImagePSDAnalysis-class
#' @rdname AFMImagePSDAnalysis-class
setGeneric("psd1d",function(object){standardGeneric("psd1d")})
setGeneric(name= "psd1d<-", 
           def= function(AFMImagePSDAnalysis, value) {
             return(standardGeneric("psd1d<-"))
           })

#' @rdname AFMImagePSDAnalysis-class
#' @aliases psd1d
setMethod("psd1d",signature=signature(object='AFMImagePSDAnalysis'),
          function(object) {
            return(object@psd1d)
          }
)
setReplaceMethod(f="psd1d",
                 signature(AFMImagePSDAnalysis = "AFMImagePSDAnalysis", value = "data.table"),
                 definition= function(AFMImagePSDAnalysis, value) {
                   AFMImagePSDAnalysis@psd1d <- value
                   return(AFMImagePSDAnalysis)
                 })


#' Method \code{psd2d} returns a data.table of psd in 1D
#' @name AFMImagePSDAnalysis-class
#' @rdname AFMImagePSDAnalysis-class
setGeneric("psd2d",function(object){standardGeneric("psd2d")})
setGeneric(name= "psd2d<-", 
           def= function(AFMImagePSDAnalysis, value) {
             return(standardGeneric("psd2d<-"))
           })

#' @rdname AFMImagePSDAnalysis-class
#' @aliases psd2d
setMethod("psd2d",signature=signature(object='AFMImagePSDAnalysis'),
          function(object) {
            return(object@psd2d)
          }
)
setReplaceMethod(f="psd2d",
                 signature(AFMImagePSDAnalysis = "AFMImagePSDAnalysis", value = "data.table"),
                 definition= function(AFMImagePSDAnalysis, value) {
                   AFMImagePSDAnalysis@psd2d <- value
                   return(AFMImagePSDAnalysis)
                 })

#' Method \code{roughnessAgainstLengthscale} returns a data.table of roughnesses versus lengthscale
#' @name AFMImagePSDAnalysis-class
#' @rdname AFMImagePSDAnalysis-class
setGeneric("roughnessAgainstLengthscale",function(object){standardGeneric("roughnessAgainstLengthscale")})
setGeneric(name= "roughnessAgainstLengthscale<-", 
           def= function(AFMImagePSDAnalysis, value) {
             return(standardGeneric("roughnessAgainstLengthscale<-"))
           })


#' @rdname AFMImagePSDAnalysis-class
#' @aliases roughnessAgainstLengthscale
setMethod("roughnessAgainstLengthscale",signature=signature(object='AFMImagePSDAnalysis'),
          function(object) {
            return(object@roughnessAgainstLengthscale)
          }
)
setReplaceMethod(f="roughnessAgainstLengthscale",
                 signature(AFMImagePSDAnalysis = "AFMImagePSDAnalysis", value = "data.table"),
                 definition= function(AFMImagePSDAnalysis, value) {
                   AFMImagePSDAnalysis@roughnessAgainstLengthscale <- value
                   return(AFMImagePSDAnalysis)
                 })

#' Method \code{intersections} returns a intersection numeric value
#' @name AFMImagePSDAnalysis-class
#' @rdname AFMImagePSDAnalysis-class
setGeneric("intersections",function(object){standardGeneric("intersections")})
setGeneric(name= "intersections<-", 
           def= function(AFMImagePSDAnalysis, value) {
             return(standardGeneric("intersections<-"))
           })

#' @rdname AFMImagePSDAnalysis-class
#' @aliases intersections
setMethod("intersections",signature=signature(object='AFMImagePSDAnalysis'),
          function(object) {
            return(object@intersections)
          }
)
setReplaceMethod(f="intersections", 
                 signature(AFMImagePSDAnalysis = "AFMImagePSDAnalysis", value = "numeric"),
                 definition= function(AFMImagePSDAnalysis, value) {
                   AFMImagePSDAnalysis@intersections <- value
                   return(AFMImagePSDAnalysis)
                 })


#' Shift the quadrants of the FFT 2D
#'
#' \code{shiftFFT2D} returns the FFT 2D matrix shifted to put zero frequencies in the middle.
#' 
#' @param fft2data  the FFT 2D of the AFM image
#' @return The shifted matrix
#' @author M.Beauvais
#' @export
#' @examples
#' \dontrun{
#' library(AFM)
#' library(fftwtools)
#' 
#' data(AFMImageOfNormallyDistributedHeights)
#' AFMImage<-AFMImageOfNormallyDistributedHeights
#' nMheightsData= matrix(AFMImage@@data$h, nrow=AFMImage@@samplesperline)
#' shiftedFFT2D<-shiftFFT2D(fftwtools::fftw2d(nMheightsData))
#' }
shiftFFT2D<-function(fft2data) { 
  N=nrow(fft2data)
  M=ncol(fft2data)
  halfN=N/2
  halfM=M/2
  quadrant1=fft2data[1:halfN, seq(1,halfM)]
  quadrant2=fft2data[seq(halfN+1,N), seq(1,halfM)]
  quadrant3=fft2data[seq(halfN+1,N),seq(halfM+1,M)]
  quadrant4=fft2data[seq(1,halfN),seq(halfM+1,M)]
  return(rbind(cbind(quadrant3,quadrant2),cbind(quadrant4, quadrant1)))
}    


# zeroPadShiftedFFT2D<-function(shiftedFFT2Ddata){
#   N=nrow(fft2data)
#   M=ncol(fft2data)
#   
#   r = 2^(ceil(log2(x)))
# }

#' Calculate the shifted PSD matrix
#'
#' \code{shiftedPSDuv} returns the Power Spectral Density matrix in the frequency space from shifted FFT 2D
#' 
#' @param AFMImage an \code{\link{AFMImage}} from Atomic Force Microscopy
#' @return (1/NM^2) * abs(shiftedFFT2Ddata)^2) with N the number of lines of the sample and M the number of samples per line of the sample
#' @author M.Beauvais
#' @export
#' @examples
#' \dontrun{
#' library(AFM)
#' library(ggplot2)
#' 
#' data(AFMImageOfRegularPeaks)
#' AFMImage<-AFMImageOfRegularPeaks
#' nMheightsData= matrix(AFMImage@@data$h, nrow=AFMImage@@samplesperline)
#' shiftedPSDuv<-shiftedPSDuv(AFMImage)

#' a=AFMImage@@scansize
#' b=AFMImage@@scansize
#' 
#' M=AFMImage@@sampsline
#' N=AFMImage@@lines
#' NM=N*M # pixels^2
#' MN = M*N 
#' A=a*b
#' ab=a*b
#' 
#' dx=a/M
#' dy=b/N
#' 
#' um = seq( (1-(M+1)/2)/(M*dx), (M-(M+1)/2)/(M*dx), by=1/(M*dx))
#' vn = seq( (1-(N+1)/2)/(N*dy), (N-(N+1)/2)/(N*dy), by=1/(N*dy))
#' x = rep(um, times = AFMImage@@lines)
#' y = rep(vn, each = AFMImage@@sampsline)
#' z = as.vector(shiftedPSDuv)
#' 
#' data<-data.frame(x=x, y=y, z=z)
#' 
#' p5 <- qplot(x, y, data=data, colour=log10(z))
#' p5 <- p5 + scale_colour_gradientn(colours = rainbow(7))
#' p5 <- p5 + ylab("v")
#' p5 <- p5 + xlab("u")
#' title<-paste("shifted PSD of", basename(AFMImage@@fullfilename))
#' p5 <- p5 + ggtitle(title)
#' # Hide all the horizontal gridlines
#' p5 <- p5 + theme(panel.grid.minor.x=element_blank(), panel.grid.major.x=element_blank())
#' # Hide all the vertical gridlines
#' p5 <- p5 + theme(panel.grid.minor.y=element_blank(), panel.grid.major.y=element_blank())
#' p5 <- p5 + theme(panel.background = element_rect(fill = 'white', colour = 'black'))
#' p5
#' }
shiftedPSDuv<-function(AFMImage) {
  nMheighData= matrix(AFMImage@data$h, nrow=AFMImage@samplesperline)
  shiftedFFT2Ddata = shiftFFT2D(fftwtools::fftw2d(nMheighData))
  
  N=nrow(shiftedFFT2Ddata)
  M=ncol(shiftedFFT2Ddata)
  NM=N*M
  return((1/NM^2) * abs(shiftedFFT2Ddata)^2)
}

#' Calculate the 2D Power Spectral Density
#' 
#' PSD2DAgainstFrequency returns a data table of PSD 2D values against spatial frequencies
#'
#' @param AFMImage an \code{AFMImage} to be analysed
#' @param AFMImagePSDAnalysis an \code{AFMImagePSDAnalysis} to store PSD analysis results
#' @return \code{PSD2DAgainstFrequency} returns a data table of frequencies and PSD values
#' \itemize{
#'   \item freq: the considered frequency
#'   \item PSD: the considered PSD value
#'   \item type: PSD-2D
#'   \item fullfilename: directory and filename on the disk
#' }
#' @references  Sidick2009, Erkin Sidick "Power Spectral Density Specification and Analysis of Large Optical Surfaces", 2009, "Modeling Aspects in Optical Metrology II, Proc. of SPIE Vol. 7390 73900L-1"
#' @name PSD2DAgainstFrequency
#' @rdname PSD2DAgainstFrequency-methods
#' @exportMethod PSD2DAgainstFrequency
#' @examples
#' \dontrun{
#' library(AFM)
#' library(ggplot2)
#' library(plyr)
#' 
#' # Calculate Power Spectrum Density in 2D against frequency
#' data("AFMImageOfNormallyDistributedHeights")
#' oneAFMImage<-AFMImageOfNormallyDistributedHeights
#' psd2d<-PSD2DAgainstFrequency(oneAFMImage)
#' p <- ggplot(data=psd2d)
#' p <- p + geom_point(aes(freq, PSD, color=type),subset = .(type %in% c("PSD-2D")))
#' p <- p + geom_line(aes(freq, PSD, color=type),subset = .(type %in% c("PSD-1D")),size=1.1)
#' p <- p + scale_x_log10()
#' p <- p + scale_y_log10()
#' p <- p + ylab("PSD (nm^4)")
#' p <- p + xlab("Frequency (nm^-1)")
#' p <- p + ggtitle(basename(oneAFMImage@@fullfilename))
#' p
#' }
setGeneric(name= "PSD2DAgainstFrequency", 
           def= function(AFMImage, AFMImagePSDAnalysis) {
             return(standardGeneric("PSD2DAgainstFrequency"))
           })

#' @rdname PSD2DAgainstFrequency-methods
#' @aliases PSD2DAgainstFrequency,AFMImage-method
setMethod(f="PSD2DAgainstFrequency", signature(AFMImage="AFMImage",AFMImagePSDAnalysis="AFMImagePSDAnalysis"),
          definition= function(AFMImage, AFMImagePSDAnalysis) {
            NyquistFq<-getNyquistSpatialFrequency(AFMImage)
            
            a=AFMImage@hscansize
            b=AFMImage@vscansize
            
            M=AFMImage@samplesperline
            N=AFMImage@lines
            NM=N*M # pixels^2
            MN = M*N 
            A=a*b
            ab=a*b
            
            dx=a/M
            dy=b/N
            
            shiftedPSDuv<-shiftedPSDuv(AFMImage)
            
            um = seq( (1-(M+1)/2)/(M*dx), (M-(M+1)/2)/(M*dx), by=1/(M*dx))
            vn = seq( (1-(N+1)/2)/(N*dy), (N-(N+1)/2)/(N*dy), by=1/(N*dy))
            K=meshgrid(um,vn)
            K$Z<-sqrt(K$X^2+K$Y^2)
            
            aAggregatedPSDValuesForEachFreq=data.frame(freq=sort(unique(as.vector(K$Z))))
            totalLength <- length(aAggregatedPSDValuesForEachFreq$freq)
            frequencies<-c()
            sumedPSD<-c()
            counter<-0
            for(freq in aAggregatedPSDValuesForEachFreq$freq) {
              if (freq > NyquistFq) break;
              
              if (!is.null(AFMImagePSDAnalysis@updateProgress)&&
                  (is.function(AFMImagePSDAnalysis@updateProgress)&&
                   (!is.null(AFMImagePSDAnalysis@updateProgress())))) {
                counter<-counter+1
                if (counter/100==floor(counter/100)) {
                  value<-counter / totalLength
                  text <- paste0("freq:", round(freq, 2)," ", round(counter, 2),"/",totalLength)
                  AFMImagePSDAnalysis@updateProgress(value= value, detail = text)
                } 
              }
              
              inds <- arrayInd(which(K$Z == freq), dim(K$Z))
              allPSDSum<-0
              allPSDSum<-sum(shiftedPSDuv[inds[,1:2]])
              sumedPSD = c(sumedPSD, allPSDSum)
              frequencies=c(frequencies, freq)
            }
            return(data.table(freq = frequencies, PSD = sumedPSD, type="PSD-2D", name=AFMImage@fullfilename))
          }
)

#' Calculate the 1D Power Spectral Density; returns a data table of PSD 1D and PSD 2D values
#' against spatial frequencies.\cr As mentionned in Sidick2009, this function calculates the 
#' PSD against spatial frequencies in 1D from \code{\link{PSD2DAgainstFrequency}} by using
#' breaks in the log space to sum PSD 2D and frequency values.
#' 
#' @param AFMImage an \code{AFMImage} to be analysed
#' @param AFMImagePSDAnalysis n \code{AFMImagePSDAnalysis} to store the setup and results of PSD analysis
#' @return \code{PSD1DAgainstFrequency} returns a data table of frequencies and PSD values
#' \itemize{
#'   \item freq: the considered frequency
#'   \item PSD: the considered PSD value
#'   \item type: PSD-1D
#'   \item fullfilename: directory and filename on the disk
#' }
#' @name PSD1DAgainstFrequency
#' @rdname PSD1DAgainstFrequency-methods
#' @exportMethod PSD1DAgainstFrequency
#' @examples
#' \dontrun{
#' library(AFM)
#' library(ggplot2)
#' library(plyr)
#' library(scales)

#' data("AFMImageOfNormallyDistributedHeights")
#'  newAFMImage<-AFMImageOfNormallyDistributedHeights
#' newAFMImage@fullfilename<-"C:/Users/one/AFMImageOfNormallyDistributedHeights.txt"
#' psdAnalysis<-AFMImagePSDAnalysis()
#' # Create a closure to update progress
#' psdAnalysis@updateProgress<- function(value = NULL, detail = NULL, message = NULL) {
#'   if (exists("progressPSD")){
#'    if (!is.null(message)) {
#'      progressPSD$set(message = message, value = 0)
#'    }else{
#'      progressPSD$set(value = value, detail = detail)
#'    }
#'   }
#' }
#' psdAnalysis@psd1d_breaks<-2^3
#' psdAnalysis@psd2d_truncHighLengthScale<-TRUE
#' psdAnalysis<-performAllPSDCalculation(AFMImagePSDAnalysis= psdAnalysis, AFMImage= newAFMImage)
#' datap<-psdAnalysis@psd1d
#' p <- ggplot(data=datap)
#' p <- p + geom_point(aes(freq, PSD, color=type),data=datap[datap$type %in% c("PSD-2D")])
#' p <- p + geom_line(aes(freq, PSD, color=type),data=datap[datap$type %in% c("PSD-1D")],size=1.1)
#' p <- p + scale_x_log10()
#' p <- p + scale_y_log10()
#' p <- p + ylab("PSD (nm^4)")
#' p <- p + xlab("Frequency (nm^-1)")
#' p
#' }
setGeneric(name= "PSD1DAgainstFrequency", 
           def= function(AFMImage,AFMImagePSDAnalysis) {
             return(standardGeneric("PSD1DAgainstFrequency"))
           })

#' @rdname PSD1DAgainstFrequency-methods
#' @aliases PSD1DAgainstFrequency,AFMImage-method
setMethod(f="PSD1DAgainstFrequency", "AFMImage",
          definition= function(AFMImage, AFMImagePSDAnalysis) {
            AFMImagePSDAnalysis@psd2d<-PSD2DAgainstFrequency(AFMImage, AFMImagePSDAnalysis)
            
            breaks=AFMImagePSDAnalysis@psd1d_breaks
            psd2dDT=AFMImagePSDAnalysis@psd2d
            
            # step 3, cut in the log space
            Q <- breaks
            maxRhoL<- max(psd2dDT$freq)
            maxRhoL
            
            psd2dDT$logcuts<-cut(log10(psd2dDT$freq),breaks = Q)
            
            meanFreq<-c()
            meanPSD<-c()
            totalLength<-length(unique(as.vector(psd2dDT$logcuts)))
            counter<-0
            if (!is.null(AFMImagePSDAnalysis@updateProgress)&&
                (is.function(AFMImagePSDAnalysis@updateProgress)&&
                 (!is.null(AFMImagePSDAnalysis@updateProgress())))) {
              text <- paste0("starting ", totalLength, " calculations")
              AFMImagePSDAnalysis@updateProgress(value= 0, detail = text)
            } 
            
            
            for(freq in sort(unique(as.vector(psd2dDT$logcuts)))) {
              inds <- arrayInd(which(psd2dDT$logcuts == freq), dim(psd2dDT))
              allFreqSum<-0
              allPSDSum<-0
              allFreqSum<-mean(psd2dDT$freq[inds[,1]])
              allPSDSum<-mean(psd2dDT$PSD[inds[,1]])
              meanFreq = c(meanFreq, allFreqSum)
              meanPSD = c(meanPSD, allPSDSum)
              
              if (!is.null(AFMImagePSDAnalysis@updateProgress)&&
                  (is.function(AFMImagePSDAnalysis@updateProgress)&&
                   (!is.null(AFMImagePSDAnalysis@updateProgress())))) {
                counter<-counter+1
                if (counter/100==floor(counter/100)) {
                  value<- counter / totalLength
                  text <- paste0("freq:", round(freq, 2)," ", round(counter, 2),"/",totalLength)
                  AFMImagePSDAnalysis@updateProgress(value= value, detail = text)
                } 
              }
            }
            return(rbind(data.table(freq = meanFreq, PSD = meanPSD, type="PSD-1D", name=AFMImage@fullfilename), data.table(freq = psd2dDT$freq, PSD = psd2dDT$PSD, type="PSD-2D", name=psd2dDT$name)))
          })

#' Calculate the roughness of the sample against length scale
#'
#' The calculation of the roughness against lengthscale is performed throught a FFT 2D calculation, PSD 2D calculation and a meshgrid of frequencies.
#' \code{RoughnessByLengthScale} returns a data.table of roughnesses against length scales
#' 
#' @param AFMImage an \code{\link{AFMImage}} from Atomic Force Microscopy
#' @param AFMImagePSDAnalysis n \code{AFMImagePSDAnalysis} to store the setup and results of PSD analysis
#' 
#' @return a data table of lenght scale (r) and roughness values (roughness)
#' \itemize{ 
#' \item {roughness: roughnesses} 
#' \item {r: length scales}
#' \item {filename: fullfilename slot of the AFMImage} 
#' }
#' @name RoughnessByLengthScale
#' @rdname RoughnessByLengthScale-methods
#' @exportMethod RoughnessByLengthScale
#' @author M.Beauvais
#' @examples
#' \dontrun{
#' library(AFM)
#' library(ggplot2)
#' 
#' data("AFMImageOfNormallyDistributedHeights")
#' oneAFMImage<-AFMImageOfNormallyDistributedHeights
#' AFMImagePSDAnalysis<-AFMImagePSDAnalysis()
#' data<-RoughnessByLengthScale(oneAFMImage, AFMImagePSDAnalysis)
#' r<-roughness<-filename<-NULL
#' p1 <- ggplot(data, aes(x=r, y=roughness, colour= basename(filename)))
#' p1 <- p1 + geom_point()
#' p1 <- p1 + geom_line()
#' p1 <- p1 + ylab("roughness (nm)")
#' p1 <- p1 + xlab("lengthscale (nm)")
#' p1
#' }
setGeneric(name= "RoughnessByLengthScale", 
           def= function(AFMImage, AFMImagePSDAnalysis) {
             return(standardGeneric("RoughnessByLengthScale"))
           })

#' @rdname RoughnessByLengthScale-methods
#' @aliases RoughnessByLengthScale,AFMImage-method
setMethod(f="RoughnessByLengthScale", "AFMImage",
          definition= function(AFMImage, AFMImagePSDAnalysis) {
            # calculate roughness depending on frequency
            AFMImagePSDAnalysis@psd2d<-PSD2DAgainstFrequency(AFMImage, AFMImagePSDAnalysis)
            
            
            truncHighLengthScale = AFMImagePSDAnalysis@psd2d_truncHighLengthScale
            maxHighLengthScale = AFMImagePSDAnalysis@psd2d_maxHighLengthScale
            AggregatedPSDValuesForEachFreq = AFMImagePSDAnalysis@psd2d
            
            minFrequency<-1/min(AFMImage@hscansize, AFMImage@vscansize)
            indexfmin<-tail(which(AggregatedPSDValuesForEachFreq$freq < minFrequency), n=1)
            
            if (missing(truncHighLengthScale)||truncHighLengthScale==FALSE) {
              if(!missing(maxHighLengthScale)){
                truncHighLengthScale <- FALSE
                if (maxHighLengthScale<(1/minFrequency)) {
                  indexfmin<-which(AggregatedPSDValuesForEachFreq$freq > (1/maxHighLengthScale))[1]-1
                }
              }
            }
            
            nyquistSF <- getNyquistSpatialFrequency(AFMImage)
            indexfmax<-which(AggregatedPSDValuesForEachFreq$freq > nyquistSF)[1]-1
            
            #if (!isTRUE(truncHighLengthScale)||is.na(indexfmin)) indexfmin<-0
            if (is.na(indexfmin)) indexfmin<-0
            if (is.na(indexfmax)) indexfmax<-length(AggregatedPSDValuesForEachFreq$freq)
            
            r<-c()
            roughnesses=c()
            totalLength<-indexfmax
            counter<-0
            for (i in seq(1,indexfmax)){
              if (i>indexfmin) {
                tryingPSDSum<-sum(AggregatedPSDValuesForEachFreq$PSD[i:indexfmax])
                roughnesses=c(roughnesses, sqrt(tryingPSDSum))
                r=c(r, 1/AggregatedPSDValuesForEachFreq$freq[i])
                
                if (!is.null(AFMImagePSDAnalysis@updateProgress)&&
                    is.function(AFMImagePSDAnalysis@updateProgress)&&
                    !is.null(AFMImagePSDAnalysis@updateProgress())) {
                  counter<-counter+1
                  if (counter/100==floor(counter/100)) {
                    value<-counter / totalLength
                    text <- paste0(round(counter, 2),"/",totalLength)
                    AFMImagePSDAnalysis@updateProgress(value= value, detail = text)
                  } 
                }
              }
            }
            return(data.table(filename=rep(AFMImage@fullfilename, length(AggregatedPSDValuesForEachFreq$freq)-indexfmin), r= r, roughness= roughnesses))
          })


#' Get the Nyquist spatial frequency
#'
#' Get the Nyquist spatial frequency of an \code{\link{AFMImage}} calculated as following:\cr
#' 0.5 multiplied by the minimum between the horizontal scansize divided by the number of samples per line and the vertical scansize divided by the number of lines
#' 
#' \code{getNyquistSpatialFrequency} returns the Nyquist spatial frequency as a numeric
#' @param AFMImage an \code{\link{AFMImage}} from Atomic Force Microscopy
#' @return the Nyquist spatial frequency of the \code{\link{AFMImage}}
#' @name getNyquistSpatialFrequency
#' @rdname getNyquistSpatialFrequency-methods
#' @exportMethod getNyquistSpatialFrequency
#' @author M.Beauvais
#' @examples
#' \dontrun{
#' library(AFM)
#' 
#' data(AFMImageOfNormallyDistributedHeights)
#' NyquistSpatialFrequency<-getNyquistSpatialFrequency(AFMImageOfNormallyDistributedHeights)
#' print(NyquistSpatialFrequency)
#' }
#' 
setGeneric(name= "getNyquistSpatialFrequency", 
           def= function(AFMImage) {
             return(standardGeneric("getNyquistSpatialFrequency"))
           })

#' @rdname getNyquistSpatialFrequency-methods
#' @aliases getNyquistSpatialFrequency,AFMImage-method
setMethod(f="getNyquistSpatialFrequency", "AFMImage",
          definition= function(AFMImage) {
            M=AFMImage@samplesperline
            N=AFMImage@lines
            a=AFMImage@hscansize
            b=AFMImage@vscansize
            dx=a/M
            dy=b/N
            
            #old   return(min(abs((1-(M+1)/2)/(M*dx)), abs((1-(N+1)/2)/(N*dy))))
            return(min(1/(2*dx),1/(2*dy)))
          })

#' Get a zero padded AFMImage
#' 
#' Get a zero padded \code{\link{AFMImage}} useful in Power Spectral Density analysis. The original \code{\link{AFMImage}} is padded with zero in order to get a larger square AFMImage which size is a power of 2.
#'
#' @param AFMImage an \code{\link{AFMImage}} from Atomic Force Microscopy
#' @return a zero-padded \code{\link{AFMImage}} with a fullfilename equals to the original fullfilename pasted with padded-to-"ScanSize".txt
#' @author M.Beauvais
#' @export
#' @examples
#' \dontrun{
#' library(AFM)
#' 
#' data(AFMImageOfNormallyDistributedHeights)
#' paddedAFMImage<-getPaddedAFMImage(AFMImageOfNormallyDistributedHeights)
#' displayIn3D(AFMImage= paddedAFMImage, width= 1024,noLight=TRUE)
#' }
getPaddedAFMImage<-function(AFMImage) {
  paddedAFMImageMatrix<-matrix(AFMImage@data$h, nrow=AFMImage@samplesperline, ncol=AFMImage@lines,byrow = TRUE)
  N=nrow(paddedAFMImageMatrix)
  print(N)
  M=ncol(paddedAFMImageMatrix)
  print(M)
  
  rn = 2^(ceil(log2(N)))
  paddedN <- ifelse(rn==N, 2^(ceil(log2(N+1))), rn)
  rm = 2^(ceil(log2(M)))
  paddedM <- ifelse(rm==M, 2^(ceil(log2(M+1))), rm)
  
  
  addingN=paddedN/4
  addingM=paddedM/4
  
  A<-matrix( rep(0,addingM*N), nrow=N,ncol=addingM,byrow = TRUE)
  B<-matrix( rep(0,addingM*paddedN), nrow=addingM,ncol=paddedN,byrow = TRUE)
  paddedAFMImageMatrix<-cbind(A, paddedAFMImageMatrix, A)
  paddedAFMImageMatrix<-rbind(B, paddedAFMImageMatrix, B)
  
  Lines<-paddedN;
  Samplesperline<-paddedM;
  ScanSize<-AFMImage@hscansize*paddedM/M
  # not tested
  hscanSize<-AFMImage@hscansize*paddedM/M
  vscanSize<-AFMImage@vscansize*paddedN/N
  ScanSize<-max(hscanSize, vscanSize)
  
  
  scanSizeFromZero<-ScanSize-1
  scanby<-ScanSize/Samplesperline
  endScan<-ScanSize*(1-1/Samplesperline)
  nM<-as.vector(t(paddedAFMImageMatrix))
  
  AFMImage(data = data.table(x = rep(seq(0,endScan, by= scanby), times = Lines),
                             y = rep(seq(0,endScan, by= scanby), each = Samplesperline), 
                             h = nM), 
           samplesperline = Samplesperline, 
           lines = Lines,
           hscansize = hscanSize,
           vscansize = vscanSize,
           scansize = ScanSize, 
           fullfilename = paste(AFMImage@fullfilename, "padded-to-",ScanSize,".txt",sep=""))
}

#' Perform all the calculation for PSD exploitation
#' 
#' \code{\link{performAllPSDCalculation}} perform all the calculation for PSD exploitation
#' @param AFMImagePSDAnalysis an \code{\link{AFMImagePSDAnalysis}} to manage and store the results of PSD analysis
#' @param AFMImage an \code{\link{AFMImage}} from Atomic Force Microscopy
#' @author M.Beauvais
#' @export
#' @examples
#' \dontrun{
#' library(AFM)
#' 
#' data(AFMImageOfNormallyDistributedHeights)
#' 
#' newAFMImage<-AFMImageOfNormallyDistributedHeights
#' newAFMImage@fullfilename<-"C:/Users/one/AFMImageOfNormallyDistributedHeights.txt"
#' psdAnalysis<-AFMImagePSDAnalysis()
#' # Create a closure to update progress
#' psdAnalysis@updateProgress<- function(value = NULL, detail = NULL, message = NULL) {
#'   if (exists("progressPSD")){
#'     if (!is.null(message)) {
#'       progressPSD$set(message = message, value = 0)
#'     }else{
#'       progressPSD$set(value = value, detail = detail)
#'     }
#'   }
#' }
#' psdAnalysis@psd1d_breaks<-2^3
#' psdAnalysis@psd2d_truncHighLengthScale<-TRUE
#' psdAnalysis<-performAllPSDCalculation(AFMImagePSDAnalysis= psdAnalysis, AFMImage= newAFMImage)
#' print("done psdAnalysis")
#' }
performAllPSDCalculation<-function(AFMImagePSDAnalysis, AFMImage) {
  if (is.function(AFMImagePSDAnalysis@updateProgress)) {
    AFMImagePSDAnalysis@updateProgress(message="1/3 - Calculating PSD2D", value=0)
  }
  AFMImagePSDAnalysis@psd2d<-PSD2DAgainstFrequency(AFMImage, AFMImagePSDAnalysis)
  
  if (is.function(AFMImagePSDAnalysis@updateProgress)) {
    AFMImagePSDAnalysis@updateProgress(message="2/3 Calculating PSD1D", value=0)
  }
  AFMImagePSDAnalysis@psd1d<-PSD1DAgainstFrequency(AFMImage, AFMImagePSDAnalysis)
  
  if (is.function(AFMImagePSDAnalysis@updateProgress)) {
    AFMImagePSDAnalysis@updateProgress(message="3/3 Calculating Roughness", value=0)
  }
  AFMImagePSDAnalysis@roughnessAgainstLengthscale<-RoughnessByLengthScale(AFMImage, AFMImagePSDAnalysis)
  
  return(AFMImagePSDAnalysis)
}

#' save an image of the roughness against lenghtscale calculations
#' 
#' \code{\link{saveOnDiskIntersectionForRoughnessAgainstLengthscale}} save an image of the roughness against lenghtscale calculations
#' @param AFMImageAnalyser an \code{\link{AFMImageAnalyser}} to get Roughness against lenghtscale calculation
#' @param exportDirectory a directory on the file system
#' @author M.Beauvais
#' @export
saveOnDiskIntersectionForRoughnessAgainstLengthscale<-function(AFMImageAnalyser, exportDirectory){
  sampleName<-basename(AFMImageAnalyser@fullfilename)
  
  data<-getSimplifiedRoughnessAgainstLenghscale(AFMImageAnalyser)
  data$r<-as.numeric(data$r)
  
  aval<-max(data$r)
  index<-which(data$r<= aval)[1]
  print(index)
  lengthData<-length(data$r)-index
  ndataw<-tail(data,n= lengthData)
  ndataw$sample<-basename(ndataw$filename)
  
  #find x1 x2 that minimizes Xinter
  min=nrow(data)
  max=2
  
  point<- data[data$r %in% min(data$r)]
  otherpoints<-as.numeric(point$V1)-min
  point1<-data[as.numeric(data$V1) %in% (otherpoints)]
  otherpoints<-as.numeric(point$V1)-max
  point2<-data[as.numeric(data$V1) %in% (otherpoints)]
  
  point1<-data[min]
  point2<-data[max]
  
  
  origintangeantePoints = data.table(x=c(point1$r, point2$r), y=c(point1$roughness, point2$roughness))
  aorigin<-0
  borigin <- point1$roughness - aorigin * point2$r
  
  x1x2=AFMImageAnalyser@psdAnalysis@intersections[c(2,3,5,6)]
  print(x1x2)
  
  for(i in c(0,2)) {
    x1<-x1x2[i+1]
    x2<-x1x2[i+2]
    print(x1)
    point1<-data[x1]
    point2<-data[x2]
    x=data[seq(x2,x1)]$r
    y=data[seq(x2,x1)]$roughness
    res <- lm(y~x)
    coefficients(res)
    b<-unname(res$coefficients[1])
    a<-unname(res$coefficients[2])
    
    tangeantePoints = data.table(x=c(point1$r, point2$r), y=c(point1$roughness, point2$roughness))
    
    xinter <- (b-borigin)/(aorigin-a)
    title<-paste(" -Lc= ", xinter," -plateau= ", borigin)
    
    roughness<-r<-NULL
    p1 <- ggplot(ndataw, aes(x=r, y=roughness, colour= basename(sample)))
    p1 <- p1 + geom_point()
    p1 <- p1 + geom_line()
    p1 <- p1 + geom_abline(intercept = b, slope = a)
    p1 <- p1 +geom_point(data=tangeantePoints, aes(x=x, y=y), color="blue") 
    p1 <- p1 + geom_abline(intercept = borigin, slope = aorigin)
    p1 <- p1 +geom_point(data=origintangeantePoints, aes(x=x, y=y), color="blue") 
    p1 <- p1 + ylab("roughness (nm)")
    p1 <- p1 + xlab("lengthscale (nm)")
    p1 <- p1 + guides(colour=FALSE)
    p1 <- p1 + ggtitle(title)
    exportpng2FullFilename=getRoughnessAgainstLengthscaleIntersection(exportDirectory, paste( sampleName, i, sep="-"))
    print(paste("saving", basename(exportpng2FullFilename)))
    png(filename=exportpng2FullFilename, units = "px", width=800, height=800)
    print(p1)
    dev.off()
  }
}

#' get the intersection between tangente and plateau
#' 
#' \code{\link{getAutoIntersectionForRoughnessAgainstLengthscale}} get the intersection between tangente and plateau
#' @param AFMImageAnalyser an \code{\link{AFMImageAnalyser}} to get Roughness against lenghtscale calculation
#' @param second_slope a boolean to manage first or second slope in the roughness against lenghtscale curve
#' @return a \code{\link{AFMImagePSDSlopesAnalysis}}
#' @author M.Beauvais
#' @export
getAutoIntersectionForRoughnessAgainstLengthscale<-function(AFMImageAnalyser, second_slope=FALSE){
  # sampleName<-basename(AFMImageAnalyser@AFMImage@fullfilename)
  # exportDirectory<-paste(dirname(AFMImageAnalyser@AFMImage@fullfilename), "outputs", sep="/")
  
  data<-getSimplifiedRoughnessAgainstLenghscale(AFMImageAnalyser)
  data$r<-as.numeric(data$r)
  
  aval<-max(data$r)
  index<-which(data$r<= aval)[1]
  
  lengthData<-length(data$r)-index
  print(paste("lengthData=",lengthData))
  #lengthData
  # ndataw<-tail(data,n= lengthData)
  # ndataw$sample<-basename(ndataw$filename)
  # print(paste("length(ndataw)=",length(ndataw)))
  
  lengthData<-nrow(data)
  #newMax=ceiling(data[c(lengthData),]$r/20)
  minW<-which.min(abs(data$r - data[c(lengthData),]$r/20)) 
  newMax=minW
  print(paste("first slope - newMax= ",newMax))
  
  #newMax_second_slope=ceiling(data[c(lengthData),]$r/10)
  #newMax_second_slope=ceiling(data[c(lengthData),]$r/10)
  minW<-which.min(abs(data$r - data[c(lengthData),]$r/10)) 
  minW
  data[minW]
  newMax_second_slope=minW
  print(paste("second slope newMax_second_slope= ",newMax_second_slope))
  
  
  minimumR <- function(data, space, x, y, second_slope) {
    lengthData<-nrow(data)
    
    aorigin<-0
    borigin <- data[lengthData]$roughness
    #print(borigin)
    
    finalres2=c()
    if (!second_slope) finalres = c(Inf,0,0,0,0,0)
    else finalres = c(Inf,0,0,0,0,0)
    
    for (i in seq(1, length(x))) {
      x1=x[i]
      for (j in seq(1, length(y))) {
        if (abs(j-i)>space) {
          x2=y[j]
          
          if ((x1<1)||(x2<1)||(x1>lengthData)||(x2>lengthData)||(x1==x2)) {
            inter <- data[1]$r
          } else{
            if (x1<x2) {
              myx=data[seq(x1,x2)]$r
              myy=data[seq(x1,x2)]$roughness
            }
            if (x1>x2) {
              myx=data[seq(x2,x1)]$r
              myy=data[seq(x2,x1)]$roughness
            }    
            slope=(myy[2]-myy[1])/(myx[2]-myx[1])
            yintersept = myy[1] - slope * myx[1]
            
            res <- lm(myy~myx)
            b<-unname(res$coefficients[1])
            a<-unname(res$coefficients[2])
            inter <- (borigin-b)/a
            slope <- a
            yintersept <- b
            if ((!second_slope&(inter<finalres[1])&(inter>0))|
                (second_slope&(inter<finalres[1])&(inter>0))){
              finalres=c(inter, x1, x2, borigin, slope, yintersept)
              print(finalres)
              # print(paste(a,b))
              # print(paste(myx[1],myx[2],myy[1],myy[2]))
            }
          }
        }
        #print(paste(x1, x2))
      }
      #finalres2=c(finalres2, inter)
    }
    AFMImagePSDSlopesAnalysis = new("AFMImagePSDSlopesAnalysis")
    AFMImagePSDSlopesAnalysis@lc=finalres[1]
    AFMImagePSDSlopesAnalysis@tangente_point1=finalres[2]
    AFMImagePSDSlopesAnalysis@tangente_point2=finalres[3]
    AFMImagePSDSlopesAnalysis@wsat=finalres[4]
    AFMImagePSDSlopesAnalysis@slope=finalres[5]
    AFMImagePSDSlopesAnalysis@yintersept=finalres[6]
    #print(AFMImagePSDSlopesAnalysis)
    return(AFMImagePSDSlopesAnalysis)
  }
  
  
  
  if (second_slope==FALSE) {
    aby<-1
    print(aby)
    x <- seq(1, newMax,by=aby)
    print(x)
    z <- minimumR(data, space= 1, x,x,second_slope)
  } else {
    aby<-1
    print(aby)
    space=ceiling(lengthData/4)
    space=ceiling(lengthData/8)
    space=ceiling(lengthData/10)
    space=30
    print(paste("space= ",space))
    x <- seq(newMax_second_slope,lengthData, by=aby)
    z <- minimumR(data, space= space, x,x,second_slope)
  }
  return(z)
}


#' get the intersection between tangente and plateau
#' 
#' \code{\link{getIntersectionForRoughnessAgainstLengthscale}} get the intersection between tangente and plateau
#' @param AFMImageAnalyser an \code{\link{AFMImageAnalyser}} to get Roughness against lenghtscale calculation
#' @param minValue index of the lowest point to be used for the tangent
#' @param maxValue index of the highest point to be used for the tangent
#' @param second_slope a boolean to manage first or second slope in the roughness against lenghtscale curve
#' @return a \code{\link{AFMImagePSDSlopesAnalysis}}
#' @author M.Beauvais
#' @export
getIntersectionForRoughnessAgainstLengthscale<-function(AFMImageAnalyser, minValue, maxValue, second_slope=FALSE){
  # sampleName<-basename(AFMImageAnalyser@AFMImage@fullfilename)
  # exportDirectory<-paste(dirname(AFMImageAnalyser@AFMImage@fullfilename), "outputs", sep="/")
  
  data<-getSimplifiedRoughnessAgainstLenghscale(AFMImageAnalyser)
  data$r<-as.numeric(data$r)
  
  aval<-max(data$r)
  index<-which(data$r<= aval)[1]
  
  lengthData<-length(data$r)-index
  print(paste("lengthData=",lengthData))
  
  lengthData<-nrow(data)
  
  
  minimumR <- function(data, x1, x2) {
    lengthData<-nrow(data)
    
    aorigin<-0
    borigin <- data[lengthData]$roughness
    #print(borigin)
    
    finalres2=c()
    
    
    if ((x1<1)||(x2<1)||(x1>lengthData)||(x2>lengthData)||(x1==x2)) {
      inter <- data[1]$r
    } else{
      if (x1<x2) {
        myx=data[seq(x1,x2)]$r
        myy=data[seq(x1,x2)]$roughness
      }
      if (x1>x2) {
        myx=data[seq(x2,x1)]$r
        myy=data[seq(x2,x1)]$roughness
      }    
      slope=(myy[2]-myy[1])/(myx[2]-myx[1])
      yintersept = myy[1] - slope * myx[1]
      
      res <- lm(myy~myx)
      b<-unname(res$coefficients[1])
      a<-unname(res$coefficients[2])
      inter <- (borigin-b)/a
      slope <- a
      yintersept <- b
      finalres=c(inter, x1, x2, borigin, slope, yintersept)
      print(finalres)
      # print(paste(a,b))
      # print(paste(myx[1],myx[2],myy[1],myy[2]))
    }
    
    AFMImagePSDSlopesAnalysis = new("AFMImagePSDSlopesAnalysis")
    AFMImagePSDSlopesAnalysis@lc=finalres[1]
    AFMImagePSDSlopesAnalysis@tangente_point1=finalres[2]
    AFMImagePSDSlopesAnalysis@tangente_point2=finalres[3]
    AFMImagePSDSlopesAnalysis@wsat=finalres[4]
    AFMImagePSDSlopesAnalysis@slope=finalres[5]
    AFMImagePSDSlopesAnalysis@yintersept=finalres[6]
    #print(AFMImagePSDSlopesAnalysis)
    return(AFMImagePSDSlopesAnalysis)
  }
  
  
  AFMImagePSDSlopesAnalysis <- minimumR(data, minValue,maxValue)
  return(AFMImagePSDSlopesAnalysis)
}


getRoughnessAgainstLengthscale<-function(exportDirectory, sampleName) {
  exportCsvFilename<-paste(sampleName,"-roughness-against-lengthscale.png", sep="")
  exportCsvFullFilename<-paste(exportDirectory, exportCsvFilename, sep="/")
  return(exportCsvFullFilename)
}

getRoughnessAgainstLengthscale10nm<-function(exportDirectory, sampleName) {
  exportCsvFilename<-paste(sampleName,"-roughness-against-lengthscale-10nm.png", sep="")
  exportCsvFullFilename<-paste(exportDirectory, exportCsvFilename, sep="/")
  return(exportCsvFullFilename)
}

getRoughnessAgainstLengthscaleIntersection<-function(exportDirectory, sampleName) {
  exportpngFilename<-paste(sampleName,"-roughness-against-lengthscale-intersection.png", sep="")
  exportpngFullFilename<-paste(exportDirectory, exportpngFilename, sep="/")
  return(exportpngFullFilename)
}


getSimplifiedRoughnessAgainstLenghscale<-function(AFMImageAnalyser) {
  ral<-copy(AFMImageAnalyser@psdAnalysis@roughnessAgainstLengthscale)
  ral<-ral[order(r)]
  ral$simplyfied_r<-round(ral$r)
  
  ral<-ral[!duplicated(ral$simplyfied_r),]
  
  roughness<-r<-NULL
  resPSD = data.table(
    filename=ral$filename,
    r = ral$r,
    roughness=ral$roughness
  )
  return(resPSD)
}

Try the AFM package in your browser

Any scripts or data that you put into this service are public.

AFM documentation built on Oct. 23, 2020, 5:23 p.m.