"""
    solve(sso::SteadyStateObjective, [method, options, x0]) :: SteadyStateFitResult

Optimize a [`SteadyStateObjective`](@ref) `sso` using Optim.  The rest
of the positional and keyword arguments are passed to
`Optim.optimize`.
"""
function solve(
    sso::SteadyStateObjective,
    method::Optim.AbstractOptimizer = Optim.BFGS(),
    options::Optim.Options = Optim.Options(),
    x0 = get(sso.p, sso.parameterlens);
    kwargs...,
)
    result = Optim.optimize(
        Optim.only_fg!(sso),
        x0,
        method,
        setupoptions(sso, options);
        kwargs...,
    )
    return SteadyStateFitResult(result, sso)
end

"""
    SteadyStateFitResult

# Fields
- `result :: Optim.OptimizationResults`
- `objective :: SteadyStateObjective`

# Methods
- `minimum(fit::SteadyStateFitResult)`: Equivalent to `minimum(fit.result)`.
- `Optim.minimizer(fit::SteadyStateFitResult)`: Return a copy of
  `fit.objective.p` with parameters replaced by `Optim.minimizer(fit.result)`.
"""
struct SteadyStateFitResult
    result  # Optim.MultivariateOptimizationResults
    objective  # SteadyStateObjective
end

function Base.show(io::IO, fit::SteadyStateFitResult)
    maybe_default_show(io, fit) && return
    print(io, "SteadyStateFitResult: ")
    if Optim.converged(fit)
        printstyled(io, "success"; color=:green)
    else
        printstyled(io, "failure"; color=:red)
    end
    print(io, "; ")
    _summarybody(io, fit.objective)
end

function Base.show(io::IO, ::MIME"text/plain", fit::SteadyStateFitResult)
    println(io, "SteadyStateFitResult")
    _showbody(io, fit.objective)
    println(io)
    show(io, MIME("text/plain"), fit.result)
end

function Optim.minimizer(fit::SteadyStateFitResult)
    p = fit.objective.p
    parameterlens = fit.objective.parameterlens
    return set(p, parameterlens, Optim.minimizer(fit.result))
end

# Forward accessor methods to `Optim`.  See:
# https://julianlsolvers.github.io/Optim.jl/stable/#user/minimization/#complete-list-of-functions
for f in [
    :(Base.minimum),
    :(Base.summary),
    # Generic optimization:
    :(Optim.iterations),
    :(Optim.iteration_limit_reached),
    :(Optim.trace),
    :(Optim.x_trace),
    :(Optim.f_trace),
    :(Optim.f_calls),
    :(Optim.converged),
    # Multivariate optimization:
    :(Optim.g_norm_trace),
    :(Optim.g_calls),
    :(Optim.x_converged),
    :(Optim.f_converged),
    :(Optim.g_converged),
    :(Optim.initial_state),
]
    @eval $f(fit::SteadyStateFitResult) = $f(fit.result)
end

"""
    steadystates(fit::SteadyStateFitResult)

Compute steady states with the minimizer.
"""
steadystates(fit::SteadyStateFitResult) =
    steadystates(fit.objective, Optim.minimizer(fit.result))

# A hacky solution: To use the steady state of the last iteration,
# `updatesteadystates!` is called via `callback` option.

function setupoptions(sso::SteadyStateObjective, options::Optim.Options)
    @assert options.show_every == 1
    options = @set options.extended_trace = true
    options = @set options.callback =
        StateUpdater(sso, options.callback, options.store_trace)
    return options
end

struct StateUpdater{T, C}
    sso::T
    callback::C
    store_trace::Bool
end

function (su::StateUpdater)(os)
    if su.store_trace
        # os :: Vector{<:OptimizationState}
        updatesteadystates!(su.sso, os[end].metadata["x"])
    else
        # os :: OptimizationState
        updatesteadystates!(su.sso, os.metadata["x"])
    end
    su.callback === nothing ? false : su.callback(os)
end


import LinearAlgebra

@testset "T" begin
    @testset "termpt" begin
        try
            furnsh(path(CORE, :spk),
                   path(CORE, :pck),
                   path(CORE, :lsk),
                   path(EXTRA, :mars_spk),
                   path(EXTRA, :phobos_dsk))
            et = str2et("1972 AUG 11 00:00:00")
            points, epochs, tangts = termpt("UMBRAL/TANGENT/DSK/UNPRIORITIZED", "SUN",
                                            "PHOBOS", et, "IAU_PHOBOS", "CN+S", "CENTER",
                                            "MARS", [0.0, 0.0, 1.0], 2/3 * π, 3, 1.0e-4,
                                            1.0e-7, 10000)
            @test length(points) == 3
        finally
            kclear()
        end
    end
    @testset "timdef" begin
        try
            furnsh(path(CORE, :lsk))
            # Calendar - default is Gregorian
            value = timdef(:GET, :CALENDAR)
            @test value in ("GREGORIAN", "JULIAN", "MIXED")
            # System - ensure it changes the str2et results
            @test timdef(:GET, :SYSTEM) == "UTC"
            # Approximately 64.184
            et = str2et("2000-01-01T12:00:00")
            # Change to TDB system
            @test timdef(:SET, :SYSTEM, "TDB") == "TDB"
            @test str2et("2000-01-01T12:00:00") == 0.0
            # Change back to UTC system
            @test timdef(:SET, :SYSTEM, "UTC") == "UTC"
            @test str2et("2000-01-01T12:00:00") == et

            # This should throw according to the docs but doesn't
            # @test_throws SpiceError timdef(:TEST, :SYSTEM)

            @test_throws SpiceError timdef(:GET, :TEST)
        finally
            kclear()
        end
    end
    @testset "timout" begin
        try
            furnsh(path(CORE, :lsk))
            sample = "Thu Oct 1 11:11:11 PDT 1111"
            pic = tpictr(sample)
            et = 188745364.0
            out = timout(et, pic)
            @test out == "Sat Dec 24 18:14:59 PDT 2005"
            @test_throws SpiceError timout(et, "")
        finally
            kclear()
        end
    end
    @testset "tipbod" begin
        ref = [0.70041408 0.70486133 -0.11220794;
            -0.70859907 0.70555446 0.00895915;
            0.08548377 0.07323533 0.99364436]
        try
            furnsh(path(CORE, :lsk), path(CORE, :pck))
            et = str2et("Jan 1 2005")
            tipm = tipbod("J2000", 699, et)
            @testset for i in eachindex(ref, tipm)
                @test tipm[i] ≈ ref[i] atol=1e-8
            end
        finally
            kclear()
        end
    end
    @testset "tisbod" begin
        ref = [
            0.70041408 0.70486133 -0.11220794 0.00000000E+00 0.00000000E+00 0.00000000E+00;
            -0.70859907 0.70555446 0.00895915 0.00000000E+00 0.00000000E+00 0.00000000E+00;
            0.08548377 0.07323533 0.99364436 0.00000000E+00 0.00000000E+00 0.00000000E+00;
            -0.00011606 0.00011556 1.46737366E-06 0.70041408 0.70486133 -0.11220794;
            -0.00011472 -0.00011545 1.83779762E-05 -0.70859907 0.70555446 0.00895915;
            3.12746980E-14 -2.71850372E-15 -2.49021541E-15 0.08548377 0.07323533 0.99364436;
        ]
        try
            furnsh(path(CORE, :lsk), path(CORE, :pck))
            et = str2et("Jan 1 2005")
            tsipm = tisbod("J2000", 699, et)
            @testset for i in eachindex(ref, tsipm)
                @test tsipm[i] ≈ ref[i] atol=1e-8
            end
        finally
            kclear()
        end
    end
    @testset "tkvrsn" begin
        @test tkvrsn() == "CSPICE_N0066"
    end
    @testset "tparse" begin
        actual1 = tparse("1996-12-18T12:28:28")
        @test actual1 == -95815892.0
        actual2 = tparse("1 DEC 1997 12:28:29.192")
        @test actual2 == -65748690.808
        actual3 = tparse("1997-162::12:18:28.827")
        @test actual3 == -80696491.173
        @test_throws SpiceError tparse("test")
    end
    @testset "tpictr" begin
        test_string = "10:23 P.M. PDT January 3, 1993"
        pictur = tpictr(test_string)
        @test pictur == "AP:MN AMPM PDT Month DD, YYYY ::UTC-7"
        @test_throws SpiceError tpictr("test")
    end
    @testset "trace" begin
        a = randn(3, 3)
        @test SPICE._trace(a) ≈ LinearAlgebra.tr(a)
    end
    @testset "tsetyr" begin
        # Expand 2-digit year to full year, typically 4-digit
        tmp_getyr4 = (iy2) -> parse(Int,
            split(etcal(tparse("3/3/$(lpad(iy2, 2, string(0)))")))[1])
        # Find current lower bound on the 100 year interval of expansion,
        # so it can be restored on exit
        tsetyr_lowerbound = tmp_getyr4(0)
        for iy2_test in 0:99
            tmp_lowerbound =  tmp_getyr4(iy2_test)
            if tmp_lowerbound < tsetyr_lowerbound
                tsetyr_lowerbound = tmp_lowerbound
                break
            end
        end
        # Run first case with a year not ending in 00
        tsetyr_y2 = tsetyr_lowerbound % 100
        tsetyr_y4 = tsetyr_lowerbound + 200 + ((tsetyr_y2 == 0) && 50 || 0)
        tsetyr(tsetyr_y4)
        @test tmp_getyr4(tsetyr_y4 % 100) == tsetyr_y4
        @test tmp_getyr4((tsetyr_y4-1) % 100) == (tsetyr_y4+99)
        # Run second case with a year ending in 00
        tsetyr_y4 -= (tsetyr_y4 % 100)
        tsetyr(tsetyr_y4)
        @test tmp_getyr4(tsetyr_y4 % 100) == tsetyr_y4
        @test tmp_getyr4((tsetyr_y4-1) % 100) == (tsetyr_y4+99)
        # Cleanup:  reset lowerbound to what it was when this routine started
        tsetyr_y4 = tsetyr_lowerbound
        tsetyr(tsetyr_y4)
        @test tmp_getyr4(tsetyr_y4 % 100) == tsetyr_y4
        @test tmp_getyr4((tsetyr_y4-1) % 100) == (tsetyr_y4+99)
    end
    @testset "twopi" begin
        @test SPICE._twopi() ≈ 2π
    end
    @testset "twovec" begin
        axdef = [1.0, 0.0, 0.0]
        plndef = [0.0, -1.0, 0.0]
        expected = [1.0 0.0 0.0; 0.0 -1.0 0.0; 0.0 0.0 -1.0]
        @test twovec(axdef, 1, plndef, 2) ≈ expected
        @test_throws ArgumentError twovec(axdef[1:2], 1, plndef, 2)
        @test_throws ArgumentError twovec(axdef, 1, plndef[1:2], 2)
        @test_throws SpiceError twovec(axdef, 1, plndef, 1)
        @test_throws SpiceError twovec(axdef, 1, plndef, 4)
        @test_throws SpiceError twovec(axdef, 1, axdef, 2)
    end
    @testset "tyear" begin
        @test tyear() == 3.15569259747e7
    end
end


module TestExamplesP4estMesh3D

using Test
using Trixi

include("test_trixi.jl")

EXAMPLES_DIR = joinpath(examples_dir(), "p4est_3d_dgsem")

# Start with a clean environment: remove Trixi output directory if it exists
outdir = "out"
isdir(outdir) && rm(outdir, recursive=true)

