function gnorm!(c::AbstractVector, γ)
    T = eltype(c)
    if γ == zero(T)
        c[1] = exp(c[1])
        return c
    end

    gain = one(T) + γ*c[1]
    for i=2:length(c)
        @inbounds c[i] /= gain
    end
    c[1] = gain^(one(T)/γ)

    c
end

gnorm(c::AbstractVector, γ=0.0) = gnorm!(copy(c), γ)

function gnorm!{T<:GeneralizedLogCepstrum}(state::SpectralParamState{T})
    assert_not_ready_to_filt(state)
    assert_gain_unnormalized(state)

    γ = glog_gamma(paramdef(state))
    state.data = gnorm!(rawdata(state), γ)
    state.gain_normalized = true
    state
end

function gnorm!{T<:Union{AllPoleLogCepstrum,StandardLogCepstrum}}(state::SpectralParamState{T})
    assert_not_ready_to_filt(state)
    assert_gain_unnormalized(state)
    state
end

function gnorm{T<:MelGeneralizedCepstrum}(state::SpectralParamState{T})
    gnorm!(copy(state))
end


# module model_fit

using DifferentialEquations, Flux, Optim, DiffEqFlux, DiffEqSensitivity, Plots
using BlackBoxOptim
using BenchmarkTools
using RecursiveArrayTools # for VectorOfArray
# -------------------------------------------------------------------------

