#!/usr/bin/python

from math import *
import numpy as np
import Manyo as m
import Domain

####    linear combination of gaussian    ####
def dist(x, n, a, c, w):
    sum=0.0
    for i in range(n):
        sum = sum + a[i]*exp(-1.0*((x-c[i])/w[i])**2)
    return sum

####    sign function    ####
def sign(r):
    if r > 0.0:
        s = 1.0
    elif r == 0.0:
        s = 0.0
    else:
        s = -1.0
    return s

####    initialize an ElementContainer    ####
def initElementContainer(xmin, xmax, nDiv):

    bin = m.MakeDoubleVector(nDiv+1)
    delta = (xmax - xmin)/nDiv
    for i in range(nDiv+1):
        bin[i] = xmin + delta*i

    xc = m.MakeDoubleVector(nDiv)
    for i in range(nDiv):
        xc[i] = (bin[i] + bin[i+1])/2.0

    nPeak=1
    a=m.MakeDoubleVector(nPeak)
    c=m.MakeDoubleVector(nPeak)
    w=m.MakeDoubleVector(nPeak)
    a[0]=100000.0
    c[0]=7.5
    w[0]=2.5
    y = m.MakeDoubleVector(nDiv)
    e = m.MakeDoubleVector(nDiv)
    for i in range(nDiv):
        p = dist(xc[i], nPeak, a, c, w)
        q = sign(np.random.rand(1)-0.5)*(p/10.0)*sqrt(-1.0*log(np.random.rand(1)))
        y[i] = p + q
        e[i] = p/10.0

    ec = m.ElementContainer()
    ec.AddToHeader("run number", 1)
    ec.AddToHeader("level",      1)
    ec.AddToHeader("Inst.",      "manyo")
    ec.Add("TOF",       bin, "sec." )
    ec.Add("Intensity", y,   "count")
    ec.Add("Error",     e,   "count")
    ec.SetKeys("TOF", "Intensity", "Error")

    return ec

def outputElementContainer(src):
    bin = src.Put(src.PutXKey())
    y   = src.Put(src.PutYKey())
    e   = src.Put(src.PutEKey())

    print str("No.").rjust(4), str("----------- bin -----------").rjust(27), str("xc").rjust(10), str("Intensity").rjust(23), str("error").rjust(23)
    for i in range(src.PutSize(src.PutYKey())):
         print str(i).rjust(4), "[", str(bin[i]).rjust(10), ",", str(bin[i+1]).rjust(10), ")", str((bin[i]+bin[i+1])/2.0).rjust(10), str(y[i]).rjust(23), str(e[i]).rjust(23)

####    main routine    ####
xmin = 0.0
xmax = 15.0
nDiv = 1500
src = initElementContainer(xmin, xmax, nDiv)
#outputElementContainer(src)

domain = Domain.Domain()
domain.setSource(src)
domain.setRange(0, src.PutSize(src.PutYKey())-1)
print "Bound                [", str(domain.getLowerBound()).rjust(10),      ",", str(domain.getUpperBound()).rjust(10),      ")"
print "BinBoundID           [", str(domain.getLowerBinBoundID()).rjust(10), ",", str(domain.getUpperBinBoundID()).rjust(10), ")"
print "BinID                [", str(domain.getLowerBinID()).rjust(10),      ",", str(domain.getUpperBinID()).rjust(10),      "]"
print "BoundID (deprecated) [", str(domain.getLowerBoundID()).rjust(10),    ",", str(domain.getUpperBoundID()).rjust(10),    "]"
print "number of bins: ", domain.getNumberOfBin()
bin=domain.getBin()
centers=domain.createXC()

for i in range(domain.getNumberOfBin()):
    print i, "[", str(bin[i]).rjust(5), ", ", str(bin[i+1]).rjust(5), "] ", centers[i]

#print "type of the domain", domain.getType()
#domain.setType(Domain.Domain.OO)
#print "type of the domain", domain.getType()