@testset "P4estMesh3D" begin
  @trixi_testset "elixir_advection_basic.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_basic.jl"),
      # Expected errors are exactly the same as with TreeMesh!
      l2   = [0.00016263963870641478],
      linf = [0.0014537194925779984])
  end

  @trixi_testset "elixir_advection_unstructured_curved.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_unstructured_curved.jl"),
      l2   = [0.0004750004258546538],
      linf = [0.026527551737137167])
  end

  @trixi_testset "elixir_advection_nonconforming.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_nonconforming.jl"),
      l2   = [0.00253595715323843],
      linf = [0.016486952252155795])
  end

  @trixi_testset "elixir_advection_amr.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr.jl"),
      # Expected errors are exactly the same as with TreeMesh!
      l2   = [9.773852895157622e-6],
      linf = [0.0005853874124926162])
  end

  @trixi_testset "elixir_advection_amr_unstructured_curved.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_amr_unstructured_curved.jl"),
      l2   = [1.6236411810065552e-5],
      linf = [0.0010554006923731395],
      tspan = (0.0, 1.0))
  end

  @trixi_testset "elixir_advection_cubed_sphere.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_cubed_sphere.jl"),
      l2   = [0.002006918015656413],
      linf = [0.027655117058380085])
  end

  @trixi_testset "elixir_advection_restart.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"),
      l2   = [0.002590388934758452],
      linf = [0.01840757696885409])
  end

  @trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_curved.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonconforming_unstructured_curved.jl"),
      l2   = [4.070355207909268e-5, 4.4993257426833716e-5, 5.10588457841744e-5, 5.102840924036687e-5, 0.00019986264001630542],
      linf = [0.0016987332417202072, 0.003622956808262634, 0.002029576258317789, 0.0024206977281964193, 0.008526972236273522],
      tspan = (0.0, 0.01))
  end

  @trixi_testset "elixir_euler_source_terms_nonperiodic.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_source_terms_nonperiodic.jl"),
      l2   = [0.0015106060984283647, 0.0014733349038567685, 0.00147333490385685, 0.001473334903856929, 0.0028149479453087093],
      linf = [0.008070806335238156, 0.009007245083113125, 0.009007245083121784, 0.009007245083102688, 0.01562861968368434],
      tspan = (0.0, 1.0))
  end

  @trixi_testset "elixir_euler_free_stream.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream.jl"),
      l2   = [5.162664597942288e-15, 1.941857343642486e-14, 2.0232366394187278e-14, 2.3381518645408552e-14, 7.083114561232324e-14],
      linf = [7.269740365245525e-13, 3.289868377720495e-12, 4.440087186807773e-12, 3.8686831516088205e-12, 9.412914891981927e-12],
      tspan = (0.0, 0.03))
  end

  @trixi_testset "elixir_euler_free_stream_extruded.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_free_stream_extruded.jl"),
      l2   = [8.444868392439035e-16, 4.889826056731442e-15, 2.2921260987087585e-15, 4.268460455702414e-15, 1.1356712092620279e-14],
      linf = [7.749356711883593e-14, 2.8792246364872653e-13, 1.1121659149182506e-13, 3.3228975127030935e-13, 9.592326932761353e-13],
      tspan=(0.0, 0.1))
  end

  @trixi_testset "elixir_euler_ec.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_ec.jl"),
      l2   = [0.010380390326164493, 0.006192950051354618, 0.005970674274073704, 0.005965831290564327, 0.02628875593094754],
      linf = [0.3326911600075694, 0.2824952141320467, 0.41401037398065543, 0.45574161423218573, 0.8099577682187109],
      tspan = (0.0, 0.2))
  end

  @trixi_testset "elixir_euler_sedov.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_sedov.jl"),
      l2   = [7.82070951e-02, 4.33260474e-02, 4.33260474e-02, 4.33260474e-02, 3.75260911e-01],
      linf = [7.45329845e-01, 3.21754792e-01, 3.21754792e-01, 3.21754792e-01, 4.76151527e+00],
      tspan = (0.0, 0.3))
  end

  @trixi_testset "elixir_mhd_alfven_wave_nonconforming.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_alfven_wave_nonconforming.jl"),
      l2   = [0.00019018725889431733, 0.0006523517707148006, 0.0002401595437705759, 0.0007796920661427565,
              0.0007095787460334334, 0.0006558819731628876, 0.0003565026134076906, 0.0007904654548841712,
              9.437300326448332e-7],
      linf = [0.0012482306861187897, 0.006408776208178299, 0.0016845452099629663, 0.0068711236542984555,
              0.004626581522263695, 0.006614624811393632, 0.0030068344747734566, 0.008277825749754025,
              1.3475027166309006e-5],
      tspan = (0.0, 0.25))
  end

  @trixi_testset "elixir_mhd_shockcapturing_amr.jl" begin
    @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhd_shockcapturing_amr.jl"),
      l2   = [0.006298541670176575, 0.0064368506652601265, 0.007108729762852636, 0.006530420607206385,
              0.02061185869237284, 0.005562033787605515, 0.007571716276627825, 0.005571862660453231,
              3.909755063709152e-6],
      linf = [0.20904054009050665, 0.18622917151105936, 0.2347957890323218, 0.19432508025509926,
              0.6858860133405615, 0.15172116633332622, 0.22432820727833747, 0.16805989780225183,
              0.000535219040687628],
      tspan = (0.0, 0.04))
  end
end

# Clean up afterwards: delete Trixi output directory
@test_nowarn rm(outdir, recursive=true)

end # module


"""
collecting all needed  functions required to calculate Housdorff distance
"""
module Housdorff
using CUDA
using ..CUDAGpuUtils ,..IterationUtils,..ReductionUtils , ..MemoryUtils,..CUDAAtomicUtils
using ..BitWiseUtils,..MetadataAnalyzePass,..MetaDataUtils,..WorkQueueUtils,..ProcessMainDataVerB,..HFUtils,..ResultListUtils,..PrepareArrtoBool, ..MainLoopKernel,..ScanForDuplicates
export get_shmemMainKernel, getHousedorffDistance,boolKernelLoad,mainKernelLoad,get_shmemMainKernel,get_shmemBoolKernel,preparehousedorfKernel
"""
calculate housedorff distance of given arrays with given robustness percentage

"""
function getHousedorffDistance(goldGPUa,segmGPUa,boolKernelArgs,mainKernelArgs,threadsBoolKern,blocksBoolKern ,threadsMainKern,blocksMainKern,shmemSizeBool,shmemSizeMain)
    # boolKernelArgs[1]= goldGPU
    # boolKernelArgs[2]= segmGPU
    mainArrDims,dataBdim,metaData,metaDataDims,reducedGoldA,reducedSegmA,loopXinPlane,loopYinPlane,minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp ,numberToLooFor,inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength = boolKernelArgs

    @cuda threads=threadsBoolKern blocks=blocksBoolKern shmem=shmemSizeBool  cooperative=true boolKernelLoad(goldGPUa,segmGPUa,boolKernelArgs...)
    #now time to get data structures dependent on bool kernel like for example loading subsections of meta data, creating work queue ...
    #some arrays needs to be instantiated only after we know the number of the false and true positives
    metaData,reducedGoldA  ,reducedSegmA ,paddingStore,resList,workQueue,workQueueCounter= getBigGPUForHousedorffAfterBoolKernel(metaData,minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp,reducedGoldA,reducedSegmA,dataBdim)
    referenceArrs,dilatationArrs, mainArrDims,dataBdim,numberToLooFor,metaDataDims,metaData,iterThrougWarNumb,robustnessPercent,shmemSumLengthMaxDiv4,globalFpResOffsetCounter,globalFnResOffsetCounter    ,globalIterationNumber,globalCurrentFnCount,globalCurrentFpCount    ,globalIterationNumb,workQueue,workQueueCounter,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed    ,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop    ,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength, fn,fp,resList,inBlockLoopXZIterWithPadding,paddingStore,shmemblockDataLenght,shmemblockDataLoop= mainKernelArgs

    dilatationArrs= (reducedGoldA,reducedSegmA)
    #reverse order as when dilatating gold we want to establish do we cover segm voxels
    referenceArrs=(segmGPUa,goldGPUa )

    #main calculations
    @cuda threads=threadsMainKern blocks=blocksMainKern shmem=shmemSizeMain cooperative=true mainKernelLoadB( referenceArrs,dilatationArrs, mainArrDims,dataBdim
    ,numberToLooFor,metaDataDims,metaData,iterThrougWarNumb,robustnessPercent
    ,shmemSumLengthMaxDiv4,globalFpResOffsetCounter,globalFnResOffsetCounter
    ,globalIterationNumber,globalCurrentFnCount,globalCurrentFpCount
    ,globalIterationNumb,workQueue,workQueueCounter
    ,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed
    ,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY
    ,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop
    ,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength, fn,fp,resList,inBlockLoopXZIterWithPadding,paddingStore,shmemblockDataLenght,shmemblockDataLoop)
        #@cuda threads=threadsMainKern blocks=blocksMainKern shmem=shmemSizeMain cooperative=true mainKernelLoad(dilatationArrs,referenceArrs, mainArrDims,dataBdim,numberToLooFor,metaDataDims,metaData,iterThrougWarNumb,robustnessPercent,shmemSumLengthMaxDiv4,globalFpResOffsetCounter,globalFnResOffsetCounter,globalIterationNumber,globalCurrentFnCount,globalCurrentFpCount,globalIterationNumb,workQueaue,resList,resListIndicies,maxResListIndex,inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength, fn,fp)
    return globalIterationNumb

    end

"""
clearing data before next execution
"""
function housClearForExecution()

end

"""
for invoking getBoolCubeKernel
"""
function boolKernelLoad(goldGPU,segmGPU,mainArrDims,dataBdim,metaData,metaDataDims,reducedGoldA,reducedSegmA,loopXinPlane,loopYinPlane,minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp ,numberToLooFor,inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength)
    @getBoolCubeKernel()
    return
end
"""
main function responsible for calculations of Housedorff distance
"""
function mainKernelLoadB(referenceArrs,dilatationArrs, mainArrDims,dataBdim
    ,numberToLooFor,metaDataDims,metaData,iterThrougWarNumb,robustnessPercent
    ,shmemSumLengthMaxDiv4,globalFpResOffsetCounter,globalFnResOffsetCounter
    ,globalIterationNumber,globalCurrentFnCount,globalCurrentFpCount
    ,globalIterationNumb,workQueue,workQueueCounter
    ,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed
    ,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY
    ,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop
    ,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength, fn,fp,resList,inBlockLoopXZIterWithPadding,paddingStore,shmemblockDataLenght,shmemblockDataLoop)

   #@mainLoopKernel()
    return
end

function mainKernelLoad(referenceArrs,dilatationArrs, mainArrDims,dataBdim
    ,numberToLooFor,metaDataDims,metaData,iterThrougWarNumb,robustnessPercent
    ,shmemSumLengthMaxDiv4,globalFpResOffsetCounter,globalFnResOffsetCounter
    ,globalIterationNumber,globalCurrentFnCount,globalCurrentFpCount
    ,globalIterationNumb,workQueue,workQueueCounter
    ,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed
    ,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY
    ,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop
    ,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength, fn,fp,resList,inBlockLoopXZIterWithPadding,paddingStore,shmemblockDataLenght,shmemblockDataLoop)
    @mainLoopKernel()
    return
end

function get_shmemMainKernel(dataBdim)

    shmemblockData= sizeof(UInt32)*32*32
    # shmemblockData= sizeof(UInt32)*dataBdim[1]* dataBdim[2]
    resShmemblockData= sizeof(UInt32)*32*32
    # resShmemblockData= sizeof(UInt32)*dataBdim[1]* dataBdim[2]
    shmemPaddings= sizeof(Bool)*(  max(dataBdim[1], dataBdim[2]))*(  max(dataBdim[1], dataBdim[2]))*6
    shmemSum= sizeof(UInt32)*36*16
    areToBeValidated= sizeof(Bool)*14
    isAnythingInPadding= sizeof(Bool)*7
    alreadyCoveredInQueues= sizeof(UInt32)*14
    someBools = sizeof(Bool)*4
    someInt16 = sizeof(UInt16)*6
    workCountersInshmem = sizeof(UInt16)*2
return workCountersInshmem+shmemSum+areToBeValidated+isAnythingInPadding+alreadyCoveredInQueues+someBools+shmemblockData+someInt16+resShmemblockData+shmemPaddings
end

function get_shmemBoolKernel(dataBdim)
    # shmemSum= sizeof(Float32)*32*2
    shmemblockData= sizeof(Int32)*(dataBdim[1])*(dataBdim[2])
    localQuesValues = sizeof(UInt32)*14
    minMaxes = sizeof(Float32)*6
return minMaxes+localQuesValues+shmemblockData
end

"""
creates required cu arrays , calculates some kernel constants and uses occupancy API
to calculate optimal number of threads and blocks to run a kernel
robustnessPercent - frequently we do not want to analyze all of the fap and fn in order to reduce the impact of the outliers
numberToLooFor - what we will look for in main arrays
"""
function preparehousedorfKernel(goldGPU,segmGPU,robustnessPercent,numberToLooFor)
    mainArrDims = size(goldGPU)
    dataBdim = (32,32,32) # will be modified after number of threads gets calculated by occupancy API

    metaData = MetaDataUtils.allocateMetadata(mainArrDims,dataBdim);
    metaDataDims= size(metaData);
    #for bool cube kernel
    threadsBoolKern= (30,32); blocksBoolKern = 10#just some dummy will be modified after invoking occupancy API
    #for main kernel
    threadsMainKern= (30,32); blocksMainKern = 10#just some dummy will be modified after invoking occupancy API
    iterThrougWarNumb = cld(14,threadsMainKern[2])

    inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength=calculateLoopsIter(dataBdim,threadsBoolKern[1],threadsBoolKern[2],metaDataDims,blocksBoolKern)
        minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp  =getSmallForBoolKernel();
        reducedGoldA,reducedSegmA=  getLargeForBoolKernel(mainArrDims,dataBdim);

    loopXinPlane,loopYinPlane = 1,1
    boolKernelArgs = (mainArrDims,dataBdim,metaData,metaDataDims,reducedGoldA,reducedSegmA,loopXinPlane,loopYinPlane,minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp ,numberToLooFor,inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength)
    #needed also in bool kernel

    #### main kernel
    fpLoc = 10
    fnLoc = 10
    resList= allocateResultLists(fpLoc,fnLoc)
    globalFpResOffsetCounter,globalFnResOffsetCounter,globalIterationNumber,globalCurrentFnCount,globalCurrentFpCount,globalIterationNumb= getSmallGPUForHousedorff()

    referenceArrs=(goldGPU,segmGPU)

    inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength=calculateLoopsIter(dataBdim,threadsBoolKern[1],threadsBoolKern[2],metaDataDims,blocksBoolKern)
    shmemSumLengthMaxDiv4= fld((36*14),4)*4 # subject to futre changes

    metaData,reducedGoldA  ,reducedSegmA ,paddingStore,resList,workQueue,workQueueCounter = getBigGPUForHousedorffAfterBoolKernel(metaData,minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp,reducedGoldA,reducedSegmA,dataBdim)

    reducedGoldA,reducedSegmA=  getLargeForBoolKernel(mainArrDims,dataBdim);

    dilatationArrs= (reducedGoldA,reducedSegmA)

    mainKernelArgs= (referenceArrs,dilatationArrs, mainArrDims,dataBdim
    ,numberToLooFor,metaDataDims,metaData,iterThrougWarNumb,robustnessPercent
    ,shmemSumLengthMaxDiv4,globalFpResOffsetCounter,globalFnResOffsetCounter
    ,globalIterationNumber,globalCurrentFnCount,globalCurrentFpCount
    ,globalIterationNumb,workQueue,workQueueCounter
    ,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed
    ,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY
    ,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop
    ,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength, fn,fp,resList,inBlockLoopXZIterWithPadding,paddingStore,shmemblockDataLenght,shmemblockDataLoop)

    function get_shmemMainKernelLoc(threads)
        dataBdim = (threads[1],threads[2],32)
        get_shmemMainKernel(dataBdim)
    end

    threadsMainKern,blocksMainKern = getThreadsAndBlocksNumbForKernel(get_shmemMainKernel,mainKernelLoad,(mainKernelArgs))
    function get_shmemBoolKernelLoc(threads)
        dataBdim = (threadsMainKern[1],threadsMainKern[2],32)
        get_shmemBoolKernel(dataBdim)
    end

    boolKernelArgs = (mainArrDims,dataBdim,metaData,metaDataDims,reducedGoldA,reducedSegmA,loopXinPlane,loopYinPlane,minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp ,numberToLooFor,inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength)

     ## now we need to make use of occupancy API to get optimal number of threads and blocks fo each kernel
    threadsBoolKern,blocksBoolKern = getThreadsAndBlocksNumbForKernel(get_shmemBoolKernelLoc,boolKernelLoad,(goldGPU,segmGPU,boolKernelArgs...))

    loopXinPlane,loopYinPlane = fld(threadsMainKern[1],threadsBoolKern[1] ), fld(threadsMainKern[2],threadsBoolKern[2] )