function generate_data(sol)
  t = collect(range(0,stop=10,length=101))

  solution = sum(sol(t),dims=1)
  # randomized = VectorOfArray([(sol(t[i]) + .02randn(size(sol,1))) for i in 1:length(t)])
  # dataset = convert(Array,randomized)
  randomized = solution .+ .01randn(size(solution))
  dataset = randomized
  display(scatter!(t,dataset'))
  return dataset
end

function generate_data(sol,t)

  solution = sum(sol(t),dims=1)
  # randomized = VectorOfArray([(sol(t[i]) + .02randn(size(sol,1))) for i in 1:length(t)])
  # dataset = convert(Array,randomized)
  randomized = solution .+ .01randn(size(solution))
  dataset = randomized
  display(scatter!(t,dataset'))
  return dataset
end

function run_model_2(model,p,data,densities,constants,t) # version of run function with multiple models
    f = (du,u,p,t) -> model(du,u,10 .^ p,t,densities,constants)
    tmp_prob = ODEProblem(f,u₀,tspan,p)
    # tmp_sol = solve(tmp_prob,AutoVern7(KenCarp4()),saveat=t, abstol=1e-8,reltol=1e-8)
    tmp_sol = solve(tmp_prob,Vern7(),saveat=t, abstol=1e-5,reltol=1e-5)
    # stack Σ of solution across n species
    tmp_sol
end

function loss_2(p,data,model,dens,cons,t,unique_t)
    # for i in 1:siz
    tmp_sol = run_model_2(model,p,data,dens,cons,unique_t)

    # @show Σ_sol
    # @show solution
    # if any((s.retcode != :Success for s in solution))
    # @show typeof(solution.retcode)
    if tmp_sol.retcode != :Success
      # @show solution
      L = Inf
    else
      Σ_sol = sum(Array(tmp_sol),dims=1)
      Δy = 0.
      for (i, tᵢ) in enumerate(t)
          ind = unique_t .== tᵢ
          yᵢ_exp = Σ_sol[ind][1]
          yᵢ_obs = data[i]
          Δyᵢ = yᵢ_obs .- yᵢ_exp
          # setindex!(Δy, Δyᵢ, i)
          # Δy[i] = Δyᵢ
          Δy = vcat(Δy,Δyᵢ)
          # @show Δy
          # @show tᵢ, yᵢ_obs, Δyᵢ
      end
      L = sum(abs2, Δy[2:end]) #, Σ_sol
    end
    return L
end

# function callback(p,l,tmp_sol,data,model,dens,cons,t)
function callback(p,l,data,model,dens,cons,t,unique_t)
  @show l, p

  # Σ_sol = run_model_2(model,p,data,dens,cons,unique_t)

  # fig = plot(unique_t,Σ_sol')
  # scatter!(fig,t,data,legend=:bottomright)
  # display(fig)

  false
end

function scan_param_space(p,data,model,dens,cons,t,unique_t,lb,ub)
      #create rand mesh
      n = 10000
      ps = rand(n,size(p,1)) .* 10 .- 8
      errors = zeros(n)
      for i in 1:n
          # error, a = loss(ps[i,:],data,model,dens,cons,t)
          error = loss_2(ps[i,:],data,model,dens,cons,t,unique_t)
          errors[i] = error
          # @show error
      end
      min_ind = argmin(errors)
      min_error = minimum(errors)
      @show findmin(errors)
      p_best = ps[min_ind,:]
      @show p_best
      if size(p,1) == 2
          fig = scatter(ps[:,1],ps[:,2],log10.(errors),
          zcolor = log10.(errors),camera=[0,90])
          scatter!([p_best[1]],[p_best[2]],[log10(min_error)],markercolor=:green,markersize=5)
          display(fig)
      end
      return p_best
end

function optimization(model,data,dens,cons,options,t)
# fit function - given model, data, densities, options get best parameters
  unique_t = unique(t)
  loss_in = (p) -> loss_2(p,data,model,dens,cons,t,unique_t)
  # callback_in = (p,l,tmp_sol) -> callback(p,l,tmp_sol,data,model,dens,cons,t)
  callback_in = (p,l) -> callback(p,l,data,model,dens,cons,t,unique_t)

  # @unpack lb,ub = options
  lb,ub = options

  start = scan_param_space(pinit,data,model,dens,cons,t,unique_t,lb,ub) # !! change behavior so that it doesnt need pinit

  res = DiffEqFlux.sciml_train(loss_in,start,BFGS(),cb=callback_in)

  rates = res.minimizer
  l = res.minimum

  # bootstrap_rates = bootstrapping(rates,data,model,dens,cons,t)
  bootstrap_rates = []

  f = (du,u,p,t) -> model(du,u,p,t,dens,cons) # optimize in log space
  prob = ODEProblem(f,u₀,tspan,10 .^ rates)
  sol = solve(prob,Vern7())
  h = plot!(sol)
  display(h)
  @show model, rates, start

  hes_for = ForwardDiff.hessian(loss_in,rates)
  hes_zyg = Zygote.hessian(loss_in,rates)
  @show hes_for ≈ hes_zyg

  return rates, hes_zyg, l, bootstrap_rates
end

function bootstrapping(rates,data,model,dens,cons,t)
  #create sample
  data = n
  B_size = 10
  # rand_mat = rand(1:length(data),(length(data),B_size))

  rand_mat = [rand(1:length(data),length(data)) for i in 1:B_size]

  bootstrap_rates = zeros(size(rates))
  # bootstrap_rates = []
  for i in 1:B_size
    resampled_data = data[rand_mat[i]]
    resampled_t = t[rand_mat[i]]
    sort_ind = sortperm(resampled_t)
    resampled_data = resampled_data[sort_ind]
    resampled_t = resampled_t[sort_ind]
    unique_t = unique(resampled_t)

    # loss_in = (p) -> loss_2(p,resampled_data,model,dens,cons,resampled_t,unique_t)
    # callback_in = (p,l) -> callback(p,l,resampled_data,model,dens,cons,resampled_t,unique_t)
    loss_in = (p) -> loss_2(p,data,model,dens,cons,t,unique(t))
    callback_in = (p,l) -> callback(p,l,data,model,dens,cons,t,unique(t))

    # @show loss_in(rates)
    res = optimize(loss_in,-9, 2, rates,Fminbox(NelderMead()))
    # @time res = DiffEqFlux.sciml_train(loss_in,rates,BFGS(),
    #                                 lower_bounds = -9,
    #                                 upper_bounds = 2,
    #                                 cb = callback_in,
    #                                 maxiters=50,
    #                                 f_tol = 1e-4)

    # @show res.minimizer
    bootstrap_rates= hcat(bootstrap_rates,res.minimizer)
    # push!(bootstrap_rates,res.minimizer)
    # Σ_sol = run_model_2(model,p,resampled_data,dens,cons,unique_t)
  end

  return bootstrap_rates[:,2:end]
end


using FractionalDiffEq
using Plots

function chua(t, x, k)
    a=10.725
    b=10.593
    c=0.268
    m0=-1.1726
    m1=-0.7872

    if k == 1
        f = m1*x[1]+0.5*(m0-m1)*(abs(x[1]+1)-abs(x[1]-1))
        y = a*(x[2]-x[1]-f)
        return y
    elseif k == 2
        y = x[1]-x[2]+x[3]
        return y
    elseif k == 3
        y = -b*x[2]-c*x[3]
        return y
    end
end

α = [0.93, 0.99, 0.92];
x0 = [0.2; -0.1; 0.1];
h = 0.001;
prob = FODESystem(chua, α, x0)
tn = 500;
result = solve(prob, h, tn, NonLinearAlg(), 10000)

gr()
plot(result[:, 1], result[:, 2], title="Chua System with Short Memory Effect", legend=:bottomright)


using DiffEqUncertainty, DiffEqBase, OrdinaryDiffEq, DiffEqProblemLibrary
using Test

function g(du,u,p,t)
  σ,ρ,β = p
  x,y,z = u
  du[1] = σ*(y-x)
  du[2] = x*(ρ-z) - y
  du[3] = x*y - β*z
end
u0 = [1.0;0.0;0.0]
tspan = (0.0,10.0)
p = [10.0,28.0,8/3]
prob = ODEProblem(g,u0,tspan,p)

cb = ProbIntsUncertainty(1e4,5)
solve(prob,Tsit5())
monte_prob = EnsembleProblem(prob)
sim = solve(monte_prob,Tsit5(),trajectories=10,callback=cb,adaptive=false,dt=1/10)

#using Plots; plotly(); plot(sim,vars=(0,1),linealpha=0.4)

function fitz(du,u,p,t)
  V,R = u
  du[1] = 3.0*(V - V^3/3 + R)
  du[2] = -(1/3.0)*(V -  0.2 - 0.2*R)
end
u0 = [-1.0;1.0]
tspan = (0.0,20.0)
prob = ODEProblem(fitz,u0,tspan)

cb = ProbIntsUncertainty(0.1,1)
sol = solve(prob,Euler(),dt=1/10)
monte_prob = EnsembleProblem(prob)
sim = solve(monte_prob,Euler(),trajectories=100,callback=cb,adaptive=false,dt=1/10)

#using Plots; plotly(); plot(sim,vars=(0,1),linealpha=0.4)

cb = AdaptiveProbIntsUncertainty(5)
sol = solve(prob,Tsit5())
monte_prob = EnsembleProblem(prob)
sim = solve(monte_prob,Tsit5(),trajectories=100,callback=cb,abstol=1e-3,reltol=1e-1)

#using Plots; plotly(); plot(sim,vars=(0,1),linealpha=0.4)


# calculate the least squares line of the errors

dirs = Array(1:3)  # do directories 1 through 3.  This range does not have
                   # to start at 1, but it must be contiguous
npts = length(dirs)
err_vals = zeros(maximum(dirs))
h_vals = zeros(maximum(dirs))
for i in dirs
  println("i = ", i)
  fname = "m$i/error_calc.dat"  # this file is written by the solver
  val_i = readdlm(fname)
  err_vals[i] = val_i[1]  # get error value
  h_vals[i] = val_i[2]  # get nominal mesh spacing h

end

min_idx = minimum(dirs)
max_idx = maximum(dirs)
err_vals = err_vals[min_idx:max_idx]
h_vals = h_vals[min_idx:max_idx]
npts = max_idx - min_idx + 1

# print the raw data
println("h  |   error")
println(hcat(h_vals, err_vals))

# tag the log of the data points
err_vals_log = zeros(npts)
h_vals_log = zeros(npts)
for i=1:npts
  err_vals_log[i] = log(err_vals[i])
  h_vals_log[i] = log(h_vals[i])
end

# now form system
A = ones(npts, 2)
A[:, 2] = h_vals_log

# solve system
AAt = A.'*A
rhs = A.'*err_vals_log

x = AAt\rhs

# compute error of each point compared to best fit line
for i=1:npts
  h_i = h_vals_log[i]
  err_exp = x[1] + h_i*x[2]
  err_act = err_vals_log[i]
  err_pct = 100*(err_exp - err_act)/err_act
  println("point $i percent error of best fit line = ", err_pct, "%")
end

# calculate slope from last two points
slope2 = (err_vals_log[npts - 1] - err_vals_log[npts])/(h_vals_log[npts - 1] - h_vals_log[npts])

println("2 point slope: ", slope2)
println("least squares slope: ", x[2])

# write data to file for plotting
data_arr = hcat(h_vals, err_vals)
writedlm("err_data.dat", data_arr, ' ')


using BenchmarkTools, Schrodinger
n = 10
A = Operator(rand(n,n),(n,));
B = Operator(rand(n,n),(n,));
A*B;
A.data*B.data;
@time for i=1:300000;A*B;end
@time for i=1:300000;A.data*B.data;end

function test_Operator()
    for n in [10,16,30]
        A = Operator(rand(n,n),(n,))
        B = Operator(rand(n,n),(n,))
        @show @benchmark $A*$B
        @show @benchmark $A.data*$B.data
    end
end

test_Operator()

@benchmark begin
N = 10
omega_a = 1.0
omega_c = 1.0
g = 0.05
a = tensor(sigma0, destroy(N))
sm = tensor(sigmaplus, qeye(N))
sz = tensor(sigmaz, qeye(N))
smdsm = (sm'*sm)
H = 0.5 * omega_a * sz + omega_c * a' * a + g * (a' * sm + a * sm')
psi0 = tensor(basis(2,1),basis(N,0))
end

#python -m timeit -s "import qutip as qt" "N = 10; omega_a = 1.0; omega_c = 1.25; g = 0.05; a = qt.tensor(qt.identity(2), qt.destroy(N)); sm = qt.tensor(qt.destroy(2), qt.identity(N)); sz = qt.tensor(qt.sigmaz(), qt.identity(N)); H = 0.5 * omega_a * sz + omega_c* a.dag() * a + g *(a.dag() * sm + a * sm.dag())"


module TestChaining

using Test, Random
using DataFrames
using DataFramesMeta
using Lazy, Chain
using Statistics
using Random

Random.seed!(1)
n = 100
df = DataFrame(a = rand(1:3, n),
               b = ["a","b","c","d"][rand(1:4, n)],
               x = rand(n))

x = @where(df, :a .> 2)
x = @transform(x, y = 10 * :x)
x = @by(x, :b, meanX = mean(:x), meanY = mean(:y))
x = @orderby(x, :b, -:meanX)
x = @select(x, var = :b, :meanX, :meanY)

x_as = @as _x_ begin
    df
    @where(_x_, :a .> 2)
    @transform(_x_, y = 10 * :x)
    @by(_x_, :b, meanX = mean(:x), meanY = mean(:y))
    @orderby(_x_, :b, -:meanX)
    @select(_x_, var = :b, :meanX, :meanY)
end

x_thread = @> begin
   df
   @where(:a .> 2)
   @transform(y = 10 * :x)
   @by(:b, meanX = mean(:x), meanY = mean(:y))
   @orderby(:b, -:meanX)
   @select(var = :b, :meanX, :meanY)
end

x_chain = @chain df begin
   @where(:a .> 2)
   @transform(y = 10 * :x)
   @by(:b, meanX = mean(:x), meanY = mean(:y))
   @orderby(:b, -:meanX)
   @select(var = :b, :meanX, :meanY)
end

@test x == x_as
@test x == x_thread

end # module


using BHAPtfem
using Test

#=
Compare formulas at:
http://www.awc.org/pdf/codes-standards/publications/design-aids/AWC-DA6-BeamFormulas-0710.pdf
=#

println("Test when editing in Atom\n")

N = 20
Np1 = N + 1
Nhp1 = Int(N/2) + 1

data = Dict(
  # Frame(nels, nn, ndim, nst, nip, finite_element(nod, nodof))
  :struc_el => Frame(N, Np1, 3, 1, 1, Line(2, 3)),
  :properties => [1.0e6 1.0e6 1.0e6 3.0e5;],
  :x_coords => range(0, stop=4, length=Np1),
  :y_coords => zeros(Np1),
  :z_coords => zeros(Np1),
  :g_num => [
    collect(1:N)';
    collect(2:Np1)'],
  :support => [
    (1, [1 0 0 0 0 0]),
    (Np1, [0 0 0 0 0 0]),
    ],
  :loaded_nodes => [
    (Nhp1, [0.0 -10000.0 0.0 0.0 0.0 0.0])]
)

@time m, dis_df, fm_df = PtFEM.p44(data)

# See figure 24 in above reference (Δmax):
@test round.(m.displacements[2,Nhp1], digits=11) ≈ -0.00333333333

# See figure 24 in above reference (Mmax):
@test m.actions[12,Nhp1] ≈ 3999.9999999975844


module Day01

using Chain
using ShiftedArrays

import ..data_dir # from parent module

export part1, part2

const data_file = joinpath(data_dir, "day01")
const input = readlines(data_file) # read into an array, each line is an element

# PART 1
function part1(input = input)
    @chain input begin
        parse.(Int32, _)  # convert strings to integers
        _ .- lag(_) # compute difference with previous value
        _[2:end] # remove first element, which will be missing
        filter(x -> x > 0, _) # filter to the increases in value
        length # now count
    end
end

# PART 2
function part2(input = input)
    @chain input begin
        parse.(Int32, _) # convert strings to integers
        _ + lag(_) + lag(_, 2) # compute the sum of each value with its previous 2
        _ - lag(_) # now compute the difference with the previous element
        _[4:end] # remove first three elements, since we're summing triples
        filter(x -> x > 0, _) # filter to positive values, which are the increases in value
        length # now count
    end
end

end # module


module hughes_cantilever_examples
using FinEtools
using FinEtoolsDeforLinear
using FinEtoolsDeforLinear.AlgoDeforLinearModule
using FinEtools.AlgoBaseModule: evalconvergencestudy
using FinEtoolsDeforLinear.AlgoDeforLinearModule: linearstatics, exportstresselementwise, exportstress
using Statistics: mean
using LinearAlgebra: Symmetric, cholesky

# Example from TJR Hughes, The Finite Element Method: Linear Static and Dynamic Finite Element Analysis, 1987.
# Two-dimensional plane-elasticity Solution of beam deflection. Shear force P at one end, and corresponding reactions (tractions) at the other end. The Analytical solution is plane-strain.
# Find out: where does the exact solution come from?

# Isotropic material
E=1.0;
P=1.0;
L=16.0;
c=2.0;
h=1.0;
W=2/3*h*c^3;
CTE = 0.0
tolerance = 0.00001*c

function getfrcL!(forceout::FFltVec, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
    copyto!(forceout, [0.0; 0.0; P/2/W*(c^2-XYZ[3]^2)])
end

function getfrc0!(forceout::FFltVec, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
    copyto!(forceout, [P*L/W*XYZ[3]; 0.0; -P/2/W*(c^2-XYZ[3]^2)])
end

function evaluateerrors(filebase, modeldatasequence)
    println("")
    println("Stress RMS error")
    for md = modeldatasequence
        md["targetfields"] = [e["field"] for e in md["postprocessing"]["exported"]]
    end
    elementsizes, errornorms, p = evalconvergencestudy(modeldatasequence)

    println("Normalized Approximate Error = $(errornorms)")

    f = log.(vec(errornorms))
    A = hcat(log.(vec(elementsizes[1:end-1])), ones(size(f)))
    p = A \ f
    println("Linear log-log fit: p = $(p)")

    csvFile = filebase * "_Stress" * ".CSV"
    savecsv(csvFile,
    elementsizes=vec(elementsizes[1:end-1]),
    elementsizes2=vec(elementsizes[1:end-1].^2),
    elementsizes3=vec(elementsizes[1:end-1].^3),
    errornorms=vec(errornorms)
    )
    println("Wrote $csvFile")

    println("")
    println("Displacement RMS error")
    for md = modeldatasequence
        md["targetfields"] = [md["u"] for r in md["regions"]]
    end
    elementsizes, errornorms, p = evalconvergencestudy(modeldatasequence)

    println("Normalized Approximate Error = $(errornorms)")

    f = log.(vec(errornorms))
    A = hcat(log.(vec(elementsizes[1:end-1])), ones(size(f)))
    p = A \ f
    println("Linear log-log fit: p = $(p)")

    csvFile = filebase * "_Displ" * ".CSV"
    savecsv(csvFile,
    elementsizes=vec(elementsizes[1:end-1]),
    elementsizes2=vec(elementsizes[1:end-1].^2),
    elementsizes3=vec(elementsizes[1:end-1].^3),
    errornorms=vec(errornorms)
    )
    println("Wrote $csvFile")
end

function hughes_cantilever_stresses_H8_by_hand()
    elementtag = "H8"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
    nu=0.3; # COMPRESSIBLE
    E1=E/(1-nu^2);  # Plane strain
    nu1=nu/(1-nu); I=h*(2*c)^3/12;
    exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
    exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    n = 2 #

    nL = 3*n # number of elements lengthwise
    nc = 2*n # number of elements through the depth
    nh = 1 # number of elements through the thickness
    xs = collect(linearspace(0.0, L, nL+1))
    ys = collect(linearspace(0.0, h, nh+1))
    zs = collect(linearspace(-c, +c, nc+1))
    fens,fes = H8blockx(xs, ys, zs)
    # fens,fes = H8toH20(fens,fes)
    bfes = meshboundary(fes)
    # end cross-section surface  for the shear loading
    sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
    # 0 cross-section surface  for the reactions
    sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

    MR = DeforModelRed3D
    material = MatDeforElastIso(MR, 0.0, E, nu, CTE)

    # Material orientation matrix
    csmat = [i==j ? one(FFlt) : zero(FFlt) for i=1:3, j=1:3]

    function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
        copyto!(csmatout, csmat)
    end

    femm = FEMMDeforLinear(MR, IntegDomain(fes, GaussRule(3, 2)), material)

    geom = NodalField(fens.xyz)
    u = NodalField(zeros(size(fens.xyz,1), 3)) # displacement field

    lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
    setebc!(u,lx0,true,1,0.0)
    setebc!(u,lx0,true,2,0.0)
    setebc!(u,lx0,true,3,0.0)
    lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
    lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
    setebc!(u,vcat(lx1, lx2),true,1,0.0)
    ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
    ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
    setebc!(u,vcat(ly1, ly2),true,2,0.0)
    applyebc!(u)
    numberdofs!(u)

    fi = ForceIntensity(FFlt, 3, getfrc0!);
    el1femm = FEMMBase(IntegDomain(subset(bfes, sshear0), GaussRule(2, 2)))
    F1 = distribloads(el1femm, geom, u, fi, 2);
    fi = ForceIntensity(FFlt, 3, getfrcL!);
    el2femm = FEMMBase(IntegDomain(subset(bfes, sshearL), GaussRule(2, 2)))
    F2 = distribloads(el2femm, geom, u, fi, 2);

    associategeometry!(femm, geom)
    K = stiffness(femm, geom, u)

    K = cholesky(K)
    U = K\(F1 + F2)
    scattersysvec!(u,U[:])

    Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
    utip = mean(u.values[Tipl, 3])
    println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

    File =  "hughes_cantilever_stresses_H8_by_hand.vtk"
    vtkexportmesh(File, fens, fes;  vectors=[("u", u.values)])
    @async run(`"paraview.exe" $File`)
    # modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)", "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy, "component"=>[5])
    # modeldata = exportstresselementwise(modeldata)

    # modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
    # "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
    # "component"=>collect(1:6))
    # modeldata = exportstresselementwise(modeldata)
    # stressfields = ElementalField[modeldata["postprocessing"]["exported"][1]["field"]]

    true

end # hughes_cantilever_stresses_H8_by_hand

function hughes_cantilever_stresses_H20_by_hand()
    elementtag = "H20"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
    nu=0.3; # COMPRESSIBLE
    E1=E/(1-nu^2);  # Plane strain
    nu1=nu/(1-nu); I=h*(2*c)^3/12;
    exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
    exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    n = 8 #

    nL = 3*n # number of elements lengthwise
    nc = 2*n # number of elements through the depth
    nh = 1 # number of elements through the thickness
    xs = collect(linearspace(0.0, L, nL+1))
    ys = collect(linearspace(0.0, h, nh+1))
    zs = collect(linearspace(-c, +c, nc+1))
    fens,fes = H8blockx(xs, ys, zs)
    fens,fes = H8toH20(fens,fes)
    bfes = meshboundary(fes)
    # end cross-section surface  for the shear loading
    sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
    # 0 cross-section surface  for the reactions
    sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

    MR = DeforModelRed3D
    material = MatDeforElastIso(MR, 0.0, E, nu, CTE)

    # Material orientation matrix
    csmat = [i==j ? one(FFlt) : zero(FFlt) for i=1:3, j=1:3]

    function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
        copyto!(csmatout, csmat)
    end

    femm = FEMMDeforLinear(MR, IntegDomain(fes, GaussRule(3, 2)), material)

    geom = NodalField(fens.xyz)
    u = NodalField(zeros(size(fens.xyz,1), 3)) # displacement field

    lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
    setebc!(u,lx0,true,1,0.0)
    setebc!(u,lx0,true,2,0.0)
    setebc!(u,lx0,true,3,0.0)
    lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
    lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
    setebc!(u,vcat(lx1, lx2),true,1,0.0)
    ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
    ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
    setebc!(u,vcat(ly1, ly2),true,2,0.0)
    applyebc!(u)
    numberdofs!(u)
    u

    fi = ForceIntensity(FFlt, 3, getfrc0!);
    el1femm = FEMMBase(IntegDomain(subset(bfes, sshear0), GaussRule(2, 2)))
    F1 = distribloads(el1femm, geom, u, fi, 2);
    fi = ForceIntensity(FFlt, 3, getfrcL!);
    el2femm = FEMMBase(IntegDomain(subset(bfes, sshearL), GaussRule(2, 2)))
    F2 = distribloads(el2femm, geom, u, fi, 2);

    associategeometry!(femm, geom)
    K = stiffness(femm, geom, u)

    K = cholesky(K)
    U = K\(F1 + F2)
    scattersysvec!(u,U[:])

    Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
    utip = mean(u.values[Tipl, 3])
    println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

    File =  "hughes_cantilever_stresses_H8_by_hand.vtk"
    vtkexportmesh(File, fens, fes;  vectors=[("u", u.values)])
    @async run(`"paraview.exe" $File`)
    # modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)", "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy, "component"=>[5])
    # modeldata = exportstresselementwise(modeldata)

    # modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
    # "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
    # "component"=>collect(1:6))
    # modeldata = exportstresselementwise(modeldata)
    # stressfields = ElementalField[modeldata["postprocessing"]["exported"][1]["field"]]

    true

end # hughes_cantilever_stresses_MST10

function hughes_cantilever_stresses_T10_by_hand()
    elementtag = "T10"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
    nu=0.3; # COMPRESSIBLE
    E1=E/(1-nu^2);  # Plane strain
    nu1=nu/(1-nu); I=h*(2*c)^3/12;
    exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
    exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    n = 2 #

    nL = 3*n # number of elements lengthwise
    nc = 2*n # number of elements through the depth
    nh = n # number of elements through the thickness
    xs = collect(linearspace(0.0, L, nL+1))
    ys = collect(linearspace(0.0, h, nh+1))
    zs = collect(linearspace(-c, +c, nc+1))
    fens,fes = T10blockx(xs, ys, zs)
    bfes = meshboundary(fes)
    # end cross-section surface  for the shear loading
    sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
    # 0 cross-section surface  for the reactions
    sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

    MR = DeforModelRed3D
    material = MatDeforElastIso(MR, 0.0, E, nu, CTE)

    # Material orientation matrix
    csmat = [i==j ? one(FFlt) : zero(FFlt) for i=1:3, j=1:3]

    function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
        copyto!(csmatout, csmat)
    end

    gr = SimplexRule(3, 4)

    femm = FEMMDeforLinear(MR, IntegDomain(fes, gr), material)

    geom = NodalField(fens.xyz)
    u = NodalField(zeros(size(fens.xyz,1), 3)) # displacement field

    lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
    setebc!(u,lx0,true,1,0.0)
    setebc!(u,lx0,true,2,0.0)
    setebc!(u,lx0,true,3,0.0)
    lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
    lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
    setebc!(u,vcat(lx1, lx2),true,1,0.0)
    ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
    ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
    setebc!(u,vcat(ly1, ly2),true,2,0.0)
    applyebc!(u)
    numberdofs!(u)

    fi = ForceIntensity(FFlt, 3, getfrc0!);
    el1femm = FEMMBase(IntegDomain(subset(bfes, sshear0), SimplexRule(2, 3)))
    F1 = distribloads(el1femm, geom, u, fi, 2);
    fi = ForceIntensity(FFlt, 3, getfrcL!);
    el2femm = FEMMBase(IntegDomain(subset(bfes, sshearL), SimplexRule(2, 3)))
    F2 = distribloads(el2femm, geom, u, fi, 2);

    associategeometry!(femm, geom)
    K = stiffness(femm, geom, u)
    K=cholesky(K)
    U = K\(F1 + F2)
    scattersysvec!(u,U[:])

    Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
    utip = mean(u.values[Tipl, 3])
    println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

    File =  "hughes_cantilever_stresses_T10_by_hand.vtk"
    vtkexportmesh(File, fens, fes;  vectors=[("u", u.values)])
    @async run(`"paraview.exe" $File`)
    # modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)", "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy, "component"=>[5])
    # modeldata = exportstresselementwise(modeldata)

    # modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
    # "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
    # "component"=>collect(1:6))
    # modeldata = exportstresselementwise(modeldata)
    # stressfields = ElementalField[modeldata["postprocessing"]["exported"][1]["field"]]

    true

end # hughes_cantilever_stresses_MST10

function hughes_cantilever_stresses_MST10_by_hand()
    elementtag = "MST10"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
    nu=0.3; # COMPRESSIBLE
    E1=E/(1-nu^2);  # Plane strain
    nu1=nu/(1-nu); I=h*(2*c)^3/12;
    exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
    exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    n = 2 #

    nL = 3*n # number of elements lengthwise
    nc = 2*n # number of elements through the depth
    nh = n # number of elements through the thickness
    xs = collect(linearspace(0.0, L, nL+1))
    ys = collect(linearspace(0.0, h, nh+1))
    zs = collect(linearspace(-c, +c, nc+1))
    fens,fes = T10blockx(xs, ys, zs)
    bfes = meshboundary(fes)
    # end cross-section surface  for the shear loading
    sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
    # 0 cross-section surface  for the reactions
    sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

    MR = DeforModelRed3D
    material = MatDeforElastIso(MR, 0.0, E, nu, CTE)

    # Material orientation matrix
    csmat = [i==j ? one(FFlt) : zero(FFlt) for i=1:3, j=1:3]

    function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
        copyto!(csmatout, csmat)
    end

    gr = SimplexRule(3, 4)

    femm = FEMMDeforLinearMST10(MR, IntegDomain(fes, gr), material)

    geom = NodalField(fens.xyz)
    u = NodalField(zeros(size(fens.xyz,1), 3)) # displacement field

    lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
    setebc!(u,lx0,true,1,0.0)
    setebc!(u,lx0,true,2,0.0)
    setebc!(u,lx0,true,3,0.0)
    lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
    lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
    setebc!(u,vcat(lx1, lx2),true,1,0.0)
    ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
    ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
    setebc!(u,vcat(ly1, ly2),true,2,0.0)
    applyebc!(u)
    numberdofs!(u)

    fi = ForceIntensity(FFlt, 3, getfrc0!);
    el1femm = FEMMBase(IntegDomain(subset(bfes, sshear0), SimplexRule(2, 3)))
    F1 = distribloads(el1femm, geom, u, fi, 2);
    fi = ForceIntensity(FFlt, 3, getfrcL!);
    el2femm = FEMMBase(IntegDomain(subset(bfes, sshearL), SimplexRule(2, 3)))
    F2 = distribloads(el2femm, geom, u, fi, 2);

    associategeometry!(femm, geom)
    K =stiffness(femm, geom, u)
    K=cholesky(K)
    U=  K\(F1 + F2)
    scattersysvec!(u,U[:])

    Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
    utip = mean(u.values[Tipl, 3])
    println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

    # modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)", "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy, "component"=>[5])
    # modeldata = exportstresselementwise(modeldata)

    # modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
    # "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
    # "component"=>collect(1:6))
    # modeldata = exportstresselementwise(modeldata)
    # stressfields = ElementalField[modeldata["postprocessing"]["exported"][1]["field"]]

    true

end # hughes_cantilever_stresses_MST10

function hughes_cantilever_stresses_MST10()
    elementtag = "MST10"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
    nu=0.3; # COMPRESSIBLE
    E1=E/(1-nu^2);  # Plane strain
    nu1=nu/(1-nu); I=h*(2*c)^3/12;
    exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
    exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    modeldatasequence = FDataDict[]
    for n = [1 2 4 8] #

        nL = 3*n # number of elements lengthwise
        nc = 2*n # number of elements through the depth
        nh = n # number of elements through the thickness
        xs = collect(linearspace(0.0, L, nL+1))
        ys = collect(linearspace(0.0, h, nh+1))
        zs = collect(linearspace(-c, +c, nc+1))
        fens,fes = T10blockx(xs, ys, zs)
        bfes = meshboundary(fes)
        # end cross-section surface  for the shear loading
        sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
        # 0 cross-section surface  for the reactions
        sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

        MR = DeforModelRed3D
        material = MatDeforElastIso(MR, 0.0, E, nu, CTE)

        # Material orientation matrix
        csmat = [i==j ? one(FFlt) : zero(FFlt) for i=1:3, j=1:3]

        function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
            copyto!(csmatout, csmat)
        end

        gr = SimplexRule(3, 4)

        region = FDataDict("femm"=>FEMMDeforLinearMST10(MR, IntegDomain(fes, gr), material))

        lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
        # println("lx0 = $(lx0)")
        ex01 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>lx0 )
        ex02 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>lx0 )
        ex03 = FDataDict( "displacement"=>  0.0, "component"=> 3, "node_list"=>lx0 )
        lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
        lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
        # println("vcat(lx1, lx2) = $(vcat(lx1, lx2))")
        ex04 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>vcat(lx1, lx2) )
        ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
        ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
        # println("vcat(ly1, ly2) = $(vcat(ly1, ly2))")
        ey01 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>vcat(ly1, ly2) )

        Trac0 = FDataDict("traction_vector"=>getfrc0!, "femm"=>FEMMBase(IntegDomain(subset(bfes, sshear0), SimplexRule(2, 3))))
        TracL = FDataDict("traction_vector"=>getfrcL!, "femm"=>FEMMBase(IntegDomain(subset(bfes, sshearL), SimplexRule(2, 3))))

        modeldata = FDataDict("fens"=>fens,
        "regions"=>[region],
        "essential_bcs"=>[ex01, ex02, ex03, ex04, ey01],
        "traction_bcs"=>[Trac0, TracL],
        "temperature_change"=>FDataDict("temperature"=>0.0)
        )
        modeldata = linearstatics(modeldata)

        u = modeldata["u"]
        geom = modeldata["geom"]

        Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
        utip = mean(u.values[Tipl, 3])
        println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)", "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy, "component"=>[5])
        modeldata = exportstresselementwise(modeldata)

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
        "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
        "component"=>collect(1:6))
        modeldata = exportstresselementwise(modeldata)
        stressfields = ElementalField[modeldata["postprocessing"]["exported"][1]["field"]]

        modeldata["geometricaltolerance"] = tolerance
        modeldata["elementsize"] = 1.0 / n
        push!(modeldatasequence, modeldata)
    end

    filebase = "hughes_cantilever_stresses_$(elementtag)"
    evaluateerrors(filebase, modeldatasequence)

    true

end # hughes_cantilever_stresses_MST10

function hughes_cantilever_stresses_MST10_incompressible()
    elementtag = "MST10"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
    nu=0.499999999; # INCOMPRESSIBLE
    E1=E/(1-nu^2);  # Plane strain
    nu1=nu/(1-nu); I=h*(2*c)^3/12;
    exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
    exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    modeldatasequence = FDataDict[]
    for n = [1 2 4 8] #

        nL = 3*n # number of elements lengthwise
        nc = 2*n # number of elements through the wwith
        nh = n # number of elements through the thickness
        xs = collect(linearspace(0.0, L, nL+1))
        ys = collect(linearspace(0.0, h, nh+1))
        zs = collect(linearspace(-c, +c, nc+1))
        fens,fes = T10blockx(xs, ys, zs)
        bfes = meshboundary(fes)
        # end cross-section surface  for the shear loading
        sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
        # 0 cross-section surface  for the reactions
        sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

        MR = DeforModelRed3D
        material = MatDeforElastIso(MR,  0.0, E, nu, CTE)

        # Material orientation matrix
        csmat = [i==j ? one(FFlt) : zero(FFlt) for i=1:3, j=1:3]

        function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
            copyto!(csmatout, csmat)
        end

        gr = SimplexRule(3, 4)

        region = FDataDict("femm"=>FEMMDeforLinearMST10(MR,
        IntegDomain(fes, gr), material))

        lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
        # println("lx0 = $(lx0)")
        ex01 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>lx0 )
        ex02 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>lx0 )
        ex03 = FDataDict( "displacement"=>  0.0, "component"=> 3, "node_list"=>lx0 )
        lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
        lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
        # println("vcat(lx1, lx2) = $(vcat(lx1, lx2))")
        ex04 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>vcat(lx1, lx2) )
        ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
        ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
        # println("vcat(ly1, ly2) = $(vcat(ly1, ly2))")
        ey01 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>vcat(ly1, ly2) )

        Trac0 = FDataDict("traction_vector"=>getfrc0!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshear0), SimplexRule(2, 3))))
        TracL = FDataDict("traction_vector"=>getfrcL!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshearL), SimplexRule(2, 3))))

        modeldata = FDataDict("fens"=>fens,
        "regions"=>[region],
        "essential_bcs"=>[ex01, ex02, ex03, ex04, ey01],
        "traction_bcs"=>[Trac0, TracL],
        "temperature_change"=>FDataDict("temperature"=>0.0)
        )
        modeldata = linearstatics(modeldata)

        u = modeldata["u"]
        geom = modeldata["geom"]

        Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
        utip = mean(u.values[Tipl, 3])
        println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
        "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
        "component"=>[5])
        modeldata = exportstresselementwise(modeldata)

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
        "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
        "component"=>collect(1:6))
        modeldata = exportstresselementwise(modeldata)
        stressfields = ElementalField[modeldata["postprocessing"]["exported"][1]["field"]]

        modeldata["geometricaltolerance"] = tolerance
        modeldata["elementsize"] = 1.0 / n
        push!(modeldatasequence, modeldata)
    end

    filebase = "hughes_cantilever_stresses_incompressible_$(elementtag)"
    evaluateerrors(filebase, modeldatasequence)

    true