#now we get defoult values of data b dim  set on the basis of the threadsMainHKernel; and generally recalculating loops constants
    dataBdim = (threadsMainKern[1],threadsMainKern[2],32)
    metaData = MetaDataUtils.allocateMetadata(mainArrDims,dataBdim);
    metaDataDims= size(metaData);
    iterThrougWarNumb = cld(14,threadsMainKern[2])

    boolKernelArgs = (mainArrDims,dataBdim,metaData,metaDataDims,reducedGoldA,reducedSegmA,loopXinPlane,loopYinPlane,minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp ,numberToLooFor,inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength)

    inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength=calculateLoopsIter(dataBdim,threadsBoolKern[1],threadsBoolKern[2],metaDataDims,blocksBoolKern)

    boolKernelArgs = (mainArrDims,dataBdim,metaData,metaDataDims,reducedGoldA,reducedSegmA,loopXinPlane,loopYinPlane,minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp ,numberToLooFor,inBlockLoopXZIterWithPadding,shmemblockDataLoop,shmemblockDataLenght,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength)
    metaData,reducedGoldA  ,reducedSegmA ,paddingStore,resList,workQueue,workQueueCounter= getBigGPUForHousedorffAfterBoolKernel(metaData,minxRes,maxxRes,minyRes,maxyRes,minzRes,maxzRes,fn,fp,reducedGoldA,reducedSegmA,dataBdim)

    reducedGoldA,reducedSegmA=  getLargeForBoolKernel(mainArrDims,dataBdim);

    mainKernelArgs= (referenceArrs,dilatationArrs, mainArrDims,dataBdim
    ,numberToLooFor,metaDataDims,metaData,iterThrougWarNumb,robustnessPercent
    ,shmemSumLengthMaxDiv4,globalFpResOffsetCounter,globalFnResOffsetCounter
    ,globalIterationNumber,globalCurrentFnCount,globalCurrentFpCount
    ,globalIterationNumb,workQueue,workQueueCounter
    ,loopAXFixed,loopBXfixed,loopAYFixed,loopBYfixed,loopAZFixed,loopBZfixed
    ,loopdataDimMainX,loopdataDimMainY,loopdataDimMainZ,inBlockLoopX,inBlockLoopY
    ,inBlockLoopZ,metaDataLength,loopMeta,loopWarpMeta,clearIterResShmemLoop
    ,clearIterSourceShmemLoop,resShmemTotalLength,sourceShmemTotalLength, fn,fp,resList,inBlockLoopXZIterWithPadding,paddingStore,shmemblockDataLenght,shmemblockDataLoop)
    shmemSizeBool=get_shmemBoolKernelLoc(threadsBoolKern)
    shmemSizeMain=get_shmemMainKernelLoc(threadsMainKern)

    # CUDA.unsafe_free!(goldGPU)
    # CUDA.unsafe_free!(segmGPU)
    #CUDA.reclaim()
return (boolKernelArgs, mainKernelArgs,threadsBoolKern,blocksBoolKern ,threadsMainKern,blocksMainKern ,shmemSizeBool,shmemSizeMain)

end

end# module


# using Lar
using SparseArrays

#=== GEOMETRY ===#
casa = Lar.Model([
	-2.4597565 -2.4522173 -0.5671277 -0.5006746 -0.1162969 -0.0411648 -1.6065569 -1.538553 0.5220077 0.425385 -2.4566889 -2.4327611 2.5407924 2.6519575 2.1569667 2.0238272 -0.894649 -0.8185376 -2.4668106 0.5897599 0.5219602 -2.5230682 -2.5963977 -0.3287384 -2.2379807 -2.3812557 -2.4523731 -2.4583376 -2.4506559 -2.4624104 -2.4565361 0.0682781 0.063364 0.0736117 1.7383648 1.6803876 0.0641146 2.6845417 2.6794123 2.6847454 -1.291334 -1.3641939 2.683177 0.0714553 0.0726213 -0.970352 -1.084115 2.4465407 0.0499117 0.0755465 -0.0171626 0.1698998 2.3119033 2.3146026 0.0675813 0.0750238 -2.2785281 -2.2093537 2.6702801 2.6750389 -1.1911889 2.3117217 2.3011701 1.9283984 2.100243 2.2618915 2.3525084 -1.0223487 2.6818127 2.7088002 2.7279705 2.7330924 0.9731528 1.1525246 1.5631746 2.7081553 2.7207837 -2.5788434 -2.5269253 -2.4731252 -1.821651 -1.7123963 2.7594761 2.7571373 -0.0947099 -0.1485818 -2.4511418 0.072852 -0.1620383 -0.1662685 0.8595433 0.7588224 -2.4588392 -2.452629 2.1566859 1.3332641 1.4510288 2.7504926 0.0774187 -0.2340476 -2.1634959 -0.9132363 -2.4641121 0.3490488 0.6262756 1.8654597 1.7936748 1.0015132 0.9402439 0.0702856 -1.1127833 -1.3501558 -2.4625144 -2.5212469 2.2929953 2.313716 -1.8574036 -1.7264204 -2.0617478 2.2823501 2.2737555 -0.7543049 2.3116562 2.7110918 2.7164272 0.92606 0.801297 1.7932344 1.506639 1.3434536 2.6838242 0.0713831 0.0723581 2.469077 1.5491556 1.7167967 -2.0654657 -0.4624259 -0.5369107 2.3129304 2.3129603 0.058069 0.0587657 2.3170069 2.3192346 -1.4246313 1.2255454 0.0661538 0.0775579 1.2504264 -0.0508638 0.0761935 1.1196212 -0.1501275 0.7450013 -2.4577283 -2.4585812 2.3172282 1.9084504 0.3660852 -2.3497349 0.6823004 2.2582174 2.7682638 2.7647983 0.0671101 -2.4181523 -2.4545437 -1.4313996 2.5843276 2.3143028 -0.3356507 -2.4556546 2.317352 -0.0073131 -1.6494431 -1.8938893 2.7370805 -2.006383 2.7437875 -0.7995016 0.209298 0.1491918 -0.6867198 -1.7435649 -1.6852676 -2.3560753 -2.2940905 -2.1835872 -2.3065283 -0.9389482 -0.6578962 -0.9247664 -1.1098947 -2.9472717 -2.7753367 -1.8544405 -3.1510798 -3.1992528 -4.7309064 -4.5890579 -4.2111635 -4.3234671 -0.2845128 -0.1094404 -2.6308679 -2.7158101 -3.0090251 -3.0490859 -0.296038 -4.3905647 -4.2485043 -1.049826 -1.24665 0.2963348 0.5193222 -2.1860743 0.6402265 0.6810601 -1.5557214 -1.7228437 -0.4970008 -0.4962014 0.5744369 0.5233759 0.0854987 0.1984824 -3.9852406 -3.9361804 -0.9379879 -0.9979447 -2.0020245 -0.0172744 -3.5342162 -3.5931719 -0.8289806 -4.4711829 -4.4363744 -2.0110464 -1.835957 -3.4261627 -3.5043042 -3.6461062 -3.7054107 0.0844048 -4.5643017 -4.6091353 -0.618908 -2.744999 -2.8170587 -1.0538115 -3.3073639 -3.2443271 -0.9368517 -1.7035089 -1.9155018 -2.5574476 -2.062185 -1.9592845 -0.3693283 -0.6267654 -0.7878155 -0.4869925 -0.5240197 -0.3780919 -2.1959351 -2.2889439 -2.5571048 -4.3774894 -2.904005 -2.8588801 -0.9338782 -1.076003 -1.162096 0.631892 0.7301973 -0.7484179 -0.8602121 -2.4048824 -1.4974084 -1.6112392 -4.0387079 0.257541 -2.6754072 -4.5222411 -0.9858613 -1.485821 -3.6718217 -3.4742656 -4.6630908 -1.3353008 -1.2772183 -1.5018219 -1.4358349 -0.02953 -0.2555202 -2.9671287 -1.1087682 -2.4639265 -3.9027765 -3.800463 -3.1111456 -1.9506761 -0.5649958 -0.9449505 -1.4260742 -3.875387 -1.8217333 -1.3488349 -1.40887 0.433554 -3.3442485 0.7711486 -1.2387963 -1.5276395 -1.3845939 -2.0950038 -0.4060411 -1.2868788 -4.0441791 -4.1631913 -4.0980637 -0.6189779 -3.7674224 -3.8213713 -2.302362 -2.4111075 -0.6719471 -3.2632786 0.1143499 0.1587926 2.3273379 2.4422443 1.2135167 1.3124028 0.1648119 0.1576137 0.1703019 0.1310771 0.1611757 0.1691751 0.1600217 1.7792455 1.6963646 2.5723669 2.688466 2.6776584 2.5607561 0.9859014 1.1252119 0.1394538 0.1626795 0.8690058 0.1603461 0.1743647 0.1628319 2.1188063 2.235698 1.4745653 1.442926 0.7673111 0.1471046 0.1495127 1.4390668 1.3301793 2.4554814 1.097406 0.9993168 2.0891203 1.9934332 0.1490009 -0.046728 0.8255584 0.6246198 0.3996017 2.3445886 0.1640362 0.312557 0.1879842 2.0002929 0.1579382 0.1346884 0.1550794 1.542232 0.651629 0.142315 2.2132318 1.5567542 0.1724124 0.1438429 1.6728018 1.7805323 0.4262432 0.5383357 0.5033218 -0.1744205 1.8882255 0.4785966 0.1916377 -1.0122844 -0.9352273 -0.1413375 -0.2582962 1.660591 1.471577 1.9177234 2.0018243 1.328469 0.6444978 0.5604974 0.9787573 0.9796913 0.3824948 0.189364 0.7638461 0.637685 0.271648 0.3406026 -1.0401907 -0.9512283 -0.3682892 -0.3914369 -0.1995503 0.1838124 0.1327996 -0.5921586 -0.6352363 0.8097449 1.3848885 1.2949135 -0.607214 -0.5111724 1.6627397 1.7627341 1.0720423 0.7625474 0.7903823 -0.7122493 0.532766 0.4016217 -0.1591777 -0.0941649 0.3308101 0.2507908 -0.7053311 -0.8393037 1.8247261 0.4234877 0.6346095 0.7207471 -0.4401726 0.3806168 0.876491 0.7535417 0.1354005 0.0625079 0.6874856 0.3496197 0.5346226 -0.9922307 -0.367184 -0.2561859 0.0648211 0.4600837 0.5096916 2.0951764 1.7749575 1.1959506 -0.8621934 -0.8062771 -0.9412482 -0.0342302 -0.1412556 -0.4882604 -0.7782143 1.1439167 -0.0301753 -0.0012229 0.239732 -0.5474115 -0.396455 0.5356301 -0.630308 -0.6163954 -0.5404067 2.1800804 2.2251153 -0.5993244 1.5898758 1.5397638 0.5788086 0.9854526 0.3097623 1.2166146 -0.4794293 -0.0304497 -0.71231 -0.1525464 -0.4882474 -0.396141 0.6507089 -0.2862765 -0.3462454 -2.7147652 -2.6946949 1.7539594 1.6758598 -2.1883186 -2.2962534 -0.881357 -0.9429303 -1.5366758 -1.2743781 -2.4695132 -2.1787136 -0.0429226 0.0980476 0.0872128 0.1529189 -1.941774 -1.7313693 -2.5979749 -2.5062287 -2.3543208 -0.427828 1.3411393 1.2452214 -1.736128 -1.9021365 -1.0092025 -1.0587285 -1.8294893 -1.8900925 -0.1931212 -0.0399155 -1.6201954 -1.6787789 1.470155 1.7300184 1.0945133 2.3307668 2.3623777 2.2275895 2.3609573 -0.9287708 -2.0766619 2.4413944 2.6581103 -2.5874174 -2.6495893 -2.1979871 1.8857118 -2.8085839 -2.737767 -2.4373102 -0.5136769 -0.5763745 -1.9625276 -2.0720709 2.0307703 2.1577242 -2.1249224 -1.5802767 -1.8721185 2.4963959 -2.3536625 -2.4375506 1.0160102 0.8058139 -1.3448934 -1.2816532 -1.4218698 -1.3462921 0.7777807 0.9570027 -1.5410764 -1.4781689 -2.7287792 -2.6025666 0.3368114 0.3046273 -2.5268504 -3.0088951 -0.8295693 -2.286753 -2.120103 1.5377054 0.5456719 0.3005769 -0.7186781 -0.6271248 0.4867014 0.5783237 1.3542623 1.2213143 2.1116196 0.257387 0.1973929 -1.4201104 -1.2199339 -3.1195863 -1.7267037 -1.5531667 -2.7468093 0.4043509 0.7541284 -1.2108083 -0.6584753 -0.2590054 1.4678986 1.8477321 -2.0279227 -1.1607171 0.6381507 0.5445623 1.1807952 1.1813699 -2.3317319 -2.3456335 0.3503587 0.3017998 -0.0315044 -0.1489301 -2.3159777 0.8774947 1.1066022 -2.3434927 -2.3580487 -2.3098424 -2.3200008 -1.7935329 -1.90693 -2.3756106 -2.3185826 -2.2986025 -2.3051636 -1.9597072 -1.8039317 0.7524481 -0.4892793 -0.6032115 -0.5276545 -0.727261 1.1825183 1.0877424 -2.2875771 -2.2078029 1.5488468 1.4347128 1.1813921 1.1799559 1.1838788 1.1833603 -1.4531394 -1.3097153 -2.3357551 0.0855461 -1.4861962 -1.3746905 0.9887741 0.8521005 0.4129411 -0.2706968 -2.3341311 -0.7186921 -1.0244886 -1.2598465 -1.1679096 -0.1484432 0.2640911 0.1035077 -1.6045659 1.2308647 -0.8026081 1.1097685 1.1024068 -0.9110273 1.1807012 0.4927203 0.5776652 -2.3342174 -2.2182197 -2.1196549 -0.2751949 -2.3239727 0.4266989 0.2045828 -2.3714302 1.4354188 1.182306 -2.3492788 -2.308217 -0.0218118 0.7053725 -1.030478 0.7579513 -2.1106279 2.2309939 2.2017274 0.4239018 0.6550594 0.1925629 0.1689803 2.2172925 2.2257534 0.4388352 0.3198072 2.2199855 2.2059499 2.1027678 1.7583085 0.8774099 0.7633448 2.2384413 2.2308196 0.1952869 0.2570046 0.1507253 0.2660596 1.5556156 1.4035264 1.6519302 0.9880018 0.180747 0.1722834 0.2788743 2.2222405 2.2349673 2.2145517 1.1005371 0.8773533 0.5493061 1.303635 0.661103 1.1029861 1.3113812 1.3349889 1.539713 0.2747844 0.2976342 1.9888282 1.8702565 2.2364951 2.2328732 2.2324932 2.2273987 0.2807904 1.7697071 0.2667216 2.2003967 2.2266114 0.2739109 0.2534075 0.1946055 0.7070174 0.7116334 0.197384 0.1955924 0.1940394 0.5383966 0.6047711 0.1965578 0.1957318 0.7472773 0.7424578 0.3618556 0.7522863 0.1961336 0.1993785 0.7176376 0.7075799 0.4257766 0.1968208 0.1978502 0.4767214 0.7292425 0.7338587 0.6498012 0.7394662 0.758891 0.7620517 0.7020074 0.6656861 0.1979898 0.1958959 0.1950688 0.1861349 0.2823345 0.1960588 0.606619 0.7230332 0.7544783 0.1966991 0.4146112 0.5453279 0.7190266
	4.7593732 4.7452672 1.0364912 0.906016 0.1511164 0.0035642 3.0954067 2.9618444 -1.1195999 -0.9299169 4.76188 4.7165363 -5.0672003 -5.2856254 -4.2957807 -4.0350356 1.6797165 1.5302457 4.7840699 -1.2179779 -1.0848024 4.8792145 5.0218261 0.568364 4.3351174 4.6164865 4.7497338 4.7630773 4.7395531 4.7620402 4.7608843 -0.2180816 -0.2090379 -0.2279118 -3.4738169 -3.3602961 -0.2046189 -5.3633463 -5.353903 -5.3627518 2.4759375 2.6190088 -5.3590412 -0.2214822 -0.2243977 1.8454008 2.0690306 -4.8820528 -0.1887406 -0.2379082 -0.0611039 -0.4281824 -4.6099233 -4.613898 -0.2179273 -0.2331927 4.3972376 4.2614183 -5.338406 -5.3465656 2.2796309 -4.6155066 -4.594168 -3.8820517 -4.2193698 -4.5368742 -4.7147622 1.9305624 -5.3557359 -5.4077423 -5.4416739 -5.4511211 -2.0060168 -2.3582999 -3.1298954 -5.4045799 -5.4287691 5.0050349 4.9030721 4.7974005 3.5178496 3.3029058 -5.4979257 -5.4940982 0.1262369 0.2317746 4.7418148 -0.2257894 0.2225734 0.2315114 -1.7481801 -1.5500564 4.7603127 4.7487138 -4.3303961 -2.712905 -2.9440248 -5.4819173 -0.2409733 0.3995374 4.1888551 1.7334597 4.7647564 -0.745193 -1.324844 -3.7582778 -3.6171683 -2.0266127 -1.9063509 -0.2185686 2.1081022 2.574372 4.7635332 4.87405 -4.5702073 -4.6103311 3.5704793 3.3133476 3.9730522 -4.553499 -4.5372926 1.4040939 -4.6105215 -5.4115938 -5.4214414 -1.9130641 -1.6679434 -3.581865 -3.0186222 -2.6982258 -5.3631841 -0.2195006 -0.2220225 -4.9434911 -3.1369419 -3.4665235 3.9963797 0.8483447 0.9946071 -4.6162035 -4.6151883 -0.207133 -0.2073058 -4.6146554 -4.6179751 2.7377861 -2.4666699 -0.2176174 -0.2394116 -2.5503315 0.0057175 -0.2361063 -2.2586496 0.2004048 -1.5575848 4.7567864 4.7590635 -4.6160519 -3.8082458 -0.8135604 4.5371323 -1.434666 -4.4953277 -5.5139419 -5.5077616 -0.2201304 4.6715208 4.7531561 2.7351927 -5.1702899 -4.6071739 0.5992303 4.7584618 -4.6119337 -0.0455794 3.1620971 3.6597283 -5.4576179 3.8804217 -5.4697671 1.5103246 -0.470759 -0.3527396 1.2889249 -3.5969762 -3.7187346 4.3834217 4.2294094 5.3860057 5.2790535 5.7577122 5.6927545 1.6076729 1.1685686 4.7732621 4.8672093 -3.4448751 -0.5395819 -0.4137225 3.9615591 3.979436 2.47935 2.8131033 -2.3869339 -2.575875 -2.0314097 -1.7883626 -0.9405374 -0.8125868 -2.1355479 4.1330239 4.175073 5.5378115 5.3979546 -4.7500578 -4.636068 4.0694225 -4.1451459 -4.2772811 2.8157095 3.1836101 -1.4935176 -1.7986808 -3.9319748 -3.7890244 -3.0279246 -3.2359378 1.8212874 1.6873363 0.2144929 0.3455279 3.7514631 -2.7017401 0.5923072 0.7133432 0.1214988 3.2403343 3.1141786 3.5414453 3.3195179 0.2423507 0.4542357 0.8563967 1.0351491 -4.8340009 3.4902377 3.627373 -0.0144422 -1.6605162 -1.5015648 1.0426363 -0.1068128 -0.2727829 0.9166035 5.1660693 5.0800751 5.1611191 -3.1126674 -3.2517483 -5.0647839 -5.1883263 5.62082 -0.8885109 -1.217533 -2.0085917 -2.9254642 -2.7434714 -2.2456022 2.9540851 -1.2245211 -1.3654195 5.6017691 -4.7535194 -4.6125951 -4.5866048 -4.5181695 -5.1738568 -5.0636894 -2.5874214 -4.033849 -3.8337115 4.3159075 -3.3708901 4.995152 3.361287 0.7585958 2.6206285 4.5366279 4.5962671 3.8374092 -4.2827616 -4.4056945 5.6728148 5.7888043 -4.9039478 -4.9929399 -1.0706216 1.9446715 -2.4674572 4.3848517 4.4731066 -0.6656354 5.4919334 -0.6695136 -4.9294768 -4.1635774 1.5481684 5.5788869 2.3646172 2.5135887 -3.5898796 0.023281 -4.3882091 2.1266486 5.2739631 5.3310001 4.9714799 -1.3925504 5.7487686 2.0043374 2.3423274 2.1554312 -0.546499 1.2011396 1.3611811 4.8691887 4.5043956 -0.426474 4.7282565 -0.1421964 -0.1200854 0.9598278 1.0170075 0.4054603 0.4546892 -0.1171242 -0.1207261 -0.1140999 -0.1336485 -0.1188466 -0.1148453 -0.1195454 0.6870298 0.6457906 1.0817281 1.1395457 1.1341842 1.075988 0.2916879 0.3610642 -0.129405 -0.1178584 0.2334781 -0.1191888 -0.1122261 -0.1181644 0.8558622 0.9140715 0.5353793 0.5196466 0.1828318 -0.1257037 -0.1245232 0.5173639 0.463138 1.023523 0.3476745 0.2988452 0.8412648 0.7936446 -0.1245866 -0.2220483 0.2123269 0.1122533 0.0001985 0.9682994 -0.117583 -0.0436288 -0.105462 0.7968436 -0.1203694 -0.1318678 -0.1216613 0.5690571 0.1252266 -0.1281262 0.9030409 0.5759668 -0.113322 -0.1271864 0.6337552 0.6874043 0.0129848 0.0688073 0.0518518 -0.2856326 0.7410369 -4.7348311 -4.8668077 0.4772368 0.6112695 -4.9957935 -5.0997699 -4.9088343 -5.0198423 -3.9517587 -4.1767011 -5.074904 -3.8278876 -3.6758878 -2.1727393 -2.3057771 -3.3228893 -3.102964 -1.6876886 -1.4457806 -5.9888017 -5.5718277 1.3812904 1.4772689 -5.1797659 -1.8728502 -2.265915 -6.8927079 -6.7707152 0.7593087 0.8832643 -1.8497464 -2.9366644 -2.8366501 -5.593723 -5.7466992 -3.5917494 -3.6807526 -2.4625765 -4.6368592 -4.2729535 1.0532569 -1.3617344 -1.2068168 -6.2807022 -6.4276949 -7.1157092 -7.0057202 0.1672102 0.3082258 -3.8297572 -3.4498933 -6.6878237 -6.8247452 -5.8686993 -6.1908196 -5.2808914 -5.3548625 -2.9149431 -2.8008818 -4.0448945 -1.0848179 -5.3988163 1.2562675 -5.9837058 -6.1487069 -6.6557029 -6.3055529 -6.4207769 -4.6795 -4.849625 -2.7426289 1.2752888 1.154241 1.1092575 -0.2637322 -0.0127467 -5.2497495 -5.2897231 -2.6216483 -6.5437009 -0.434728 -0.6527538 -1.0048358 -1.2558606 -6.995812 -0.1567766 -0.8038266 -0.433833 -4.4975548 -4.6215348 -0.285786 -3.4276717 -3.2547356 -6.53971 -5.2079134 -0.9147365 -5.1538208 -1.6708459 -2.4708576 -5.4067778 -2.4079128 0.633258 0.4723188 -6.934767 0.2342414 0.3522592 4.4274596 4.664986 2.9148288 3.037797 2.9611397 3.1802109 0.414196 0.5298091 5.7294862 5.8571474 5.149569 5.3009954 -0.2416206 -0.0921642 5.7800148 5.5473745 5.3600594 5.4956993 4.7574097 4.5708657 5.0892714 -0.4336482 3.636411 3.7459623 2.0817843 2.3952325 0.6547084 0.7794784 4.2062235 4.0874256 6.1698446 5.8509495 1.8432025 1.9649052 0.6799853 0.8224252 4.082111 1.9437686 1.7235893 1.0612447 1.1078846 6.0254568 5.3685881 1.5075979 1.292491 3.7516179 3.8670208 5.1714414 2.7167216 4.190552 4.2949682 4.4413337 -0.3290049 -0.2159077 2.5170522 2.7272659 2.440242 2.1297469 2.846889 5.4477844 5.2294124 1.2056176 3.2964551 3.459531 0.4259306 0.3483211 1.3229227 1.1969882 4.7134822 4.857267 4.4142283 4.2158509 1.709339 1.5802729 5.1313956 5.1660324 5.1897724 5.3186975 3.6368499 4.9903176 0.298993 4.0435796 3.9839108 3.2952089 0.2397392 0.1331624 0.0934282 -0.09229 4.9682068 4.8720334 0.5995495 0.463595 1.0172221 5.4505751 0.0085971 1.4552458 1.0698642 4.9335129 4.2840952 4.5448404 4.0629087 5.0745378 4.5439149 5.047004 6.1336073 6.3693183 3.4153263 0.8707888 5.2310026 0.9535031 6.3193141 6.2724834 6.587858 6.5887284 4.8160058 4.8098101 6.1627506 6.1378739 5.9826035 5.9234622 4.8235067 6.4396178 6.5544666 4.8145053 4.8076104 4.8282254 4.8235401 5.0845978 5.0273995 4.8017271 4.8296714 4.838711 4.8358387 5.0120567 5.0905029 6.376698 5.7390312 5.6818838 5.7329645 5.6321323 6.5854084 6.5371755 4.8467981 4.887247 6.7769056 6.7191593 6.5856841 6.5845387 6.5914918 6.5916724 5.2669156 5.3390603 4.8160392 6.0415032 5.2389035 5.294886 6.4871127 6.4173137 6.1946055 5.8488484 4.8187866 5.6238766 5.4706973 5.3524085 5.4104465 5.9103319 6.1182824 6.0374544 5.1907758 6.6170076 5.5819472 6.5511113 6.54783 5.5396679 6.5860825 6.2350445 6.278154 4.8229456 4.8719876 4.9208527 5.8600009 4.8234719 6.2131995 6.1014303 4.8013686 6.7199188 6.5898304 4.8100927 4.8269824 5.974077 6.3427483 5.4795761 6.3695979 4.9240242 -4.6634685 -4.6780238 -5.5603752 -5.445693 -5.6746768 -5.6863175 -4.6701627 -4.6659991 -5.552164 -5.611231 -4.6684669 -4.6753951 -4.7273366 -4.8982567 -5.3345073 -5.391114 -4.6593855 -4.6631326 -5.673136 -5.6425671 -5.6959116 -5.6386934 -4.9988447 -5.0735571 -4.95034 -5.2796232 -5.68094 -5.6850055 -5.6321965 -4.6679962 -4.6616153 -4.6715927 -5.2246558 -5.3353779 -5.4973444 -5.1238685 -5.4418579 -5.2225607 -5.1191411 -5.1075354 -5.0058251 -5.6340154 -5.6227127 -4.7831344 -4.8419821 -4.660571 -4.6622405 -4.6624902 -4.6655001 -5.6311045 -4.8918903 -5.6379814 -4.6782957 -4.6657128 -5.6343782 -5.8573375 -5.7408429 -6.7546148 -6.7638087 -5.7459347 -5.7423345 -5.7396238 -6.4204735 -6.5518999 -5.7443519 -5.7427691 -6.8349986 -6.8254024 -6.0721112 -6.8449941 -5.7430611 -5.7494324 -6.7758066 -6.7558358 -6.1986561 -5.7447141 -5.7466993 -6.2983497 -6.7989961 -6.8081899 -6.641219 -6.8193882 -6.8581937 -6.8645172 -6.7446199 -6.6737018 -5.7466287 -5.7431912 -5.741609 -5.7229601 -5.9134446 -5.743099 -6.5567357 -6.7865968 -6.8494021 -5.7442806 -6.1753652 -6.4353777 -6.7786102
	-0.135089 -0.2850568 1.1368601 1.1299373 1.1339144 1.1338838 -2.6269768 -2.6249934 4.8059484 4.821947 -1.962096 -2.3150463 1.1439503 1.1669483 -2.6299637 -2.4740116 1.1358565 1.1348497 -2.4571605 -2.620988 -2.6259685 0.8279102 1.1278524 1.1269062 -2.5529968 -2.5509951 -1.1760453 -1.5250904 0.2819445 0.4099094 -1.8131147 2.5709182 2.7009184 2.432919 -2.6020246 -2.5290221 1.4389297 4.106945 4.241947 3.8939431 -2.5409977 -2.5369974 3.7589417 1.962921 2.0969214 -2.5070049 -2.5520019 1.134021 4.0119244 3.7599283 4.8879694 4.8249411 -0.5179924 -0.8020763 2.8309189 2.9699223 1.1969757 1.1899999 4.7639634 4.5099533 -2.6199664 0.7540096 0.6220392 4.8990397 4.8629775 4.8720219 4.855971 1.1239072 3.6249385 3.4119384 2.6159341 2.484932 4.8939512 4.8969592 -2.5730203 3.0059345 2.8749336 -2.6591653 -2.6590157 -2.6561636 -2.6309794 -2.5499978 1.4119329 1.5759321 -2.617001 -2.5610078 0.0019457 2.2979195 5.0688699 4.9338836 -2.5410122 -2.6090163 -0.722094 -0.8500174 4.9010428 4.8219657 4.7879651 1.7619329 3.628928 -2.5430089 -2.5569981 -2.5560046 0.5439268 -2.6319516 4.90698 4.8629733 4.8349738 -2.6229909 -2.6090177 1.8309206 1.1378443 1.1179623 0.133921 1.1678908 -1.0710777 -1.1930737 1.1348928 1.1119902 0.8649562 -0.1720698 -0.0280688 1.1359097 -0.2859858 3.2729391 3.1379352 4.7939509 4.7729515 -2.5400201 -2.6250096 -2.6070125 4.3739504 1.5689256 1.6989231 4.8129676 4.8319702 4.9069955 -2.5669956 -2.6060098 -2.6020086 0.3949316 0.1649317 4.5199319 4.2639265 -1.6510658 -1.8770486 -2.5549984 -2.6060099 3.364925 3.235926 4.8459637 4.7518845 3.1019227 -2.6050144 4.8069671 4.8159532 -0.4341151 -0.5630625 -1.4450677 -2.5170172 4.8439486 1.1859752 4.8630228 -2.4800083 1.1459562 1.2799337 3.5009273 1.1810004 -0.9960434 0.8469475 4.9109872 -2.1159795 -2.5760103 -1.6650793 -2.3790531 -2.5790048 1.1279283 -2.63298 2.1989343 -2.5829954 1.9799337 -2.6050052 -2.6270009 -2.6219822 -2.624951 -2.732757 -2.7332714 -2.6584803 -2.6592796 -2.6459953 -2.6486488 -2.6264398 -2.6235542 -2.6689135 -2.6757669 -2.6619478 -2.6588085 -2.7325955 -2.7191284 -2.7184439 -2.6928397 -2.6908627 -2.7015027 -2.6994922 -2.7018746 -2.7016031 -2.7278842 -2.7264601 -2.7214534 -2.7206448 -2.6994366 -2.6867747 -2.6845466 -2.6301016 -2.6340274 -2.7188188 -2.7148281 -2.6595583 -2.7082541 -2.7090959 -2.6644744 -2.662806 -2.6953787 -2.6985049 -2.7068949 -2.7060712 -2.7037847 -2.7044942 -2.7054098 -2.7061663 -2.6833993 -2.6828106 -2.6604993 -2.7017315 -2.7123389 -2.7118403 -2.682977 -2.6969687 -2.6978253 -2.6627719 -2.6628393 -2.7145696 -2.7133798 -2.7110392 -2.7099518 -2.7223609 -2.6955776 -2.6947349 -2.6817183 -2.7255152 -2.7247925 -2.6763522 -2.7166563 -2.7175652 -2.6761689 -2.6421864 -2.6457504 -2.6530332 -2.7318076 -2.7319361 -2.7304691 -2.7349934 -2.625936 -2.689034 -2.6928837 -2.6991691 -2.7315745 -2.7308799 -2.7291531 -2.6987262 -2.7230444 -2.723922 -2.6279784 -2.7362041 -2.7358441 -2.7128966 -2.7109504 -2.7363827 -2.7366638 -2.7307418 -2.7341351 -2.7335172 -2.6804468 -2.7051345 -2.6562302 -2.6963711 -2.6784124 -2.6655957 -2.6735399 -2.6704294 -2.6932584 -2.7346439 -2.7351731 -2.6344284 -2.6324021 -2.7245202 -2.7282919 -2.7222607 -2.6677761 -2.7302553 -2.6780197 -2.6758191 -2.7199191 -2.6419621 -2.6877694 -2.7363557 -2.7345666 -2.7068281 -2.6394382 -2.6664951 -2.665723 -2.70516 -2.7157855 -2.709097 -2.6675497 -2.6388541 -2.6364595 -2.6491358 -2.693191 -2.6309304 -2.7042736 -2.7023045 -2.7034019 -2.6871875 -2.7090298 -2.708067 -2.6528086 -2.6579327 -2.6866236 -2.6664054 2.195943 2.0569432 2.902943 2.6309433 4.7359433 4.6599433 1.7879432 1.6569431 3.955943 3.828943 2.445943 2.580943 1.5199432 3.7809425 4.0069425 2.0919444 2.1479439 2.2969431 2.3999431 1.4969434 1.5599435 4.3689431 4.2319431 1.4739435 2.974943 2.842943 1.3829432 1.933944 1.9679442 4.2369428 4.3989432 1.4089446 3.560943 3.4219431 1.7059432 1.6559433 2.0659436 4.9599436 5.0569438 3.308943 3.5029428 4.8499459 4.8429433 5.075945 4.9359434 4.8619463 2.0219439 1.2469435 1.2479436 2.7119429 1.8869454 3.1119429 3.6979429 4.0939432 4.1179425 1.3879436 3.280943 3.132943 1.7199439 1.919943 4.6159432 1.7499477 1.7949442 1.2849441 1.3409438 4.9159433 4.8319423 1.8559435 -2.6596823 -2.6635405 -2.6438577 -2.642222 -2.6678706 -2.6697483 -2.6481546 -2.6508423 -2.6395957 -2.6400683 -2.6527011 -2.6523997 -2.6523697 -2.6387739 -2.6395731 -2.6521182 -2.6528371 -2.6381123 -2.6379844 -2.6695125 -2.6662422 -2.6386564 -2.6371254 -2.6714061 -2.65154 -2.6518874 -2.6759453 -2.6757465 -2.6376686 -2.6373734 -2.6386092 -2.6390956 -2.6394454 -2.6764678 -2.6763756 -2.6401212 -2.6395978 -2.6395434 -2.6560629 -2.6535532 -2.6371595 -2.6385904 -2.6390446 -2.6758753 -2.676077 -2.6757363 -2.6759194 -2.6424748 -2.6430437 -2.6398439 -2.6524541 -2.6698991 -2.6698146 -2.6763616 -2.6695808 -2.6587666 -2.6605256 -2.6522682 -2.6523506 -2.6532618 -2.6388564 -2.663124 -2.6389061 -2.6762838 -2.6761055 -2.6757709 -2.6694325 -2.669605 -2.6421322 -2.6465767 -2.6399273 -2.6374058 -2.6375466 -2.6392574 -2.6379498 -2.637563 -2.6731092 -2.6764398 -2.6397456 -2.6761012 -2.6386383 -2.6373987 -2.6479216 -2.6478409 -2.6728262 -2.6436464 -2.6474336 -2.6443742 -2.6401216 -2.6403961 -2.6441011 -2.6398992 -2.639381 -2.6695924 -2.6571625 -2.6382463 -2.6543721 -2.6512484 -2.6513332 -2.6764499 -2.6522505 -2.6373288 -2.6373268 -2.6712295 -2.637605 -2.6375257 1.0036552 1.0448401 2.083173 2.078663 0.9392538 0.9403276 0.94198 0.9412005 1.5412002 1.636755 1.1826435 1.2900529 1.0891945 1.1525736 2.0227511 2.0073322 1.3680032 1.4495964 1.0868198 1.0858581 1.207302 0.9482758 2.0699823 2.0582756 0.9404725 0.9386299 0.9404303 0.9445294 1.2291764 1.1938172 1.9988951 1.9961903 0.9388317 0.9398306 1.6679491 1.7649913 2.0642755 2.1071302 2.0836117 1.9457578 1.9916263 1.7626745 1.329896 2.0745544 2.1058251 0.9403152 0.9393297 1.2651588 2.0921699 0.9410341 0.9772358 1.0867117 0.9387784 0.9372965 0.9391185 0.9384053 2.093395 2.0842762 0.9407682 1.4865764 1.3689062 2.0456981 0.9408574 0.9406228 1.4975936 1.4246918 0.9418176 0.9415487 1.4236084 1.467055 2.0212109 2.0440247 0.9420188 0.941187 1.1042573 1.1462519 2.0078286 2.017608 0.9409267 1.0015056 0.939964 1.0715054 1.1112787 2.0766174 1.3326038 1.2452065 0.9417621 0.9408668 2.0186313 2.0310737 1.6221556 1.5631264 1.9053573 2.0234314 1.1965596 0.9395405 0.9406589 0.960745 1.2707624 1.3601997 0.9400832 2.0104061 2.0335941 1.5348233 1.8576623 2.0093293 2.0741043 1.8065465 1.3236612 0.9406393 -2.6001096 -2.683106 -1.1570271 -1.3440369 0.3029267 0.0459261 1.1839632 1.3269605 -2.6720994 -2.653103 0.439922 -2.5611056 -2.4241371 -1.1180624 -1.256059 -0.0850726 -0.2220716 1.0109316 1.0569279 -2.2060555 -1.9650557 -1.6390556 -1.7770583 -2.5501229 -2.5721215 -2.5600991 1.588961 1.5319667 -2.6711294 -2.5421071 -0.0900254 0.0858682 -2.4561237 -2.5561223 -2.4001016 -2.2970946 -0.361037 -0.2250281 -1.8269288 -1.9689997 -2.5441202 -2.5381167 -0.359067 -2.6740997 1.1169419 1.155945 0.171868 0.5039401 1.0659534 1.6409697 -0.9800647 1.5009512 1.2818387 1.2398409 -2.5501155 1.6499743 1.5259649 1.5359623 -2.5601238 -2.4301697 1.4068333 -0.8321258 -0.9681236 -2.5411085 -0.6010451 0.9699548 0.8509551 -2.332058 0.6669235 0.9009262 -2.6751075 -0.8430656 -2.6891007 -2.6851 -1.4140566 -2.4271793 -1.5470241 -0.6350699 0.5779235 1.6399704 0.7419508 -2.5441119 0.6149472 1.3418149 -1.5250575 -1.6540545 -2.5690544 -2.6150543 -0.7380551 -0.5090618 -1.1300542 -1.2610571 0.4719429 0.4399472 0.233943 0.369943 -2.4570465 -2.489052 0.6519496 0.6119406 -0.0540567 0.0769429 -0.0200547 -0.2240548 -2.5440582 -2.5730543 -2.5540529 0.2919433 0.1619425 0.6949473 -2.2570587 -1.7490589 -2.0470586 -2.2250563 -1.9740506 -1.3960572 -2.604054 -2.5440509 0.4979512 -2.5450534 0.5579484 0.7339462 0.807939 0.3989451 0.8979397 -1.2490587 -1.3810588 0.3349424 0.2759421 -0.8880541 -0.404057 -0.6360567 -2.4650499 -1.511056 0.2069423 -1.1180555 -0.1810568 -1.7900572 -0.9810549 -2.5260606 -2.3780563 -0.2520572 -0.3840572 -1.3670571 -1.2370569 -2.1360564 0.3719447 0.3789494 -1.4980569 -1.6280568 -1.8910567 -1.7600569 -2.6100607 -2.0810567 -0.386057 -0.2530573 -0.6530572 -0.5160571 -2.5460605 -1.1070572 -0.9760572 0.3719463 -1.1720575 -1.3030574 -0.0020574 -1.5370573 -2.3810566 -2.5410605 -0.0680572 -2.5400604 -0.1200572 -1.8680566 -2.0050564 0.3599389 0.3639423 -0.845057 -2.5240604 -0.9150576 -2.2480565 -0.632057 0.3699447 -2.5370606 -0.7840572
]);