end # hughes_cantilever_stresses_MST10_incompressible

function hughes_cantilever_stresses_nodal_MST10()
    elementtag = "MST10"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
    nu=0.3; # COMPRESSIBLE
    E1=E/(1-nu^2);  # Plane strain
    nu1=nu/(1-nu); I=h*(2*c)^3/12;
    exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
    exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    modeldatasequence = FDataDict[]
    for n = [1 2 4 8] #

        nL = 3*n # number of elements lengthwise
        nc = 2*n # number of elements through the wwith
        nh = n # number of elements through the thickness
        xs = collect(linearspace(0.0, L, nL+1))
        ys = collect(linearspace(0.0, h, nh+1))
        zs = collect(linearspace(-c, +c, nc+1))
        fens,fes = T10blockx(xs, ys, zs)
        bfes = meshboundary(fes)
        # end cross-section surface  for the shear loading
        sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
        # 0 cross-section surface  for the reactions
        sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

        MR = DeforModelRed3D
        material = MatDeforElastIso(MR,   0.0, E, nu, CTE)

        # Material orientation matrix
        csmat = [i==j ? one(FFlt) : zero(FFlt) for i=1:3, j=1:3]

        function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
            copyto!(csmatout, csmat)
        end

        gr = SimplexRule(3, 4) # rule for tetrahedral meshes

        region = FDataDict("femm"=>FEMMDeforLinearMST10(MR,
        IntegDomain(fes, gr), material))

        lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
        # println("lx0 = $(lx0)")
        ex01 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>lx0 )
        ex02 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>lx0 )
        ex03 = FDataDict( "displacement"=>  0.0, "component"=> 3, "node_list"=>lx0 )
        lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
        lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
        # println("vcat(lx1, lx2) = $(vcat(lx1, lx2))")
        ex04 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>vcat(lx1, lx2) )
        ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
        ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
        # println("vcat(ly1, ly2) = $(vcat(ly1, ly2))")
        ey01 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>vcat(ly1, ly2) )

        Trac0 = FDataDict("traction_vector"=>getfrc0!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshear0), SimplexRule(2, 3))))
        TracL = FDataDict("traction_vector"=>getfrcL!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshearL), SimplexRule(2, 3))))

        modeldata = FDataDict("fens"=>fens,
        "regions"=>[region],
        "essential_bcs"=>[ex01, ex02, ex03, ex04, ey01],
        "traction_bcs"=>[Trac0, TracL],
        "temperature_change"=>FDataDict("temperature"=>0.0)
        )
        modeldata = linearstatics(modeldata)

        u = modeldata["u"]
        geom = modeldata["geom"]

        Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
        utip = mean(u.values[Tipl, 3])
        println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_nodal_$(elementtag)",
        "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
        "component"=>collect(1:6), "nodevalmethod"=>:averaging, "reportat"=>:extraptrend)
        modeldata = exportstress(modeldata)
        stressfields = NodalField[modeldata["postprocessing"]["exported"][1]["field"]]

        modeldata["geometricaltolerance"] = tolerance
        modeldata["elementsize"] = 1.0 / n
        push!(modeldatasequence, modeldata)
    end

    filebase = "hughes_cantilever_stresses_nodal_$(elementtag)"
    evaluateerrors(filebase, modeldatasequence)

    true