#=== TOPOLOGY : 1-CELLS ===#
I = Array{Int64}([1, 52, 1, 125, 2, 100, 2, 13, 3, 46, 3, 21, 4, 120, 4, 173, 5, 69, 5, 174, 6, 17, 6, 10, 7, 28, 7, 168, 8, 128, 8, 122, 9, 39, 9, 82, 10, 84, 11, 61, 11, 68, 12, 67, 12, 75, 13, 46, 14, 64, 14, 47, 15, 151, 15, 147, 16, 74, 16, 117, 17, 144, 18, 19, 18, 95, 19, 54, 20, 89, 20, 43, 21, 99, 22, 23, 22, 91, 23, 25, 24, 35, 24, 107, 25, 50, 26, 72, 26, 76, 27, 66, 27, 133, 28, 65, 29, 159, 29, 62, 30, 143, 30, 123, 31, 83, 31, 130, 32, 95, 32, 113, 33, 126, 33, 79, 34, 153, 34, 110, 35, 133, 36, 65, 36, 155, 37, 172, 37, 58, 38, 114, 38, 93, 39, 94, 40, 50, 40, 101, 41, 53, 41, 157, 42, 167, 42, 111, 43, 184, 44, 97, 44, 53, 45, 84, 45, 86, 47, 86, 48, 156, 48, 120, 49, 163, 49, 60, 51, 150, 51, 63, 52, 80, 54, 76, 55, 143, 55, 116, 56, 98, 56, 61, 57, 145, 57, 137, 58, 114, 59, 182, 59, 131, 60, 169, 62, 134, 63, 171, 64, 102, 66, 170, 67, 117, 68, 177, 69, 127, 70, 172, 70, 148, 71, 146, 71, 98, 72, 160, 73, 94, 73, 138, 74, 80, 75, 162, 77, 130, 77, 121, 78, 135, 78, 152, 79, 135, 81, 88, 81, 124, 82, 100, 83, 88, 85, 101, 85, 97, 87, 167, 87, 118, 89, 140, 90, 184, 90, 108, 91, 110, 92, 99, 92, 160, 93, 139, 96, 131, 96, 148, 102, 166, 103, 142, 103, 180, 104, 155, 104, 124, 105, 112, 105, 159, 106, 158, 106, 141, 107, 173, 108, 115, 109, 132, 109, 164, 111, 182, 112, 183, 113, 164, 115, 146, 116, 183, 118, 175, 119, 125, 119, 145, 121, 158, 122, 140, 123, 174, 126, 136, 127, 175, 128, 149, 129, 168, 129, 163, 132, 134, 136, 162, 137, 151, 138, 154, 139, 153, 141, 176, 142, 171, 144, 147, 149, 176, 150, 181, 152, 154, 156, 161, 157, 165, 161, 166, 165, 169, 170, 179, 177, 178, 178, 181, 179, 180, 185, 191, 185, 297, 186, 324, 186, 202, 187, 269, 187, 228, 188, 320, 188, 231, 189, 263, 189, 223, 190, 323, 190, 247, 191, 253, 192, 268, 192, 306, 193, 325, 193, 252, 194, 302, 194, 328, 195, 198, 195, 280, 196, 235, 196, 227, 197, 288, 197, 267, 198, 316, 199, 252, 199, 244, 200, 238, 200, 314, 201, 219, 201, 261, 202, 210, 203, 322, 203, 282, 204, 251, 204, 317, 205, 305, 205, 233, 206, 322, 206, 318, 207, 211, 207, 246, 208, 295, 208, 276, 209, 213, 209, 249, 210, 250, 211, 280, 212, 259, 212, 217, 213, 221, 214, 248, 214, 236, 215, 250, 215, 317, 216, 281, 216, 259, 217, 218, 218, 313, 219, 287, 220, 319, 220, 256, 221, 311, 222, 227, 222, 294, 223, 225, 224, 300, 224, 306, 225, 254, 226, 285, 226, 289, 228, 329, 229, 290, 229, 253, 230, 304, 230, 245, 231, 307, 232, 272, 232, 291, 233, 316, 234, 290, 234, 242, 235, 264, 236, 328, 237, 262, 237, 294, 238, 307, 239, 273, 239, 270, 240, 261, 240, 308, 241, 245, 241, 292, 242, 327, 243, 275, 243, 297, 244, 266, 246, 279, 247, 329, 248, 319, 249, 254, 251, 303, 255, 271, 255, 312, 256, 325, 257, 274, 257, 270, 258, 315, 258, 293, 260, 287, 260, 304, 262, 288, 263, 283, 264, 327, 265, 266, 265, 271, 267, 268, 269, 277, 272, 298, 273, 292, 274, 275, 276, 309, 277, 315, 278, 284, 278, 303, 279, 318, 281, 300, 282, 308, 283, 284, 285, 286, 286, 314, 289, 310, 291, 305, 293, 320, 295, 326, 296, 302, 296, 326, 298, 321, 299, 313, 299, 309, 301, 310, 301, 324, 311, 321, 312, 323, 330, 352, 330, 386, 331, 375, 331, 371, 332, 362, 332, 394, 333, 377, 333, 336, 334, 366, 334, 370, 335, 352, 335, 360, 336, 344, 337, 356, 337, 367, 338, 350, 338, 380, 339, 380, 339, 371, 340, 342, 340, 390, 341, 381, 341, 372, 342, 347, 343, 364, 343, 374, 344, 378, 345, 361, 345, 358, 346, 369, 346, 394, 347, 368, 348, 365, 348, 373, 349, 376, 349, 390, 350, 379, 351, 362, 351, 363, 353, 383, 353, 356, 354, 357, 354, 389, 355, 363, 355, 387, 357, 388, 358, 379, 359, 378, 359, 393, 360, 374, 361, 392, 364, 395, 365, 370, 366, 372, 367, 369, 368, 385, 373, 395, 375, 383, 376, 396, 377, 386, 381, 397, 382, 396, 382, 391, 384, 393, 384, 385, 387, 388, 389, 397, 391, 392, 398, 493, 398, 488, 399, 443, 399, 449, 400, 488, 400, 410, 401, 490, 401, 403, 402, 428, 402, 472, 403, 484, 404, 433, 404, 426, 405, 414, 405, 418, 406, 445, 406, 476, 407, 434, 407, 447, 408, 430, 408, 463, 409, 437, 409, 466, 410, 475, 411, 470, 411, 496, 412, 483, 412, 439, 413, 478, 413, 420, 414, 434, 415, 464, 415, 444, 416, 473, 416, 429, 417, 503, 417, 425, 418, 494, 419, 493, 419, 469, 420, 500, 421, 447, 421, 435, 422, 492, 422, 487, 423, 456, 423, 483, 424, 457, 424, 443, 425, 428, 426, 445, 427, 462, 427, 497, 429, 440, 430, 446, 431, 465, 431, 436, 432, 476, 432, 471, 433, 469, 435, 467, 436, 463, 437, 501, 438, 440, 438, 492, 439, 453, 441, 446, 441, 482, 442, 479, 442, 490, 444, 452, 448, 466, 448, 500, 449, 501, 450, 486, 450, 491, 451, 475, 451, 474, 452, 494, 453, 487, 454, 486, 454, 498, 455, 485, 455, 502, 456, 481, 457, 460, 458, 485, 458, 489, 459, 472, 459, 479, 460, 489, 461, 503, 461, 464, 462, 482, 465, 468, 467, 498, 468, 484, 470, 502, 471, 477, 473, 474, 477, 496, 478, 480, 480, 499, 481, 497, 491, 495, 495, 499, 504, 596, 504, 566, 505, 531, 505, 554, 506, 610, 506, 601, 507, 551, 507, 559, 508, 595, 508, 526, 509, 578, 509, 590, 510, 515, 510, 563, 511, 577, 511, 562, 512, 527, 512, 595, 513, 514, 513, 533, 514, 530, 515, 547, 516, 591, 516, 523, 517, 612, 517, 609, 518, 559, 518, 588, 519, 593, 519, 613, 520, 589, 520, 577, 521, 584, 521, 612, 522, 600, 522, 585, 523, 556, 524, 553, 524, 607, 525, 561, 525, 539, 526, 580, 527, 590, 528, 607, 528, 574, 529, 576, 529, 569, 530, 606, 531, 592, 532, 583, 532, 596, 533, 597, 534, 547, 534, 598, 535, 609, 535, 537, 536, 592, 536, 553, 537, 610, 538, 579, 538, 587, 539, 574, 540, 601, 540, 549, 541, 571, 541, 586, 542, 604, 542, 565, 543, 594, 543, 605, 544, 599, 544, 556, 545, 584, 545, 564, 546, 550, 546, 578, 548, 570, 548, 575, 549, 576, 550, 572, 551, 568, 552, 597, 552, 613, 554, 582, 555, 586, 555, 602, 557, 568, 557, 598, 558, 611, 558, 573, 560, 600, 560, 571, 561, 603, 562, 575, 563, 602, 564, 604, 565, 608, 566, 572, 567, 593, 567, 594, 569, 583, 570, 611, 573, 599, 579, 605, 580, 581, 581, 589, 582, 591, 585, 603, 587, 606, 588, 608, 614, 627, 614, 677, 615, 673, 615, 669, 616, 619, 616, 636, 617, 643, 617, 690, 618, 638, 618, 685, 619, 672, 620, 688, 620, 652, 621, 645, 621, 667, 622, 636, 622, 637, 623, 640, 623, 695, 624, 684, 624, 639, 625, 694, 625, 639, 626, 675, 626, 651, 627, 688, 628, 644, 628, 646, 629, 664, 629, 656, 630, 662, 630, 692, 631, 660, 631, 675, 632, 679, 632, 671, 633, 661, 633, 662, 634, 680, 634, 671, 635, 676, 635, 648, 637, 683, 638, 689, 640, 641, 641, 655, 642, 692, 642, 697, 643, 658, 644, 649, 645, 665, 646, 678, 647, 653, 647, 655, 648, 693, 649, 686, 650, 690, 650, 674, 651, 676, 652, 668, 653, 678, 654, 657, 654, 673, 656, 687, 657, 661, 658, 659, 659, 682, 660, 684, 663, 681, 663, 696, 664, 685, 665, 670, 666, 677, 666, 689, 667, 694, 668, 679, 669, 680, 670, 683, 672, 681, 674, 686, 682, 691, 687, 693, 691, 697, 695, 696, 698, 728, 698, 747, 699, 740, 699, 732, 700, 745, 700, 708, 701, 730, 701, 716, 702, 718, 702, 707, 703, 722, 703, 734, 704, 736, 704, 710, 705, 712, 705, 721, 706, 743, 706, 722, 707, 720, 708, 720, 709, 713, 709, 740, 710, 719, 711, 724, 711, 750, 712, 729, 713, 738, 714, 737, 714, 738, 715, 748, 715, 744, 716, 728, 717, 746, 717, 732, 718, 741, 719, 746, 721, 741, 723, 729, 723, 725, 724, 733, 725, 733, 726, 742, 726, 751, 727, 734, 727, 739, 730, 735, 731, 749, 731, 735, 736, 748, 737, 751, 739, 750, 742, 752, 743, 749, 744, 747, 745, 752, 753, 760, 753, 756, 754, 772, 754, 777, 755, 787, 755, 793, 756, 786, 757, 766, 757, 768, 758, 787, 758, 776, 759, 761, 759, 769, 760, 764, 761, 782, 762, 783, 762, 774, 763, 789, 763, 777, 764, 785, 765, 793, 765, 779, 766, 790, 767, 781, 767, 771, 768, 788, 769, 771, 770, 792, 770, 773, 772, 788, 773, 780, 774, 795, 775, 776, 775, 786, 778, 795, 778, 784, 779, 794, 780, 791, 781, 796, 782, 792, 783, 794, 784, 790, 785, 791, 789, 796, ]);
J = Array{Int64}([1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149, 150, 150, 151, 151, 152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 157, 158, 158, 159, 159, 160, 160, 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, 166, 167, 167, 168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 173, 173, 174, 174, 175, 175, 176, 176, 177, 177, 178, 178, 179, 179, 180, 180, 181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188, 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 194, 194, 195, 195, 196, 196, 197, 197, 198, 198, 199, 199, 200, 200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 206, 206, 207, 207, 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255, 256, 256, 257, 257, 258, 258, 259, 259, 260, 260, 261, 261, 262, 262, 263, 263, 264, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 270, 270, 271, 271, 272, 272, 273, 273, 274, 274, 275, 275, 276, 276, 277, 277, 278, 278, 279, 279, 280, 280, 281, 281, 282, 282, 283, 283, 284, 284, 285, 285, 286, 286, 287, 287, 288, 288, 289, 289, 290, 290, 291, 291, 292, 292, 293, 293, 294, 294, 295, 295, 296, 296, 297, 297, 298, 298, 299, 299, 300, 300, 301, 301, 302, 302, 303, 303, 304, 304, 305, 305, 306, 306, 307, 307, 308, 308, 309, 309, 310, 310, 311, 311, 312, 312, 313, 313, 314, 314, 315, 315, 316, 316, 317, 317, 318, 318, 319, 319, 320, 320, 321, 321, 322, 322, 323, 323, 324, 324, 325, 325, 326, 326, 327, 327, 328, 328, 329, 329, 330, 330, 331, 331, 332, 332, 333, 333, 334, 334, 335, 335, 336, 336, 337, 337, 338, 338, 339, 339, 340, 340, 341, 341, 342, 342, 343, 343, 344, 344, 345, 345, 346, 346, 347, 347, 348, 348, 349, 349, 350, 350, 351, 351, 352, 352, 353, 353, 354, 354, 355, 355, 356, 356, 357, 357, 358, 358, 359, 359, 360, 360, 361, 361, 362, 362, 363, 363, 364, 364, 365, 365, 366, 366, 367, 367, 368, 368, 369, 369, 370, 370, 371, 371, 372, 372, 373, 373, 374, 374, 375, 375, 376, 376, 377, 377, 378, 378, 379, 379, 380, 380, 381, 381, 382, 382, 383, 383, 384, 384, 385, 385, 386, 386, 387, 387, 388, 388, 389, 389, 390, 390, 391, 391, 392, 392, 393, 393, 394, 394, 395, 395, 396, 396, 397, 397, 398, 398, 399, 399, 400, 400, 401, 401, 402, 402, 403, 403, 404, 404, 405, 405, 406, 406, 407, 407, 408, 408, 409, 409, 410, 410, 411, 411, 412, 412, 413, 413, 414, 414, 415, 415, 416, 416, 417, 417, 418, 418, 419, 419, 420, 420, 421, 421, 422, 422, 423, 423, 424, 424, 425, 425, 426, 426, 427, 427, 428, 428, 429, 429, 430, 430, 431, 431, 432, 432, 433, 433, 434, 434, 435, 435, 436, 436, 437, 437, 438, 438, 439, 439, 440, 440, 441, 441, 442, 442, 443, 443, 444, 444, 445, 445, 446, 446, 447, 447, 448, 448, 449, 449, 450, 450, 451, 451, 452, 452, 453, 453, 454, 454, 455, 455, 456, 456, 457, 457, 458, 458, 459, 459, 460, 460, 461, 461, 462, 462, 463, 463, 464, 464, 465, 465, 466, 466, 467, 467, 468, 468, 469, 469, 470, 470, 471, 471, 472, 472, 473, 473, 474, 474, 475, 475, 476, 476, 477, 477, 478, 478, 479, 479, 480, 480, 481, 481, 482, 482, 483, 483, 484, 484, 485, 485, 486, 486, 487, 487, 488, 488, 489, 489, 490, 490, 491, 491, 492, 492, 493, 493, 494, 494, 495, 495, 496, 496, 497, 497, 498, 498, 499, 499, 500, 500, 501, 501, 502, 502, 503, 503, 504, 504, 505, 505, 506, 506, 507, 507, 508, 508, 509, 509, 510, 510, 511, 511, 512, 512, 513, 513, 514, 514, 515, 515, 516, 516, 517, 517, 518, 518, 519, 519, 520, 520, 521, 521, 522, 522, 523, 523, 524, 524, 525, 525, 526, 526, 527, 527, 528, 528, 529, 529, 530, 530, 531, 531, 532, 532, 533, 533, 534, 534, 535, 535, 536, 536, 537, 537, 538, 538, 539, 539, 540, 540, 541, 541, 542, 542, 543, 543, 544, 544, 545, 545, 546, 546, 547, 547, 548, 548, 549, 549, 550, 550, 551, 551, 552, 552, 553, 553, 554, 554, 555, 555, 556, 556, 557, 557, 558, 558, 559, 559, 560, 560, 561, 561, 562, 562, 563, 563, 564, 564, 565, 565, 566, 566, 567, 567, 568, 568, 569, 569, 570, 570, 571, 571, 572, 572, 573, 573, 574, 574, 575, 575, 576, 576, 577, 577, 578, 578, 579, 579, 580, 580, 581, 581, 582, 582, 583, 583, 584, 584, 585, 585, 586, 586, 587, 587, 588, 588, 589, 589, 590, 590, 591, 591, 592, 592, 593, 593, 594, 594, 595, 595, 596, 596, 597, 597, 598, 598, 599, 599, 600, 600, 601, 601, 602, 602, 603, 603, 604, 604, 605, 605, 606, 606, 607, 607, 608, 608, 609, 609, 610, 610, 611, 611, 612, 612, 613, 613, 614, 614, 615, 615, 616, 616, 617, 617, 618, 618, 619, 619, 620, 620, 621, 621, 622, 622, 623, 623, 624, 624, 625, 625, 626, 626, 627, 627, 628, 628, 629, 629, 630, 630, 631, 631, 632, 632, 633, 633, 634, 634, 635, 635, 636, 636, 637, 637, 638, 638, 639, 639, 640, 640, 641, 641, 642, 642, 643, 643, 644, 644, 645, 645, 646, 646, 647, 647, 648, 648, 649, 649, 650, 650, 651, 651, 652, 652, 653, 653, 654, 654, 655, 655, 656, 656, 657, 657, 658, 658, 659, 659, 660, 660, 661, 661, 662, 662, 663, 663, 664, 664, 665, 665, 666, 666, 667, 667, 668, 668, 669, 669, 670, 670, 671, 671, 672, 672, 673, 673, 674, 674, 675, 675, 676, 676, 677, 677, 678, 678, 679, 679, 680, 680, 681, 681, 682, 682, 683, 683, 684, 684, 685, 685, 686, 686, 687, 687, 688, 688, 689, 689, 690, 690, 691, 691, 692, 692, 693, 693, 694, 694, 695, 695, 696, 696, 697, 697, 698, 698, 699, 699, 700, 700, 701, 701, 702, 702, 703, 703, 704, 704, 705, 705, 706, 706, 707, 707, 708, 708, 709, 709, 710, 710, 711, 711, 712, 712, 713, 713, 714, 714, 715, 715, 716, 716, 717, 717, 718, 718, 719, 719, 720, 720, 721, 721, 722, 722, 723, 723, 724, 724, 725, 725, 726, 726, 727, 727, 728, 728, 729, 729, 730, 730, 731, 731, 732, 732, 733, 733, 734, 734, 735, 735, 736, 736, 737, 737, 738, 738, 739, 739, 740, 740, 741, 741, 742, 742, 743, 743, 744, 744, 745, 745, 746, 746, 747, 747, 748, 748, 749, 749, 750, 750, 751, 751, 752, 752, 753, 753, 754, 754, 755, 755, 756, 756, 757, 757, 758, 758, 759, 759, 760, 760, 761, 761, 762, 762, 763, 763, 764, 764, 765, 765, 766, 766, 767, 767, 768, 768, 769, 769, 770, 770, 771, 771, 772, 772, 773, 773, 774, 774, 775, 775, 776, 776, 777, 777, 778, 778, 779, 779, 780, 780, 781, 781, 782, 782, 783, 783, 784, 784, 785, 785, 786, 786, 787, 787, 788, 788, 789, 789, 790, 790, 791, 791, 792, 792, 793, 793, 794, 794, 795, 795, 796, 796, ]);
K = Array{Int8}([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ]);

Lar.addModelCells!(casa, 1, SparseArrays.sparse(I, J, K, 796, 796))

#=== TOPOLOGY : 2-CELLS ===#
I = Array{Int64}([]);
J = Array{Int64}([]);
K = Array{Int8}([]);

Lar.addModelCells!(casa, 2, SparseArrays.sparse(I, J, K, 0, 796))

#=== TOPOLOGY : 3-CELLS ===#
I = Array{Int64}([]);
J = Array{Int64}([]);
K = Array{Int8}([]);

Lar.addModelCells!(casa, 3, SparseArrays.sparse(I, J, K, 0, 0))


include("C:\\Users\\warner\\Desktop\\My Stuff\\Personal Learning\\Monte Carlo\\NautilusMC\\NautilusMC\\Materials.jl")
include("C:\\Users\\warner\\Desktop\\My Stuff\\Personal Learning\\Monte Carlo\\NautilusMC\\NautilusMC\\geometry.jl")

water = define_Material(
        density = 1.0,
        nuclides = ["O-nat", "H-nat"],
        atomic_fracs = [1.0, 2.0],
        color = [0, 200, 0])

B4C = define_Material(
        density = 2.52,
        nuclides = ["B-nat", "C-nat"],
        atomic_fracs = [4.0, 1.0],
        color = [100, 0, 100])