end # hughes_cantilever_stresses_nodal_MST10

function hughes_cantilever_stresses_nodal_T10()
    elementtag = "T10"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
    nu=0.3; # COMPRESSIBLE
    E1=E/(1-nu^2);  # Plane strain
    nu1=nu/(1-nu); I=h*(2*c)^3/12;
    exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
    exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    modeldatasequence = FDataDict[]
    for n = [1 2 4 8] #

        nL = 3*n # number of elements lengthwise
        nc = 2*n # number of elements through the wwith
        nh = n # number of elements through the thickness
        xs = collect(linearspace(0.0, L, nL+1))
        ys = collect(linearspace(0.0, h, nh+1))
        zs = collect(linearspace(-c, +c, nc+1))
        fens,fes = T10blockx(xs, ys, zs)
        bfes = meshboundary(fes)
        # end cross-section surface  for the shear loading
        sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
        # 0 cross-section surface  for the reactions
        sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

        MR = DeforModelRed3D
        material = MatDeforElastIso(MR,
        0.0, E, nu, CTE)

        # Material orientation matrix
        csmat = [i==j ? 1.0 : 0.0 for i=1:3, j=1:3]

        function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
            copyto!(csmatout, csmat)
        end

        gr = SimplexRule(3, 4)

        region = FDataDict("femm"=>FEMMDeforLinear(MR,
        IntegDomain(fes, gr), material))

        lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
        # println("lx0 = $(lx0)")
        ex01 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>lx0 )
        ex02 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>lx0 )
        ex03 = FDataDict( "displacement"=>  0.0, "component"=> 3, "node_list"=>lx0 )
        lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
        lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
        # println("vcat(lx1, lx2) = $(vcat(lx1, lx2))")
        ex04 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>vcat(lx1, lx2) )
        ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
        ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
        # println("vcat(ly1, ly2) = $(vcat(ly1, ly2))")
        ey01 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>vcat(ly1, ly2) )

        Trac0 = FDataDict("traction_vector"=>getfrc0!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshear0), SimplexRule(2, 3))))
        TracL = FDataDict("traction_vector"=>getfrcL!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshearL), SimplexRule(2, 3))))

        modeldata = FDataDict("fens"=>fens,
        "regions"=>[region],
        "essential_bcs"=>[ex01, ex02, ex03, ex04, ey01],
        "traction_bcs"=>[Trac0, TracL],
        "temperature_change"=>FDataDict("temperature"=>0.0)
        )
        modeldata = linearstatics(modeldata)

        u = modeldata["u"]
        geom = modeldata["geom"]

        Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
        utip = mean(u.values[Tipl, 3])
        println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_nodal_$(elementtag)",
        "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
        "component"=>collect(1:6))
        modeldata = exportstress(modeldata)
        stressfields = NodalField[modeldata["postprocessing"]["exported"][1]["field"]]

        modeldata["geometricaltolerance"] = tolerance
        modeldata["elementsize"] = 1.0 / n
        push!(modeldatasequence, modeldata)
    end

    filebase = "hughes_cantilever_stresses_nodal_$(elementtag)"
    evaluateerrors(filebase, modeldatasequence)

    true

end # hughes_cantilever_stresses_nodal_T10

function hughes_cantilever_stresses_T10()
    elementtag = "T10"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
    nu=0.3; # COMPRESSIBLE
    E1=E/(1-nu^2);  # Plane strain
    nu1=nu/(1-nu); I=h*(2*c)^3/12;
    exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
    exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    modeldatasequence = FDataDict[]
    for n = [1 2 4 8] #

        nL = 3*n # number of elements lengthwise
        nc = 2*n # number of elements through the wwith
        nh = n # number of elements through the thickness
        xs = collect(linearspace(0.0, L, nL+1))
        ys = collect(linearspace(0.0, h, nh+1))
        zs = collect(linearspace(-c, +c, nc+1))
        fens,fes = T10blockx(xs, ys, zs)
        bfes = meshboundary(fes)
        # end cross-section surface  for the shear loading
        sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
        # 0 cross-section surface  for the reactions
        sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

        MR = DeforModelRed3D
        material = MatDeforElastIso(MR,
        0.0, E, nu, CTE)

        # Material orientation matrix
        csmat = [i==j ? one(FFlt) : zero(FFlt) for i=1:3, j=1:3]

        function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
            copyto!(csmatout, csmat)
        end

        gr = SimplexRule(3, 4)

        region = FDataDict("femm"=>FEMMDeforLinear(MR, IntegDomain(fes, gr), material))

        lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
        # println("lx0 = $(lx0)")
        ex01 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>lx0 )
        ex02 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>lx0 )
        ex03 = FDataDict( "displacement"=>  0.0, "component"=> 3, "node_list"=>lx0 )
        lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
        lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
        # println("vcat(lx1, lx2) = $(vcat(lx1, lx2))")
        ex04 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>vcat(lx1, lx2) )
        ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
        ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
        # println("vcat(ly1, ly2) = $(vcat(ly1, ly2))")
        ey01 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>vcat(ly1, ly2) )

        Trac0 = FDataDict("traction_vector"=>getfrc0!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshear0), SimplexRule(2, 3))))
        TracL = FDataDict("traction_vector"=>getfrcL!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshearL), SimplexRule(2, 3))))

        modeldata = FDataDict("fens"=>fens,
        "regions"=>[region],
        "essential_bcs"=>[ex01, ex02, ex03, ex04, ey01],
        "traction_bcs"=>[Trac0, TracL],
        "temperature_change"=>FDataDict("temperature"=>0.0)
        )
        modeldata = linearstatics(modeldata)

        u = modeldata["u"]
        geom = modeldata["geom"]

        Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
        utip = mean(u.values[Tipl, 3])
        println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
        "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
        "component"=>[5])
        modeldata = exportstresselementwise(modeldata)

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
        "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
        "component"=>collect(1:6))
        modeldata = exportstresselementwise(modeldata)
        stressfields = ElementalField[modeldata["postprocessing"]["exported"][1]["field"]]

        modeldata["geometricaltolerance"] = tolerance
        modeldata["elementsize"] = 1.0 / n
        push!(modeldatasequence, modeldata)
    end

    filebase = "hughes_cantilever_stresses_$(elementtag)"
    evaluateerrors(filebase, modeldatasequence)

    true

end # hughes_cantilever_stresses_T10

function hughes_cantilever_stresses_T10_incompressible()
    elementtag = "T10"
    println("""
    Cantilever example.  Hughes 1987. Element: $(elementtag)
    """)
        nu=0.499999999; # INCOMPRESSIBLE
        E1=E/(1-nu^2);  # Plane strain
        nu1=nu/(1-nu); I=h*(2*c)^3/12;
        exactux(x,y) = (P/(6*E1*I)*(-y)*(3*(L^2-(L-x)^2)+(2+nu1)*(y^2-c^2)));
        exactuy(x,y) = (P/(6*E1*I)*(((L-x)^3-L^3)-((4+5*nu1)*c^2+3*L^2)*(L-x-L)+3*nu1*(L-x)*y^2));

    modeldatasequence = FDataDict[]
    for n = [1 2 4 8] #

        nL = 3*n # number of elements lengthwise
        nc = 2*n # number of elements through the wwith
        nh = n # number of elements through the thickness
        xs = collect(linearspace(0.0, L, nL+1))
        ys = collect(linearspace(0.0, h, nh+1))
        zs = collect(linearspace(-c, +c, nc+1))
        fens,fes = T10blockx(xs, ys, zs)
        bfes = meshboundary(fes)
        # end cross-section surface  for the shear loading
        sshearL = selectelem(fens, bfes; facing=true, direction = [+1.0 0.0 0.0])
        # 0 cross-section surface  for the reactions
        sshear0 = selectelem(fens, bfes; facing=true, direction = [-1.0 0.0 0.0])

        MR = DeforModelRed3D
        material = MatDeforElastIso(MR,  0.0, E, nu, CTE)

        # Material orientation matrix
        csmat = [i==j ? one(FFlt) : zero(FFlt) for i=1:3, j=1:3]

        function updatecs!(csmatout::FFltMat, XYZ::FFltMat, tangents::FFltMat, fe_label::FInt)
            copyto!(csmatout, csmat)
        end

        gr = SimplexRule(3, 4)

        region = FDataDict("femm"=>FEMMDeforLinear(MR,
        IntegDomain(fes, gr), material))

        lx0 = selectnode(fens, box=[0.0 0.0 0.0 0.0 0.0 0.0], inflate=tolerance)
        # println("lx0 = $(lx0)")
        ex01 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>lx0 )
        ex02 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>lx0 )
        ex03 = FDataDict( "displacement"=>  0.0, "component"=> 3, "node_list"=>lx0 )
        lx1 = selectnode(fens, box=[0.0 0.0 0.0 0.0 c c], inflate=tolerance)
        lx2 = selectnode(fens, box=[0.0 0.0 0.0 0.0 -c -c], inflate=tolerance)
        # println("vcat(lx1, lx2) = $(vcat(lx1, lx2))")
        ex04 = FDataDict( "displacement"=>  0.0, "component"=> 1, "node_list"=>vcat(lx1, lx2) )
        ly1 = selectnode(fens, box=[-Inf Inf 0.0 0.0 -Inf Inf], inflate=tolerance)
        ly2 = selectnode(fens, box=[-Inf Inf h h -Inf Inf], inflate=tolerance)
        # println("vcat(ly1, ly2) = $(vcat(ly1, ly2))")
        ey01 = FDataDict( "displacement"=>  0.0, "component"=> 2, "node_list"=>vcat(ly1, ly2) )

        Trac0 = FDataDict("traction_vector"=>getfrc0!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshear0), SimplexRule(2, 3))))
        TracL = FDataDict("traction_vector"=>getfrcL!,
        "femm"=>FEMMBase(IntegDomain(subset(bfes, sshearL), SimplexRule(2, 3))))

        modeldata = FDataDict("fens"=>fens,
        "regions"=>[region],
        "essential_bcs"=>[ex01, ex02, ex03, ex04, ey01],
        "traction_bcs"=>[Trac0, TracL],
        "temperature_change"=>FDataDict("temperature"=>0.0)
        )
        modeldata = linearstatics(modeldata)

        u = modeldata["u"]
        geom = modeldata["geom"]

        Tipl = selectnode(fens, box=[L L 0.0 0.0 0. 0.], inflate=tolerance)
        utip = mean(u.values[Tipl, 3])
        println("Deflection: $(utip), compared to $(exactuy(L,0.0))")

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
        "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
        "component"=>[5])
        modeldata = exportstresselementwise(modeldata)

        modeldata["postprocessing"] = FDataDict("file"=>"hughes_cantilever_stresses_$(elementtag)",
        "outputcsys"=>CSys(3, 3, updatecs!), "quantity"=>:Cauchy,
        "component"=>collect(1:6))
        modeldata = exportstresselementwise(modeldata)
        stressfields = ElementalField[modeldata["postprocessing"]["exported"][1]["field"]]

        modeldata["geometricaltolerance"] = tolerance
        modeldata["elementsize"] = 1.0 / n
        push!(modeldatasequence, modeldata)
    end

    filebase = "hughes_cantilever_stresses_incompressible_$(elementtag)"
    evaluateerrors(filebase, modeldatasequence)

    true