s1 = box([-1.0, -1.0, -1.0], [1.0, 1.0, 1.0])
s2 = box([-2.0, -2.0, -2.0], [2.0, 2.0, 2.0])
s3 = box([-3.0, -3.0, -3.0], [3.0, 3.0, 3.0])

C1 = Cell([s1], [], water, [])
C2 = Cell([s2], [s1], B4C, [])
outside = Cell([], [s2], nothing, [])

Root = Universe([C1, C2, outside], [])


using DSGE, Test, ModelConstructors

m = AnSchorfheide()
if haskey(ENV, "FRED_API_KEY") || isfile(joinpath(ENV["HOME"],".freddatarc"))
    load_data(m)

    @testset "Test util functions" begin
        @test get_class(:histobs) == :obs
        @test get_class(:histpseudo) == :pseudo
        @test get_class(:histstates) == :states
        @test get_class(:histstdshock) == :stdshocks
        @test get_class(:histshocks) == :shocks
        @test_throws ErrorException get_class(:bad)

        @test get_product(:bddhistforecast4qobs) == :bddhistforecast4q
        @test get_product(:dettrendobs) == :dettrend
        @test_throws ErrorException get_product(:bad)

        @test DSGE.get_class_longname(:pseudo)==:pseudoobservable
        @test DSGE.get_class_longname(:obs)==:observable
        @test DSGE.get_class_longname(:states)==:state
        @test DSGE.get_class_longname(:shocks)==:shock
        @test DSGE.parse_transform(Symbol("DSGE.loggrowthtopct_annualized"))([1.0]) ==
            DSGE.loggrowthtopct_annualized([1.0])

        m <= Setting(:use_population_forecast, false)
        m <= Setting(:hpfilter_population, true)
        DSGE.load_population_growth(m)
        m <= Setting(:hpfilter_population, false)
        DSGE.load_population_growth(m)
        m <= Setting(:use_population_forecast, true)
        @test_throws ErrorException DSGE.load_population_growth(m)

        @test DSGE.get_y0_index(m, :forecast) == 241
        @test DSGE.get_y0_index(m, :forecast4q) == 238
        @test DSGE.get_y0_index(m, :shockdec) == 2
        @test DSGE.get_y0_index(m, :hist) == 2
        @test DSGE.get_y0_index(m, :irf) == -1
        @test_throws ErrorException DSGE.get_y0_index(m, :bad)

        @test DSGE.check_consistent_order([1; 2; 3], [4; 5; 6])
        @test_throws AssertionError DSGE.check_consistent_order([1; 2; 3], [5; 4; 6])
        #would be nice to test:
        # resize population_forecast
        # get_population_series
        # get_mb_populuation_series

    end
else
        @warn "Skipping fred_data test because FRED_API_KEY not present"
end

@testset "Test prior_table works" begin
    DSGE.prior_table(m)

    DSGE.posterior_table(m, ones(16), ones(16, 2))

    DSGE.prior_posterior_moments_table(m, ones(16), ones(16, 2))
    DSGE.prior_posterior_table(m, ones(16))

end

@testset "Test finding density bands" begin
    @test find_density_bands(ones(100, 100), 0.95) == ones(2, 100)
    @test find_density_bands(ones(1, 100), 0.95) == ones(2, 100)
    @test find_density_bands(ones(100, 100), 0.95, minimize = true) == ones(2, 100)
    dens = find_density_bands(ones(100, 100), [.8, .9])
    @test names(dens) == [Symbol("80.0% UB"), Symbol("80.0% LB"), Symbol("90.0% UB"), Symbol("90.0% LB")]
    @test Matrix(dens) == ones(100,4)
end


module GlobalDecls

    export DATADIR, RESULTSDIR, SKIPLIST, WEEKS_PER_YEAR, annualise
    export Region, london, se, rest_of_england
    export AggLevel, national, regional, local_authority
    export SIMULATION_YEAR

    const DATADIR="/home/graham_s/VirtualWorlds/projects/action_for_children/england/data/"
    const RESULTSDIR="/home/graham_s/VirtualWorlds/projects/action_for_children/england/results/"

    const SIMULATION_YEAR = 2019

    @enum AggLevel national regional local_authority
    @enum Region london se rest_of_england
    WEEKS_PER_YEAR = 365.25/7

    SKIPLIST = [
        # "E07000189" # south somerset missing in underlying data
    ]

    function annualise( m :: Real ) :: Real
        return m*WEEKS_PER_YEAR/1_000_000.0
    end

end


"""
GenX: An Configurable Capacity Expansion Model
Copyright (C) 2021,  Massachusetts Institute of Technology
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 2 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.
A complete copy of the GNU General Public License v2 (GPLv2) is available
in LICENSE.txt.  Users uncompressing this from an archive may not have
received this license file.  If not, see <http://www.gnu.org/licenses/>.
"""

@doc raw"""
	emissions(EP::Model, inputs::Dict, UCommit::Int)

This function creates expression to add the CO2 emissions by plants in each zone, which is subsequently added to the total emissions
"""
function emissions(EP::Model, inputs::Dict)

	println("Emissions Module (for CO2 Policy modularization")

	dfGen = inputs["dfGen"]

	G = inputs["G"]     # Number of resources (generators, storage, DR, and DERs)
	T = inputs["T"]     # Number of time steps (hours)
	Z = inputs["Z"]     # Number of zones
	COMMIT = inputs["COMMIT"] # For not, thermal resources are the only ones eligible for Unit Committment

	@expression(EP, eEmissionsByPlant[y=1:G,t=1:T],
	 	if y in inputs["COMMIT"]
		 	dfGen[!,:CO2_per_MWh][y]*EP[:vP][y,t]+dfGen[!,:CO2_per_Start][y]*EP[:vSTART][y,t]
	 	else
		 	dfGen[!,:CO2_per_MWh][y]*EP[:vP][y,t]
	 	end
 	)

 	@expression(EP, eEmissionsByZone[z=1:Z, t=1:T], sum(eEmissionsByPlant[y,t] for y in dfGen[(dfGen[!,:Zone].==z),:R_ID]))

	return EP
end