end # hughes_cantilever_stresses_T10_incompressible

function allrun()
    println("#####################################################")
    println("# hughes_cantilever_stresses_H8_by_hand ")
    hughes_cantilever_stresses_H8_by_hand()
    println("#####################################################")
    println("# hughes_cantilever_stresses_H20_by_hand ")
    hughes_cantilever_stresses_H20_by_hand()
    println("#####################################################")
    println("# hughes_cantilever_stresses_T10_by_hand ")
    hughes_cantilever_stresses_T10_by_hand()
    println("#####################################################")
    println("# hughes_cantilever_stresses_MST10 ")
    hughes_cantilever_stresses_MST10()
    println("#####################################################")
    println("# hughes_cantilever_stresses_MST10_incompressible ")
    hughes_cantilever_stresses_MST10_incompressible()
    println("#####################################################")
    println("# hughes_cantilever_stresses_nodal_MST10 ")
    hughes_cantilever_stresses_nodal_MST10()
    println("#####################################################")
    println("# hughes_cantilever_stresses_nodal_T10 ")
    hughes_cantilever_stresses_nodal_T10()
    println("#####################################################")
    println("# hughes_cantilever_stresses_T10 ")
    hughes_cantilever_stresses_T10()
    println("#####################################################")
    println("# hughes_cantilever_stresses_T10_incompressible ")
    hughes_cantilever_stresses_T10_incompressible()
    return true
end # function allrun

end # module hughes_cantilever_examples


using Test
using ARMSampling
using Statistics

@testset "TrapezoidalProposal" begin
    logf(x) = -(x-1)^2
    x = [-3.0, 0.0, 1.0, 2.0, 5.0]
    y = [logf(x1) for x1 in x]

    proposal = TrapezoidalProposal(x, y)
    @test length(proposal) == 3
    @test proposal.w[2] ≈ (ℯ - 1.0)/ℯ
    @test proposal.w[3] ≈ (ℯ - 1.0)/ℯ
    @test x[1] <= sample(proposal) <= x[end]

    insert!(proposal, 0.5, logf(0.5))
    @test length(proposal) == 4
    @test sum(proposal.w[2:3]) > proposal.w[4]

    insert!(proposal, 1.5, logf(1.5))
    @test length(proposal) == 5
    @test sum(proposal.w[2:3]) ≈ sum(proposal.w[4:5])
    @test x[1] <= sample!(proposal, logf, 1.1) <= x[end]

    mysample = [1.1]
    sample_size = 20000
    sample!(mysample, sample_size, proposal, logf)
    @test length(mysample) == sample_size + 1
    @test all( proposal.x[1] .<= mysample .<= proposal.x[end] )
    @test abs(std(mysample) - sqrt(0.5)) < 1e-2
    @test abs(mean(mysample) - 1.0) < 1e-2
end


using DrWatson
@quickactivate "NonlinearDynamicsTextbook"
include(srcdir("colorscheme.jl"))
using Random, OrdinaryDiffEq
import GLMakie

function FitzHugh_Nagumo_ODE(du,u,p,t)
    a, b, d, epsilon, hsq6 = p
    uu = @view u[1,:,:]
    vv = @view u[2,:,:]

    # This code can be optimized a lot if time allows
    # Create padded u matrix to incorporate Newman boundary conditions - 9-point stencil
    uuu=[ [uu[2,2] uu[2,:]' uu[2,end-1] ] ; [ uu[:,2] uu uu[:,end-1] ] ; [ uu[end-1,2] uu[end-1,:]' uu[end-1,end-1] ] ]
    diff_term = d .* (
        4 .* (uuu[2:end-1,1:end-2] .+ uuu[2:end-1,3:end] .+
            uuu[3:end,2:end-1] .+ uuu[1:end-2,2:end-1] ) .+
            uuu[3:end,3:end] .+ uuu[3:end,1:end-2] .+ uuu[1:end-2,3:end] .+
            uuu[1:end-2,1:end-2] .- 20 .*uu
    ) ./ hsq6

    du[1,:,:] = a .* uu .*(1 .-uu).*(uu.-b) .- vv .+ diff_term
    du[2,:,:] = epsilon .* (uu .- vv )
end

# --------------------------  main program  -----------------------------

@time begin

# parameters
L = 300   # size of domain
N = 150   # no. of grid points
h = L/N # spatial steps size
hsq6 = 6*h*h

# FHN parameters
a = 3.
b = 0.2
d = 1.   #  diffusion
epsilon = 0.01

# open figure
kplt = 0  # no. of subplot

allsols = []
allts = []

for ic = 1:2    # initial conditions ( = rows of the plot )

println("ic=",ic)

uu = zeros(N,N)
vv = zeros(N,N)
Random.seed!(13371)
uu = uu .+ 0.01*randn(N,N)    # random perturbation

# local stimulius = concentric waves
if ic == 1
   uu[40:41,40:41] .= 0.999
   uu[75:76,75:76] .= 0.999
end

# local stimulius = spiral waves
if ic == 2
   uu[1:end,10:11] .= 0.999
end

# initial values
u0 = zeros(2,N,N)
u0[1,:,:] = uu
u0[2,:,:] = vv

p = a, b, d, epsilon, hsq6

if ic == 1
    saveat = 0.0:2:600
    tspan = (saveat[1], saveat[end])

    prob = ODEProblem(FitzHugh_Nagumo_ODE, u0, tspan, p)
    sol = solve(prob, Tsit5(); reltol=1e-6, abstol=1e-6, maxiters = 1e7, saveat)
    tvec = sol.t
    uout = [u[1, :, :] for u in sol.u]
    push!(allsols, uout)
    push!(allts, tvec)

elseif ic == 2
    saveat = 0.0:2.0:300.0
    tspan = (saveat[1], saveat[end])
    prob = ODEProblem(FitzHugh_Nagumo_ODE, u0, tspan, p)
    sol = solve(prob, Tsit5(); reltol=1e-6, abstol=1e-6, maxiters = 1e7, saveat)

    uout = [u[1, :, :] for u in sol.u]
    # second perturbation line
    u = sol.u[end]
    u[1, 55:73,1:70] .= 0.999
    saveat = 300.0:2:900
    tspan = (saveat[1], saveat[end])
    prob = ODEProblem(FitzHugh_Nagumo_ODE, u, tspan, p)
    sol = solve(prob, Tsit5(); reltol=1e-6, abstol=1e-6, maxiters = 1e7, saveat)

    tvec = sol.t
    uout2 = [u[1, :, :] for u in sol.u]
    append!(uout, uout2)
    push!(allsols, uout)
    push!(allts, tvec)

end
end # ic loop
end # cputime

# %% Animate
names = ("concentric", "plane_to_spiral")

for i in (1,2)
    name = names[i]
    uout = allsols[i]
    tvec = allts[i]

    heatobs = GLMakie.Observable(uout[1])
    tobs = GLMakie.Observable(0.0)
    titobs = GLMakie.lift(t -> "t = $(t)", tobs)

    fig = GLMakie.Figure(resolution = (600, 550))
    ax = fig[1,1] = GLMakie.Axis(fig; title = titobs)
    hmap = GLMakie.heatmap!(ax, heatobs; colormap = :tokyo, colorrange = (-0.2, 1))
    cb = GLMakie.Colorbar(fig[1, 2], hmap; width = 20)
    display(fig)

    GLMakie.record(
        fig, projectdir("animations", "11", "fitzhugh_$(name).mp4"),
        1:length(tvec); framerate = 15
    ) do i

        tobs[] = tvec[i]
        heatobs[] = uout[i]
    end

end


# Toy linear ODE with 2 DOFs
# u_1_t - a * u_1 = 0
# u_2_t - b * u_1 - c * u_2 = 0

# Toy 2nd order ODE with 2 DOFs
# u_1_tt + b * u_1_t - a * u_1 = 0
# u_2_tt + a * u_1_t - b * u_1 - c * u_2 = 0

import Gridap.ODEs.ODETools: ODEOperator
import Gridap.ODEs.ODETools: AffineODEOperator
import Gridap.ODEs.ODETools: ConstantODEOperator
import Gridap.ODEs.ODETools: allocate_cache
import Gridap.ODEs.ODETools: update_cache!
import Gridap.ODEs.ODETools: allocate_residual
import Gridap.ODEs.ODETools: jacobian!
import Gridap.ODEs.ODETools: jacobians!
import Gridap.ODEs.ODETools: allocate_jacobian
import Gridap.ODEs.ODETools: residual!
using SparseArrays: spzeros

struct ODEOperatorMock{T<:Real,C} <: ODEOperator{C}
  a::T
  b::T
  c::T
  order::Integer
end

get_order(op::ODEOperatorMock) = op.order

function residual!(r::AbstractVector,op::ODEOperatorMock,t::Real,x::NTuple{2,AbstractVector},ode_cache)
  u,u_t = x
  r .= 0
  r[1] = u_t[1] - op.a * u[1]
  r[2] = u_t[2] - op.b * u[1] - op.c * u[2]
  r
end

function residual!(r::AbstractVector,op::ODEOperatorMock,t::Real,x::NTuple{3,AbstractVector},ode_cache)
  u,u_t,u_tt = x
  r .= 0
  r[1] = u_tt[1] + op.b * u_t[1] - op.a * u[1]
  r[2] = u_tt[2] + op.a * u_t[1]- op.b * u[1] - op.c * u[2]
  r
end

function allocate_residual(op::ODEOperatorMock,u::AbstractVector,cache)
  zeros(2)
end

function jacobian!(J::AbstractMatrix,
  op::ODEOperatorMock,
  t::Real,
  x::NTuple{2,AbstractVector},
  i::Int,
  γᵢ::Real,
  ode_cache)
  @assert get_order(op) == 1
  @assert 0 < i <= get_order(op)+1
  if i==1
    J[1,1] += -op.a
    J[2,1] += -op.b
    J[2,2] += -op.c
  elseif i==2
    J[1,1] += 1.0*γᵢ
    J[2,2] += 1.0*γᵢ
  end
  J
end

function jacobian!(J::AbstractMatrix,
  op::ODEOperatorMock,
  t::Real,
  x::NTuple{3,AbstractVector},
  i::Int,
  γᵢ::Real,
  ode_cache)
  @assert get_order(op) == 2
  @assert 0 < i <= get_order(op)+1
  if i==1
    J[1,1] += -op.a
    J[2,1] += -op.b
    J[2,2] += -op.c
  elseif i==2
    J[1,1] += op.b*γᵢ
    J[2,2] += op.a*γᵢ
  elseif i==3
    J[1,1] += 1.0*γᵢ
    J[2,2] += 1.0*γᵢ
  end
  J
end

function jacobians!(
  J::AbstractMatrix,
  op::ODEOperatorMock,
  t::Real,
  x::Tuple{Vararg{AbstractVector}},
  γ::Tuple{Vararg{Real}},
  ode_cache)
  @assert length(γ) == get_order(op) + 1
  for order in 1:get_order(op)+1
    jacobian!(J,op,t,x,order,γ[order],ode_cache)
  end
  J