"""
	writeatmosph(data,fileout;decimal)
Write DataFrame to Hydrus1D Atmospheric data format

**Input**
* data: dataframe containing columns + timevector in DateTime format.
* fileout: full name of the output file
* decimal: optional output precision for either all or individual columns.
> input dataframe should contain :Prec,:rSoil,:rRoot,:hCritA,:rB,:hB,:ht columns,
> if not, will be set to zero. Tested for  Hydrus-1D 4.16.0110

**Example**
```
dataout = DataFrame(Prec=[0.01,0.1,0.2,0.3],
				 rSoil=[0.0,0.1,0.2,0.9],
	   			 hCritA=[1,1,1,1]
	   			 datetime=[DateTime(2010,1,1,0),DateTime(2010,1,1,1),
		   			  DateTime(2010,1,1,2),DateTime(2010,1,1,3)],);
writeatmosph(dataout,"test/output/atmosph_data.in",
			decimal=[1],
			hCritS=1000.,Extinction=-1.0);
```
"""
function writeatmosph(data::DataFrame,fileout::String;decimal=[4],hCritS=0.0,Extinction=-1.0)
	channels,timei = FileTools.findchannels(data);
	# Round data to output precision
	dataout = FileTools.round2output(data,decimal,channels);
	open(fileout,"w") do fid
		# Write header
		writeatmosph_head(fid,size(data,1),Extinction,hCritS);
		# Write data
		for i = 1:size(dataout,1)
			# Write date-index
			@printf(fid,"%11g",i);
			# add data
			for j in [:Prec,:rSoil,:rRoot,:hCritA,:rB,:hB,:ht]
				if haskey(dataout,j)
					@printf(fid,"%12g",dataout[j][i]);
				else # set missing columns to zero
					@printf(fid,"%12g",0);
				end
			end
			@printf(fid,"\n");
		end
		# add footer
		@printf(fid,"end*** END OF INPUT FILE 'ATMOSPH.IN' **********************************\n");
	end
end

"""
auxiliary function to write fixed header
"""
function writeatmosph_head(fid::IOStream,l::Int,extinc::Float64,h::Float64)
	@printf(fid,"Pcp_File_Version=4\n");
	@printf(fid,"*** BLOCK I: ATMOSPHERIC INFORMATION  ");
	for i in 1:34 @printf(fid,"*");end
	@printf(fid,"\n   MaxAL                    (MaxAL = number of atmospheric data-records)\n")
	@printf(fid,"   %i\n",l);
	@printf(fid," DailyVar  SinusVar  lLay  lBCCycles lInterc lDummy  lDummy  lDummy  lDummy  lDummy\n");
	if extinc > -1e-6
		@printf(fid,"       f       f       t       f       f       f       f       f       f       f\n")
		@printf(fid," Extinction\n   %.6g\n",extinc);
	else
		@printf(fid,"       f       f       f       f       f       f       f       f       f       f\n")
	end
	@printf(fid," hCritS                 (max. allowed pressure head at the soil surface)\n");
	@printf(fid,"   %.6g\n",h);
	@printf(fid,"       tAtm        Prec       rSoil       rRoot      hCritA");
	@printf(fid,"          rB          hB          ht      RootDepth\n");
end

"""
	writeprofile1d(nodeinfo,fileout)
Write Hydrus1D profile (nodal) file. Suitable only for pure water flow simulation

**Input**
soilinfo: dataframe containg information on:
* :start = soil layer starting depth
* :stop = soil layer end depth
* :res = vertical resolution (constant sampling)
* :h = Initial value of the pressure head
* :Mat = index of the material
* :Lay = subregion number assigned to nodes within the soil layer

fileout: output file name
iObs: list (vector) of the observation nodes for which values of the pressure head & the water content are printed

> No information about temperature or concentrations is used! Hydrus-1D 4.16.0110

**Example**
```
soilinfo = DataFrame(start=[0],stop=[10],res=[0.01],h=[100],Mat=[5],Lay=[1])
output_file = "test/output/profile1d_data.in"
print_nodes = [1,2,3];
writeprofile1d(soilinfo,output_file,iObs=print_nodes);
```
"""
function writeprofile1d(soilinfo::DataFrame,fileout::String;iObs=[0])
	open(fileout,"w") do fid
		# write header
		@printf(fid,"    2\n");# fixed number for "fixed" nodes
		@printf(fid,"%5g%15g%15g%15g\n",1,soilinfo[:start][1],1,1);
		@printf(fid,"%5g%15g%15g%15g\n",2,-soilinfo[:stop][end],1,1);
		@printf(fid,"%5g%5g%5g%5g",getnumofnodes(soilinfo),0,0,1);
		@printf(fid," x         h       Mat  Lay      Beta           Axz            ");
		@printf(fid,"Bxz            Dxz            Temp          Conc           SConc\n");
		# Write nodes
		c = 1;
		for i in 1:size(soilinfo,1)
			n = soilinfo[:start][i]:soilinfo[:res][i]:soilinfo[:stop][i];
			for j in n
				@printf(fid,"%5g%15g%15g%5g%5g",
						c,-j,soilinfo[:h][i],soilinfo[:Mat][i],soilinfo[:Lay][i]);
				# add constant values
				@printf(fid,"  0.000000e+000  1.000000e+000  1.000000e+000  1.000000e+000              \n");
				c += 1; # count nodes
			end
		end
		# add footer
		if iObs[1] != 0
			@printf(fid,"%5g\n",length(iObs));
			for i in iObs
				@printf(fid,"%5g",i)
			end
			@printf(fid,"\n");
		else
			@printf(fid,"    0\n");
		end
	end
end

"""
auxiliary function to get total number of observation points
"""
function getnumofnodes(soilinfo)
	c = 0;
	for i in 1:size(soilinfo,1)
		for j in soilinfo[:start][i]:soilinfo[:res][i]:soilinfo[:stop][i]
			c += 1; # count nodes
		end
	end
	return c
end

"""
	obnode = readhydrus1d_obsnode(filein,paramout)
Read Hydrus1D observation node output

**Input**
* filein: input file name
* paramout: what parameter should be returned (theta,h or Flux)

**Output**
obnode: dataframe containg:
* :time = time index
* :paramoutX = parameter value for node number X

> Designed only for Hydrus1D with water fluxes only! Hydrus-1D 4.16.0110

**Example**
```
input_file = "test/input/hydrus1d_Obs_Node.out"
obnode = readhydrus1d_obsnode(input_file,paramout=:theta)
```
"""
function readhydrus1d_obsnode(filein::String;paramout::Symbol=:theta)
	# read all data
	dataall = readdlm(filein,skipstart=11,comments=true,comment_char='e');
	obsnodes = getnodenumber(filein,paramout);
	dataout = DataFrame(time=dataall[:,1]);
	if paramout == :h
		col = 2;
	elseif paramout == :Flux
		col = 4;
	else
		col = 3;
	end
	for (i,v) in enumerate(obsnodes)
		dataout[v] = dataall[:,col+(i-1)*3];
	end
	return dataout;
end

"""
	atm = readatmosph(filein)
Read Hydrus1D ATMOSPH.IN file

**Input**
* filein: input file name

**Output**
obnode: dataframe containg:
* :time = time index
* :param = parameter name

> Designed only for Hydrus1D Hydrus-1D 4.16.0110

**Example**
```
input_file = "test/input/hydrus1d_atmosph.in"
atm = readatmosph(input_file)
```
"""
function readatmosph(filein::String)
	nh = headlines(filein,"tAtm");
	temp = readdlm(filein,skipstart=nh-1);
	out = DataFrame(time=temp[2:end-1,1]);
	for (i,v) in enumerate(temp[1,2:end])
		out[Symbol(v)] = eltype(temp[2,i+1])==Char ?
						zeros(Float64,length(temp[2:end-1,1])).*NaN :
						convert(Vector{Float64},temp[2:end-1,i+1])
	end
	return out
end

"""
Aux function to count number of header lines (up to a given string)

**Example**
```
filein = "f:/mikolaj/code/data_processing/sites/aggo/hydro/hydrus/AGGO/ATMOSPH.IN";
nh = headlines(filein,"tAtm")
```
"""
function headlines(filein::String,flag::String)
	c = 0;
	open(filein,"r") do fid
		row = readline(fid);
		while !occursin(flag,row)
			row = readline(fid);
			c += 1;
			if eof(fid)
				c = 0; break
			end
		end
	end
	return c+1
end

"""
auxiliary function to read node numbers
"""
function getnodenumber(filein::String,paramout::Symbol)
	obsnodes = Vector{Symbol}();
	# read node numbers
	open(filein,"r") do fid
		row = "";
		for i in 1:9
			row = readline(fid);
		end
		obsnodes = parsenodenumber(row,paramout);
	end
	return obsnodes;
end

"""
auxiliary function to extract numbers from string
"""
function parsenodenumber(row::String,paramout::Symbol)
	temp = split(row,"Node(");
	c = 1000; # max obs node number in the hydrusFile is 999 (above just ***)
	out = Vector{Symbol}();
	for i in temp[2:end] # starts with empty field (see split)
		if !occursin("*",i) # numbers below 1000
			obsnode = Meta.parse(split(i,")")[1]) # ends with ')'
		else
			obsnode = c;
			c += 1;
		end
		out = vcat(out,Symbol(string(paramout)*string(obsnode)));
	end
	return out
end

"""
	obnode = readhydrus1d_nedinf(filein,paramout)
Read Hydrus1D Node Info file (Nod_inf.out)

**Input**
* filein: input file name
* paramout: what parameter should be returned (all (default), theta, h or k)

**Output**
theta,k,h: dataframe containg:
* :time = time index
* :nodeX = valus for node number X

> Designed only for Hydrus1D with water fluxes only!

**Example**
```
input_file = "test/input/hydrus1d_Nod_Inf.out"
moisture = readhydrus1d_nedinf(input_file,paramout=:theta)
# moisture,k,h = readhydrus1d_nedinf(input_file)
```
"""
function readhydrus1d_nodinf(filein;paramout::Symbol=:all)
	# declare output
	timeout = -1;
	h = Matrix{Float64}(undef,0,0);
	theta = Matrix{Float64}(undef,0,0);
	k = Matrix{Float64}(undef,0,0);
	node = Vector{Int}();
	depth = Vector{Float64}();
	# read header
	open(filein,"r") do fid
		row = readhydrus1d_nodinf_head(fid);
		while !eof(fid)
			timeblock,datablock = readhydrus1d_nodinf_block(fid,row);
			if typeof(timeout)==Int # initial run
				timeout = timeblock;
				h = datablock[:,3]; # get Heat values (fixed position)
				theta = datablock[:,4];
				k = datablock[:,5]; # get hydraulic conductivity values (fixed position)
				node = round.(Int,datablock[:,1]); # read nodes and depth only once
				depth = datablock[:,2];
			else
				timeout = vcat(timeout,timeblock);
				h = hcat(h,datablock[:,3]);
				theta = hcat(theta,datablock[:,4]);
				k = hcat(k,datablock[:,5]);
			end
			row = readline(fid); # to reach EOF after last node info block
		end
	end
	if paramout == :theta # could not pass "paramout" as input
		return readhydrus1d_nodinf_df(timeout,node,theta)
	elseif paramout == :k
 		return readhydrus1d_nodinf_df(timeout,node,k)
	elseif paramout == :h
 		return readhydrus1d_nodinf_df(timeout,node,h)
	else # return 3 dataframes (default)
		return readhydrus1d_nodinf_df(timeout,node,theta),
				readhydrus1d_nodinf_df(timeout,node,k),
				readhydrus1d_nodinf_df(timeout,node,h)
    end
end

"""
auxiliary function to read time and data for each block
"""
function readhydrus1d_nodinf_block(fid,row)
	# find time stamp
	while !occursin("Time:",row)
		row = readline(fid);
	end
	timeout = Meta.parse(split(row,":")[2])
	# ignore header for each time step
	row = readhydrus1d_nodinf_head(fid);
	# read data
	datanode = readhydrus1d_nodinf_data(fid);
	return timeout,datanode
end

"""
auxiliary function to read file header
"""
function readhydrus1d_nodinf_head(fid)
	row = " ";
	for i in 1:5
		row = readline(fid);
	end
	return row;
end

"""
auxiliary function to get data for current block
"""
function readhydrus1d_nodinf_data(fid)
	# stack the data to a matrix
	datanode = Matrix{Float64}(undef,1,11);
	row = readline(fid);
	while !occursin("end",row)
		datanode = vcat(datanode,row |> split |> x -> Base.parse.(Float64,x) |> transpose);
		row = readline(fid);
	end
	return datanode[2:end,:]; # first line is a dummy used for declaration
end

"""
auxiliary function to convert matrix to dataframe
"""
function readhydrus1d_nodinf_df(timeout,nodes,dataout)
	df = DataFrame(time = timeout);
	for (i,v) in enumerate(nodes)
		temp = Symbol("node"*string(v));
		df[temp] = dataout[i,:];
	end
	return df
end

"""
	corr_hydrus1d_obsnode(file_obs_node,file_profile)
Correct Hydrus1D Observation node file if this does not contain all node numbers
in the header. This is motly the case if more then 10 observation nodes are
selected (manually) in the profile settings.

**Input**
* file_obs_node: Observation node file (mostly "Obs_Node.out"). The header of this file will be overwritten
* file_profile: profile settings file (mostly "PROFILE.DAT"). Will be used to get full row of Node IDs

**Example**
```
file_obs_node = "f:/mikolaj/code/data_processing/sites/aggo/hydro/model/hydrus/AGGO/Obs_Node.out"
file_profile = "f:/mikolaj/code/data_processing/sites/aggo/hydro/model/hydrus/AGGO/PROFILE.DAT"
FileTools.corr_hydrus1d_obsnode(file_obs_node,file_profile)
```
"""
function corr_hydrus1d_obsnode(file_obs_node::String,file_profile::String)
	fileout = "temp_Obs_Node.out";

	## Get node numbers
	temp = ""
	fid = open(file_profile,"r");
	node_id = fid |> readlines |> x->x[end] |> split |> x-> Base.parse.(Int,x)
	close(fid)

	## Write with new Node Info
	open(file_obs_node,"r") do fid
		fid_out = open(fileout,"w");
		while !eof(fid)
			row = readline(fid);
			if occursin("Node(",row)
				for i in node_id
					@printf(fid_out,"                      Node(%3i)",i)
				end
			else
				@printf(fid_out,"%s",row);
			end
			@printf(fid_out,"\n");
		end
		close(fid_out)
	end
	cp(fileout,file_obs_node,force=true);
	rm(fileout);
end