end

function allocate_jacobian(op::ODEOperatorMock,u::AbstractVector,cache)
  spzeros(2,2)
end

allocate_cache(op::ODEOperatorMock) = nothing
allocate_cache(op::ODEOperatorMock,v::AbstractVector,a::AbstractVector) = (v,a,nothing)
update_cache!(cache,op::ODEOperatorMock,t::Real) = cache


#= -------------------------------------------------------------------------
# @file transformations.jl
#
# @date 2019-04-09
# @author Martin Noblia
# @email mnoblia@disroot.org
#
# @brief
# Common Robotics transformations
# @detail
#
#  Licence:
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
---------------------------------------------------------------------------=#
# NOTE(elsuizo:2019-04-09): usamos esto por performance ya que sabemos de antemano el size de los arrays
#=------------------------------------------------------------------------------
imports
------------------------------------------------------------------------------=#
using StaticArrays
using LinearAlgebra

#=------------------------------------------------------------------------------
code
------------------------------------------------------------------------------=#
# TODO(elsuizo:2020-04-16): tendria que hacer la conversion a rad o deg en las funciones
# o sino con algun package como UnitfulAngle.jl

function rot2(θ::Real)
    @SMatrix [cos(θ) -sin(θ);
              sin(θ)   cos(θ)]
end

function trot2(θ::Real)
   R = @SMatrix zeros(3, 3)
   R[:, end] = [0.0, 0.0, 1.0]
   R[1:2, 1:2] = rot2(θ)
   return R
end

"""
Compute the rotation around the `x` axis(in cartesian coordinates)

Input:
-----

∠ : Angle(Number)

Output:
------

Rₓ : Rotation matrix of angle Input

example:
-------

`R = rotx(deg2rad(30)) # rotation around x 30 degrees`
"""
function rotx(θ::Real)
   Rₓ = @SMatrix [1.0   0.0       0.0;
                  0.0  cos(θ) -sin(θ);
                  0.0  sin(θ)   cos(θ)]

   return Rₓ
end

"""
Compute the rotation around the `y` axis(in cartesian coordinates)

Input:
-----

∠ : Angle(Number)

Output:
------

R_y: Rotation matrix of angle input

example:
-------
`R = roty(deg2rad(30)) # rotation around y 30 degrees`

"""
function roty(θ::Real)

   R_y = @SMatrix [cos(θ)  0.0  sin(θ);
                    0.0    1.0     0.0;
                  -sin(θ)  0.0  cos(θ)]

   return R_y
end

"""
Compute the rotation around the `z` axis(in cartesian coordinates)

Input:
-----

∠ : Angle(Number)

Output:
------

R_z: Rotation matrix of angle Input

example:
-------

`R = rotz(deg2rad(30)) # rotation around z 30 degrees`
"""
function rotz(θ::Real, type_of_angle::Symbol=:deg)

   R_z = @SMatrix [cos(θ)  -sin(θ) 0.0;
                   sin(θ)   cos(θ) 0.0;
                    0.0       0.0  1.0]

   return R_z
end

"""
Rotatation about x axis
"""
function trotx(θ::Real)
   return rot2trans(rotx(θ))
end

"""
Rotatation about y axis
"""
function troty(θ::Real)
   return rot2trans(roty(θ))
end

"""
Rotatation about z axis
"""
function trotz(θ::Real)
   return rot2trans(rotz(θ))
end

"""
Convert a 3x3 Rotation matrix to a 4x4 homogeneous transformation
"""
function rot2trans(r::AbstractArray{Float64, 2})
   R = @SMatrix zeros(4,4)
   R[:, end] = [0.0, 0.0, 0.0, 1.0]
   R[1:3, 1:3] = r
   return R
end

"""
Compute the rotation Matrix from Euler angles from the convention ZYZ

Inputs:
------
ϕ: first angle of euler(Number)
θ: second angle of euler(Number)
ψ: third angle of euler(Number)

Output:
------

R: Rotation matrix(3x3 Array{Float64, 2})
"""
function euler2rot(ϕ::Real, θ::Real, ψ::Real)

    return R = rotz(ϕ) * roty(θ) * rotz(ψ)
end

"""
Compute the rotation Matrix from Euler angles from the convention ZYZ

Input:
------
vec: Vector with the euler angles([ϕ, θ, ψ])

Output:
------

R: Rotation matrix(3x3 Array{Float64, 2})

"""
function euler2rot(vec::Array{T,1}) where T<:Real
   l = length(vec)
   if l != 3
      error("The length of the vector must be 3")
   end
   return R = rotz(vec[1]) * roty(vec[2]) * rotz(vec[3])
end

"""
Compute the euler angles from a Rotation matrix(ZYZ convention)

Input:
-----

R: Rotation matrix(Array{Float64, 2})

Outputs:
------

ϕ: first angle of euler(radian Number)
θ: second angle of euler(radian Number)
ψ: third angle of euler(radian Number)

"""
function rot2euler(R::AbstractArray{T, 2}) where T<:Real

    if abs(R[1,3]) < eps(Float64) && abs(R[2,3]) < eps(Float64)
        # singularity
        ϕ = 0.0
        sp = 0.0
        cp = 1.0
        θ = atan(cp * R[1, 3] + sp * R[2, 3], R[3, 3])
        ψ = atan(-sp * R[1, 1] + cp * R[2, 1], -sp * R[1, 2] + cp * R[2, 2])
    else
        # non-singular
        ϕ = atan(R[2, 3], R[1, 3])
        sp = sin(ϕ)
        cp = cos(ϕ)
        θ = atan(cp * R[1, 3] + sp * R[2, 3], R[3, 3])
        ψ = atan(-sp * R[1, 1] + cp * R[2, 1], -sp * R[1, 2] + cp * R[2, 2])
    end

    return rad2deg(ϕ), rad2deg(θ), rad2deg(ψ)
end

"""
Compute the Rotation from Euler angles

Inputs:
------
ϕ: first angle of euler(Number)
θ: second angle of euler(Number)
ψ: third angle of euler(Number)

Output:
------

R: Rotation homogeneous matrix(4x4 Array{Float64, 2})
"""
function euler2trans(ϕ, θ, ψ)
   return rot2trans(euler2rot(ϕ, θ, ψ))
end

"""
Compute the Rotation matrix from an arbitrary axis and angle.

Inputs:
------

θ: Angle of rotation(any Real number)
v: axis of rotation(Array{T, 1} with T any Real number)

Output:
------

R: Rotation matrix(AbstractArray{T, 2})
"""
function angle_vector2rot(θ::T, v::AbstractArray{T, 1}) where T<:Real

   cth = cos(θ)
   sth = sin(θ)
   vth = (one(T) - cth)
   v_x = v[1]; v_y = v[2]; v_z = v[3]
   @SMatrix [
      v_x*v_x*vth+cth      v_y*v_x*vth-v_z*sth   v_z*v_x*vth+v_y*sth
      v_x*v_y*vth+v_z*sth   v_y*v_y*vth+cth      v_z*v_y*vth-v_x*sth
      v_x*v_z*vth-v_y*sth   v_y*v_z*vth+v_x*sth   v_z*v_z*vth+cth
   ]
end

function skew(number:: T) where T<:Real
   z = zero(number)
   @SMatrix [z -number; number z]
end

function skew(v::Vector{T}) where T<:Real
   # checking the imput
   l = length(v)
   l == 3 || throw(DimensionMismatch("the vector must be of length 3 or scalar"))
   # for type-stability
   z = zero(T)
   @SMatrix [  z   -v[3]  v[2];
             v[3]    z   -v[1];
            -v[2]   v[1]   z  ]
end

# FIXME(elsuizo): No puedo asi como esta convertirlo a StaticArray, porque me tira un error
"""
Compute the augmented skew-symmetric matrix from a vector `v`

Inputs:
------

v: Vector

Output:
------

R: AbstractArray{T}
"""
function skewa(v::Vector{T}) where T<:Real
   # checking the imput
   l = length(v)
   l == 3 || l == 6 || throw(DimensionMismatch("the vector must be of 3 or 6 elements"))
   # for type-stability
   z = zero(T)
   if l == 3
      [skew(v[3]) v[1:2]; z z z]
   elseif l == 6
      [skew(v[4:6]) v[1:3]; z z z z]
   end
end

function vex(m::AbstractArray{T}) where T<:Real
   z = zero(T)
   s = size(m)
   # check the size of the matrix
   s == (3, 3) || s == (2, 2) || throw(DimensionMismatch("The matrix must be 2x2 or 3x3"))

   # check if the matrix are skew
   all(diag(m) .== z) || throw(error("the input must be skew-symetric"))

   if s == (3, 3)
      result = 0.5 * [m[3,2] - m[2,3]; m[1,3] - m[3,1]; m[2,1] - m[1,2]]
      convert.(T, result)
   else
      result = 0.5 * (m[2,1] - m[1,2])
      convert.(T, result)
   end
end

# TODO(elsuizo:2020-04-16): terminar esta funcion que parece que llama a otras que faltan hacer
function vexa(m::AbstractArray{T}) where T<:Real
   # check the size of the matrix
   s == (4, 4) || s == (3, 3) || throw(DimensionMismatch("The matrix must be 2x2 or 3x3"))
end


# ---
# title: 18. 4Sum
# id: problem18
# author: zhwang
# date: 2022-03-15
# difficulty: Medium
# categories: Array, Hash Table, Two Pointers
# link: <https://leetcode.com/problems/4sum/description/>
# hidden: true
# ---
#
# Given an array `nums` of _n_ integers and an integer `target`, are there
# elements _a_ , _b_ , _c_ , and _d_ in `nums` such that _a_ \+ _b_ \+ _c_ \+
# _d_ = `target`? Find all unique quadruplets in the array which gives the sum
# of `target`.
#
# **Notice**  that the solution set must not contain duplicate quadruplets.
#
#
#
# **Example 1:**
#
#
#
#     Input: nums = [1,0,-1,0,-2,2], target = 0
#     Output: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
#
#
# **Example 2:**
#
#
#
#     Input: nums = [], target = 0
#     Output: []
#
#
#
#
# **Constraints:**
#
#   * `0 <= nums.length <= 200`
#   * `-109 <= nums[i] <= 109`
#   * `-109 <= target <= 109`
#
#
## @lc code=start
using LeetCode

four_sum(nums::Vector{Int}, target::Int) = four_sum!(copy(nums), target)
function four_sum!(nums::Vector{Int}, target::Int)::Vector{NTuple{4,Int}}
    n, res = length(sort!(nums)), NTuple{4,Int}[]
    n <= 3 && return NTuple{4,Int}[]
    for (i, first) in enumerate(@view(nums[1:(end - 3)]))
        i > 1 && first == nums[i - 1] && continue ## avoid repetition
        sum(@view(nums[i:(i + 3)])) > target && return res ## pruning
        first + sum(@view(nums[(end - 3):end])) < target && continue ## pruning
        for j in (i + 1):(n - 2)
            j > i + 1 && nums[j] == nums[j - 1] && continue ## avoid repetition
            first + sum(@view(nums[j:(j + 2)])) > target && break ## pruning
            first + nums[j] + nums[end - 1] + nums[end] < target && continue ## pruning
            newtarget = target - first - nums[j]
            left, right = j + 1, n
            while left < right
                newsum = nums[left] + nums[right]
                if newsum < newtarget
                    left += 1
                elseif newsum > newtarget
                    right -= 1
                else
                    push!(res, (first, nums[j], nums[left], nums[right]))
                    pos = findfirst(!=(nums[left]), @view(nums[(left + 1):right]))
                    isnothing(pos) ? break : (left += pos)
                    pos = findfirst(!=(nums[right]), @view(nums[(right - 1):-1:left]))
                    isnothing(pos) ? break : (right -= pos)
                end
            end
        end
    end
    return res
end
## @lc code=end


# convenience function to calculate the mean-squared error
function mse(arr1::AbstractArray, arr2::AbstractArray)
    if size(arr1) != size(arr2)
        throw(DimensionMismatch("Got $(size(arr1)) and $(size(arr2))"))
    end
    N = length(arr1)
    err = 0.0
    for i in 1:N
        err += (arr2[i] - arr1[i])^2
    end
    err /= N
end


using Gadfly
# using Sigma
# REVIEW - Decide whether plotting functions should return plot or layer
# REVIEW - Add 3D preimages. Important, not just because the look cool
#        - but because they will help with intuitions about independence
#        - and symmetry

function plot_preimage(X::RandVar{Bool};prob_args...)
  satsets, mixedsets = Sigma.pre_bfs(X, t, LazyOmega();prob_args...)
  plot_preimage(satsets)
end

function plot_preimage(X::RandVar{Bool}, dims::Vector; prob_args...)
  satsets, mixedsets = Sigma.pre_bfs(X, t, LazyOmega();prob_args...)
  plot_preimage(satsets, dims)
end

function plot_preimage(os::Vector{Omega{Interval}})
  intervals = Vector{Interval}[convert(Vector{Interval},o) for o in os]
  plot_2d_boxes(intervals)
end

function plot_preimage(os::Vector{Omega{Interval}}, dims::Vector)
  intervals = Vector{Interval}[convert(Vector{Interval},o, dims) for o in os]
  @show typeof(intervals)
  plot_2d_boxes(intervals)
end

# Returns mathematica function
function plot_preimage3D(X::RandVar{Bool};prob_args...)
  satsets, mixedsets = Sigma.pre_bfs(X, t, LazyOmega();prob_args...)
  plot_preimage3D(satsets,mixedsets)
end

function plot_preimage3D(satos::Vector{Omega{Interval}}, mixedos::Vector{Omega{Interval}})
  satintervals = Vector{Interval}[convert(Vector{Interval},o) for o in satos]
  mixedintervals = Vector{Interval}[convert(Vector{Interval},o) for o in mixedos]

  satcuboids = ["Cuboid[{$(box[1].l), $(box[2].l), $(box[3].l)}, {$(box[1].u), $(box[2].u), $(box[3].u)}]" for box in satintervals]
  mixedos = ["Cuboid[{$(box[1].l), $(box[2].l), $(box[3].l)}, {$(box[1].u), $(box[2].u), $(box[3].u)}]" for box in mixedintervals]
  "Graphics3D[{Green, Opacity[0.3],$(join(satcuboids, ",")),Blue, Opacity[1.0],$(join(mixedos, ","))},{Axes->True},{PlotRange -> {{0, 1}, {0, 1}, {0, 1}}}, {AxesLabel->{ω1,ω2,ω3}}, {ViewPoint -> Dynamic[vp]}]"
end

# Take as argument canvas range
function plot_2d_boxes(bs::Vector{Vector{Interval}};
                       abs_x_min = 0.0, abs_y_min = 0.0,
                       abs_x_max = 1.0, abs_y_max = 1.0)
  x_min = Float64[]
  y_min = Float64[]
  x_max = Float64[]
  y_max = Float64[]

  for b in bs
    push!(x_min, b[1].l)
    push!(x_max, b[1].u)
    push!(y_min, b[2].l)
    push!(y_max, b[2].u)
  end

  # Update absolumte min/max values for canvas
  abs_x_min = min(abs_x_min, minimum(x_min))
  abs_y_min = min(abs_y_min, minimum(y_min))
  abs_y_max = min(abs_y_max, maximum(y_max))
  abs_x_max = min(abs_x_max, maximum(x_max))

  plot(x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max,
       color=linspace(0,1,length(bs)),
       Theme(line_width=10.0mm,highlight_width=20.0mm),
       Geom.rectbin,
       Scale.x_continuous(minvalue=abs_x_min, maxvalue=abs_y_max),
       Scale.y_continuous(minvalue=abs_y_min, maxvalue=abs_y_max),
       Coord.cartesian(fixed=true))
end

# FIXME, REVIEW: This doesn't seem to be working
function plot_volume_hist{T}(os::Vector{Omega{T}})
  vols = Float64[Sigma.measures(o) for o in os]
  plot(x=vols, Geom.histogram, Scale.y_log10)
end

# FIXME, REVIEW: This doesn't seem to be working
function plot_volume_hist(t::Sigma.Tree)
  sat_nodes::Vector{Omega} = map(n->n.data,t.nodes)
  volumes = measures(sat_nodes)
  plot(x = volumes, Geom.histogram, Scale.y_log10)
end

function plot_density(X::RandVar, lower::Real, upper::Real;
                      n_bars = 20, progargs...)
  xs = Array{Float64}(n_bars - 1)
  ys = Array{Float64}(n_bars - 1)
  ymin = Array{Float64}(n_bars - 1)
  ymax = Array{Float64}(n_bars - 1)
  for i in 1:(n_bars - 1)
    j = i + 1
    l,u = linspace(lower,upper,n_bars)[i],linspace(lower,upper,n_bars)[j]
    prob_bounds = prob((X > l) & (X <= u); progargs...)
    ys[i] = Sigma.mid(prob_bounds)
    ymin[i] = prob_bounds.l
    ymax[i] = prob_bounds.u
    xs[i] = (u-l)/2 + l
  end
  plot(x=xs, y=ys, Scale.x_continuous(minvalue=lower, maxvalue=upper),
       Scale.y_continuous(minvalue=0),
       ymin = ymin, ymax = ymax, Geom.line, Geom.errorbar)
end

# REVIEW - DRY
function plot_cond_density(X::RandVar, Y::RandVar, lower::Real, upper::Real;
                           n_bars = 20, progargs...)
  xs = Array{Float64}(n_bars - 1)
  ys = Array{Float64}(n_bars - 1)
  ymin = Array{Float64}(n_bars - 1)
  ymax = Array{Float64}(n_bars - 1)
  for i in 1:(n_bars - 1)
    j = i + 1
    l,u = linspace(lower,upper,n_bars)[i],linspace(lower,upper,n_bars)[j]
    prob_bounds = cond_prob((X > l) & (X <= u),Y; progargs...)
    ys[i] = Sigma.mid(prob_bounds)
    ymin[i] = prob_bounds.l
    ymax[i] = prob_bounds.u
    xs[i] = (u-l)/2 + l
  end
  plot(x=xs, y=ys, Scale.x_continuous(minvalue=lower, maxvalue=upper),
       Scale.y_continuous(minvalue=0),
       ymin = ymin, ymax = ymax, Geom.line, Geom.errorbar)
end

# REVIEW - Test,
function plot_sample_density(X::RandVar, nsamples::Int64)
  samples = [rand(X) for i = 1:nsamples]
  Gadfly.plot(x = samples, Gadfly.Geom.density, Gadfly.Geom.Scale.y_continuous(minvalue=0))
end

function plot_sample_histogram(X::RandVar, nsamples::Int64)
  samples = [rand(X) for i = 1:nsamples]
  Gadfly.plot(x = samples, Gadfly.Geom.histogram, Gadfly.Geom.Scale.y_continuous(minvalue=0))
end

function plot_sample_cond_histogram(X::RandVar, Y::RandVar{Bool}, nsamples::Int64; probargs...)
  condX = conditional(X,Y; probargs...)
  samples = [rand(condX) for i = 1:nsamples]
  Gadfly.plot(x = samples, Gadfly.Geom.histogram, Gadfly.Geom.Scale.y_continuous(minvalue=0))
end

function plot_sample_cond_density(X::RandVar, Y::RandVar{Bool}, nsamples::Int64; probargs...)
  condX = conditional(X,Y; probargs...)
  samples = [rand(condX) for i = 1:nsamples]
  Gadfly.plot(x = samples, Gadfly.Geom.density, Gadfly.Geom.Scale.y_continuous(minvalue=0))
end

function plot_sat_distribution(t::Sigma.Tree)
  sat_nodes = filter(x->x.status==SAT,t.nodes)
  unsat_nodes = filter(x->x.status==UNSAT,t.nodes)
  mixed_nodes = filter(x->x.status==PARTIALSAT,t.nodes)
  println("Relative counts of SAT UNSAT AND MIXED SAT are: ", map(length, Array[sat_nodes, unsat_nodes, mixed_nodes]))
  plot(y = map(length, Array[sat_nodes, unsat_nodes, mixed_nodes]), x = ["SAT", "UNSAT", "MIXED"], Geom.bar)
end


using Revise

using ADCME
using PyCall
using LinearAlgebra
using PyPlot
using SparseArrays
using Random
# Random.seed!(233)

# TODO: specify your input parameters
A = sprand(10,5,0.3)
f = rand(10)
sol = A\f
u = constant(A)\f

sess = Session()
init(sess)
@show run(sess, u)-sol
# error()

# TODO: change your test parameter to `m`
# gradient check -- v
function scalar_function(m)
    return sum((constant(A)\m)^2)
    B = SparseTensor(ii, jj, m, size(A)...)
    return sum((B\Array([f f]'))^2)
end

ii, jj, vv = find(constant(A))

# TODO: change `m_` and `v_` to appropriate values
# m_ = constant(rand(length(vv)))
# v_ = rand(length(vv))
m_ = constant(rand(5,10))
v_ = rand(5,10)
y_ = scalar_function(m_)
dy_ = gradients(y_, m_)
ms_ = Array{Any}(undef, 5)
ys_ = Array{Any}(undef, 5)
s_ = Array{Any}(undef, 5)
w_ = Array{Any}(undef, 5)
gs_ =  @. 1 / 10^(1:5)

for i = 1:5
    g_ = gs_[i]
    ms_[i] = m_ + g_*v_
    ys_[i] = scalar_function(ms_[i])
    s_[i] = ys_[i] - y_
    w_[i] = s_[i] - g_*sum(v_.*dy_)
end

sess = Session()
init(sess)
sval_ = run(sess, s_)
wval_ = run(sess, w_)
close("all")
loglog(gs_, abs.(sval_), "*-", label="finite difference")
loglog(gs_, abs.(wval_), "+-", label="automatic differentiation")
loglog(gs_, gs_.^2 * 0.5*abs(wval_[1])/gs_[1]^2, "--",label="\$\\mathcal{O}(\\gamma^2)\$")
loglog(gs_, gs_ * 0.5*abs(sval_[1])/gs_[1], "--",label="\$\\mathcal{O}(\\gamma)\$")

plt.gca().invert_xaxis()
legend()
xlabel("\$\\gamma\$")
ylabel("Error")


# Statistics functions

import Base: mean, median, std, var, cov

export meanWeighted, varWeighted, corrcoef

for (op, fn) in ((:mean, :af_mean_all), (:median, :af_median_all),
                    (:std, :af_stdev_all))

    @eval function ($op){T<:Real}(a::AFArray{T})
        real = Base.Ref{Cdouble}(0)
        imag = Base.Ref{Cdouble}(0)
        eval($fn)(real, imag, a)
        T(real[])
    end

    @eval function ($op){T<:Complex}(a::AFArray{T})
        real = Base.Ref{Cdouble}(0)
        imag = Base.Ref{Cdouble}(0)
        eval($fn)(real, imag, a)
        complex(real[], imag[])
    end

end

for (op, fn) in ((:meanWeighted, :af_mean_all_weighted),
                    (:varWeighted, :af_var_all_weighted))

    @eval function ($op){T<:Real,S}(a::AFArray{T}, w::AFArray{S})
        real = Base.Ref{Cdouble}(0)
        imag = Base.Ref{Cdouble}(0)
        eval($fn)(real, imag, a, w)
        T(real[])
    end

    @eval function ($op){T<:Complex,S}(a::AFArray{T}, w::AFArray{S})
        real = Base.Ref{Cdouble}(0)
        imag = Base.Ref{Cdouble}(0)
        eval($fn)(real, imag, a, w)
        complex(real[], imag[])
    end

end

for (op, fn) in ((:mean, :af_mean), (:median, :af_median),
                    (:std, :af_stdev))

    @eval function ($op){T}(a::AFArray{T}, dim::Integer)
        out = new_ptr()
        eval($fn)(out, a, Cuint(dim-1))
        AFArray{T}(out[])
    end

end

for (op, fn) in ((:meanWeighted, :af_mean_weighted), (:varWeighted, :af_var_weighted))

    @eval function ($op){T}(a::AFArray{T}, w::AFArray{T}, dim::Integer)
        out = new_ptr()
        eval($fn)(out, a, w, Cuint(dim-1))
        AFArray{T}(out[])
    end

end

function var{T}(a::AFArray{T}; is_biased = false)
    real = Base.Ref{Cdouble}(0)
    imag = Base.Ref{Cdouble}(0)
    af_var_all(real, imag, a, is_biased)
    Float64(real[])
end

function var{T}(a::AFArray{T}, dim::Integer; is_biased = false)
    out = new_ptr()
    af_var(out, a, is_biased, Cuint(dim-1))
    AFArray{backend_eltype(out[])}(out[])
end

function cov(a::AFArray, b::AFArray; is_biased = false)
    out = new_ptr()
    af_cov(out, a, b, is_biased)
    AFArray{backend_eltype(out[])}(out[])
end

function corrcoef(a::AFArray, b::AFArray)
    real = Base.Ref{Cdouble}(0)
    imag = Base.Ref{Cdouble}(0)
    af_corrcoef(real, imag, a, b)
    if imag[] == 0
        real[]
    else
        complex(real[], imag[])
    end
end


struct Monomial <: LsmBasisSystemPolynomType end

struct MonomialFunction <: LSMBasisSystemFunction
  order::Int
end

function (m::MonomialFunction)(x::Float64)
  ret = 1.0
  @simd for i = 1:m.order
    ret *= x
  end

  return ret
end

get_type(::Monomial) = MonomialFunction{Int}

function path_basis_system!(::Monomial, order::Int, v::Vector)
  @simd for i = 1:order + 1
    @inbounds v[i] = MonomialFunction(i - 1)
  end

  return v
end


@testset "conic linear problems" begin
    @testset "conic_linear1_test" begin
        #=
        primal
            min -3x - 2y - 4z
        s.t.
            x +  y +  z == 3 :w_1
            y +  z == 2      :w_2
            x>=0 y>=0 z>=0

        dual
            max 3w_1 + 2w_2
        s.t.
            [-w_1 - 3.0,
             -w_1 - w_2 - 2.0,
             -w_1 - w_2 - 4.0] in Nonnegatives
        =#
        primal_model = conic_linear1_test()
        dual_model, primal_dual_map = dual_model_and_map(primal_model)

        @test MOI.get(dual_model, MOI.NumberOfVariables()) == 2
        list_of_cons = MOI.get(dual_model, MOI.ListOfConstraints())
        @test list_of_cons == [(VAF{Float64}, MOI.Nonnegatives)]
        @test MOI.get(
            dual_model,
            MOI.NumberOfConstraints{VAF{Float64},MOI.Nonnegatives}(),
        ) == 1
        obj_type = MOI.get(dual_model, MOI.ObjectiveFunctionType())
        @test obj_type == SAF{Float64}
        @test MOI.get(dual_model, MOI.ObjectiveSense()) == MOI.MAX_SENSE
        obj = MOI.get(dual_model, MOI.ObjectiveFunction{obj_type}())
        @test MOI.constant(obj) == 0.0
        @test Set(MOI.coefficient.(obj.terms)) == Set([3.0; 2.0])

        ci = first(
            MOI.get(
                dual_model,
                MOI.ListOfConstraintIndices{VAF{Float64},MOI.Nonnegatives}(),
            ),
        )
        eq_con1_fun = MOI.get(dual_model, MOI.ConstraintFunction(), ci)
        @test MOI.coefficient.(eq_con1_fun.terms) == -ones(5)
        @test MOI.constant(eq_con1_fun) == [-3.0, -2.0, -4.0]
        @test MOI.get(dual_model, MOI.ConstraintSet(), ci) ==
              MOI.Nonnegatives(3)

        primal_con_dual_var = primal_dual_map.primal_con_dual_var
        ci_zero = first(
            MOI.get(
                primal_model,
                MOI.ListOfConstraintIndices{VAF{Float64},MOI.Zeros}(),
            ),
        )
        @test primal_con_dual_var[ci_zero] == VI.(1:2)
        ci_nneg = first(
            MOI.get(
                primal_model,
                MOI.ListOfConstraintIndices{VVF,MOI.Nonnegatives}(),
            ),
        )
        @test !haskey(primal_con_dual_var, ci_nneg)
        @test primal_dual_map.constrained_var_dual[ci_nneg] == ci

        for i in 1:3
            vi = VI(i)
            @test !haskey(primal_dual_map.primal_var_dual_con, vi)
            @test primal_dual_map.constrained_var_idx[vi] == (ci_nneg, i)
        end
    end

    @testset "conic_linear3_test" begin
        #=
        primal
            min  3x + 2y - 4z + 0s
        s.t.
            x           -  s == -4    :w_1
                y            == -3    :w_2
            x      +  z      == 12    :w_3
            y <= 0
            z >= 0
            s zero

        dual
            max -4w_4 - 3w_5 + 12w_6
        s.t
            w_1 + w_3 == 3
            [-w_2 + 2] in Nonpositives
            [-w_3 - 4] in Nonnegatives
        =#
        primal_model = conic_linear3_test()
        dual_model, primal_dual_map = dual_model_and_map(primal_model)

        @test MOI.get(dual_model, MOI.NumberOfVariables()) == 3
        list_of_cons = MOI.get(dual_model, MOI.ListOfConstraints())
        @test Set(list_of_cons) == Set(
            [
                (VAF{Float64}, MOI.Nonpositives)
                (VAF{Float64}, MOI.Nonnegatives)
                (SAF{Float64}, MOI.EqualTo{Float64})
            ],
        )
        @test MOI.get(
            dual_model,
            MOI.NumberOfConstraints{SAF{Float64},MOI.EqualTo{Float64}}(),
        ) == 1
        @test MOI.get(
            dual_model,
            MOI.NumberOfConstraints{VAF{Float64},MOI.Nonnegatives}(),
        ) == 1
        @test MOI.get(
            dual_model,
            MOI.NumberOfConstraints{VAF{Float64},MOI.Nonpositives}(),
        ) == 1
        obj_type = MOI.get(dual_model, MOI.ObjectiveFunctionType())
        @test obj_type == SAF{Float64}
        @test MOI.get(dual_model, MOI.ObjectiveSense()) == MOI.MAX_SENSE
        obj = MOI.get(dual_model, MOI.ObjectiveFunction{obj_type}())
        @test MOI.constant(obj) == 0.0
        @test Set(MOI.coefficient.(obj.terms)) == Set([-4.0; 12.0; -3.0])

        ci_eq = first(
            MOI.get(
                dual_model,
                MOI.ListOfConstraintIndices{SAF{Float64},MOI.EqualTo{Float64}}(),
            ),
        )
        eq_con1_fun = MOI.get(dual_model, MOI.ConstraintFunction(), ci_eq)
        eq_con1_set = MOI.get(dual_model, MOI.ConstraintSet(), ci_eq)
        @test MOI.coefficient.(eq_con1_fun.terms) == [1.0; 1.0]
        @test MOI.constant.(eq_con1_fun) == 0.0
        @test MOI.constant(eq_con1_set) == 3.0
        ci_np = first(
            MOI.get(
                dual_model,
                MOI.ListOfConstraintIndices{VAF{Float64},MOI.Nonpositives}(),
            ),
        )
        eq_con2_fun = MOI.get(dual_model, MOI.ConstraintFunction(), ci_np)
        @test MOI.get(dual_model, MOI.ConstraintSet(), ci_np) ==
              MOI.Nonpositives(1)
        @test MOI.coefficient.(eq_con2_fun.terms) == -[1.0]
        @test MOI.constant(eq_con2_fun) == [2.0]
        ci_nn = first(
            MOI.get(
                dual_model,
                MOI.ListOfConstraintIndices{VAF{Float64},MOI.Nonnegatives}(),
            ),
        )
        eq_con3_fun = MOI.get(dual_model, MOI.ConstraintFunction(), ci_nn)
        @test MOI.get(dual_model, MOI.ConstraintSet(), ci_nn) ==
              MOI.Nonnegatives(1)
        @test MOI.coefficient.(eq_con3_fun.terms) == -[1.0]
        @test MOI.constant(eq_con3_fun) == [-4.0]

        primal_con_dual_var = primal_dual_map.primal_con_dual_var
        ci_zero = first(
            MOI.get(primal_model, MOI.ListOfConstraintIndices{VVF,MOI.Zeros}()),
        )
        @test !haskey(primal_con_dual_var, ci_zero)
        ci_nneg = first(
            MOI.get(
                primal_model,
                MOI.ListOfConstraintIndices{VVF,MOI.Nonnegatives}(),
            ),
        )
        @test !haskey(primal_con_dual_var, ci_nneg)
        @test primal_dual_map.constrained_var_dual[ci_nneg] == ci_nn
        ci_npos = first(
            MOI.get(
                primal_model,
                MOI.ListOfConstraintIndices{VVF,MOI.Nonpositives}(),
            ),
        )
        @test !haskey(primal_con_dual_var, ci_npos)
        @test primal_dual_map.constrained_var_dual[ci_npos] == ci_np
        ci_aff_zero = first(
            MOI.get(
                primal_model,
                MOI.ListOfConstraintIndices{VAF{Float64},MOI.Zeros}(),
            ),
        )
        @test primal_con_dual_var[ci_aff_zero] == VI.(1:3)

        primal_var_dual_con = primal_dual_map.primal_var_dual_con
        @test primal_var_dual_con[VI(1)] == ci_eq
        for i in 2:4
            vi = VI(i)
            @test !haskey(primal_var_dual_con, vi)
        end
        @test primal_dual_map.constrained_var_idx[VI(2)] == (ci_npos, 1)
        @test primal_dual_map.constrained_var_idx[VI(3)] == (ci_nneg, 1)
        @test primal_dual_map.constrained_var_idx[VI(4)] == (ci_zero, 1)
    end
end


using LinearAlgebra, SparseArrays

export vec2mat, vec2matinv, vec2matadj

"""
    vec2mat(v)
Convert the vector `v` to a symmetric matrix by stacking the entries.

# Examples
```jldoctest
julia> vec2mat([1, 2, 3, 4, 5, 6])
3×3 Array{Int64,2}:
 1  2  4
 2  3  5
 4  5  6
```
"""
function vec2mat(v::SparseVector{Tv,Ti}) where {Tv, Ti}
    (indices, values) = findnz(v)
    sd = Int( 0.5*(sqrt(8*length(v)+1) - 1) )
    mat = spzeros(Tv, sd,sd)
    col = 1
    total = 0
    for i in 1:length(indices)
        idx = indices[i]
        while !(idx in total+1:total+col)
            total += col
            col += 1
        end
        mat[col, idx-total] = values[i]
        mat[idx-total, col] = values[i]
    end
    return mat
end
function vec2mat(v::Array{T,1}) where T
    sd = Int( 0.5*(sqrt(8*length(v)+1) - 1) )
    mat = zeros(T, sd,sd)
    col = 1
    total = 0
    for j = 1:sd
        mat[1:j,j] = v[total+1:total+j]
        mat[j,1:(j-1)] = v[total+1:total+j-1]
        total += j
    end
    return mat
end

"""
    vec2matadj(M)
Convert matrix `M` to a vector such that `dot(vec2matadj(M), u) == dot(M, vec2mat(u))`
for any vector `u`.

# Examples
```jldoctest
julia> M = [1 2; 2 3];

julia> vec2matadj(M)
3-element Array{Int64,1}:
 1
 4
 3

julia> using LinearAlgebra: dot

julia> dot(vec2matadj(M), [0, 1, 0]) == dot(M, vec2mat([0, 1, 0]))
true
```
"""
function vec2matadj(M::Union{SparseMatrixCSC{Tv,Ti}, Array{Tv,2}}) where {Tv, Ti}
    @assert issymmetric(M)
    sd = size(M,1)
    v = typeof(M) <: SparseMatrixCSC ?
    spzeros(Int( 0.5*sd *(sd+1) )) : zeros(Tv, Int( 0.5*sd *(sd+1) ))
    total = 0
    for j in 1:sd
        # Double the off-diagonal entries
        v[total+1:total+j-1] = 2 * M[1:(j-1),j]
        v[total+j] = M[j,j]
        total += j
    end
    return v
end

"""
    vec2matinv(M)
Convert matrix `M` to a vector such that `vec2mat(vec2matinv(M))` equals `M`.

# Examples
```jldoctest
julia> M = vec2mat([1, 2, 3, 4, 5, 6])
3×3 Array{Int64,2}:
 1  2  4
 2  3  5
 4  5  6

julia> vec2matinv(M)
6-element Array{Int64,1}:
 1
 2
 3
 4
 5
 6
```
"""
function vec2matinv(M::Union{SparseMatrixCSC{Tv,Ti}, Array{Tv,2}, Symmetric{Tv,Ti}}) where {Tv, Ti}
    @assert issymmetric(M)
    sd = size(M,1)
    vecsize = sd * (sd+1) ÷ 2
    v = if M isa SparseMatrixCSC spzeros(vecsize)
    elseif M isa Array zeros(Tv, vecsize)
    else Array{Tv,1}(undef, vecsize)
    end
    total = 0
    for j in 1:sd
        v[total+1:total+j] = M[1:j,j]
        total += j
    end
    return v
end


using Base.Test
using LowRankModels

# Check that sparse algorithm converges to the same solution
# from the same initial conditions for simple pca.
m,n,k = 100,100,3
A = randn(m,k)*randn(k,n)
loss = QuadLoss()
r = ZeroReg()

glrm_1 = GLRM(A,loss,r,r,k) # solve with prox algorithm
glrm_2 = deepcopy(glrm_1)   # solve with sparse prox algorithm

X1,Y1,ch1 = fit!(glrm_1,ProxGradParams())
X2,Y2,ch2 = fit!(glrm_2,SparseProxGradParams())

@test_approx_eq X1 X2
@test_approx_eq Y1 Y2

# Check that the sparsity pattern in the data is correctly identified.
A = sprand(m,n,0.5)
I,J = findn(A)

glrm = GLRM(A,loss,r,r,k) # create glrm from sparse matrix

@test length(glrm.observed_features) == m
@test length(glrm.observed_examples) == n

for i = 1:m
	for j = 1:n
		if j in glrm.observed_features[i]
			@test A[i,j] != 0.0
		else
			@test A[i,j] == 0.0
		end
	end
end

for j = 1:n
	for i = 1:m
		if i in glrm.observed_examples[j]
			@test A[i,j] != 0.0
		else
			@test A[i,j] == 0.0
		end
	end
end