#!/usr/bin/env python

"""main Absorb routines
   Copyright: 2009, Robert B. Von Dreele (Argonne National Laboratory)
"""
from __future__ import division, print_function
import math
import sys
import wx
# the next line removes the need for pythonw. Thanks to Matt Newville!
# appears unneaded from wx 4.2.1 on
if sys.platform.lower() == 'darwin': wx.PyApp.IsDisplayAvailable = lambda _: True
import numpy as np
import sys
import matplotlib as mpl
from . import GSASIIpath
from . import GSASIIElem as G2elem
from . import GSASIIElemGUI as G2elemGUI
from . import GSASIIctrlGUI as G2G
from . import GSASIIpwd as G2pwd

try:
    wx.NewIdRef
    wx.NewId = wx.NewIdRef
except AttributeError:
    pass

Gktheta = chr(0x3b8)
Gklambda = chr(0x3bb)
GkDelta = chr(0x0394)
Pwr10 = chr(0x0b9)+chr(0x2070)
Pwr20 = chr(0x0b2)+chr(0x2070)
Pwrm1 = chr(0x207b)+chr(0x0b9)
Pwrm2 = chr(0x207b)+chr(0x0b2)
Pwrm6 = chr(0x207b)+chr(0x2076)
Pwrm4 = chr(0x207b)+chr(0x2074)
Angstr = chr(0x00c5)
Gkmu = chr(0x3bc)
Pwr3 = chr(0x0b3)
Pwr4 = chr(0x2074)
Pwr20 = chr(0x0b2)+chr(0x0b0)
Pwrm1 = chr(0x207b)+chr(0x0b9)

[wxID_CHOICE1, wxID_SPINTEXT1, wxID_SPINTEXT2, wxID_SPINTEXT3, wxID_SPINTEXT4,
 wxID_RESULTS,wxID_SLIDER1, wxID_SPINBUTTON, wxID_NUMELEM, wxID_SPINTEXT5,wxID_SPINTEXT6,
] = [wx.NewId() for _init_ctrls in range(11)]

[wxID_EXIT, wxID_DELETE, wxID_NEW,
] = [wx.NewId() for _init_coll_ABSORB_Items in range(3)]

[wxID_KALPHAAGKA, wxID_KALPHACOKA, wxID_KALPHACRKA,
 wxID_KALPHACUKA, wxID_KALPHAFEKA, wxID_KALPHAMNKA,
 wxID_KALPHAMOKA, wxID_KALPHANIKA, wxID_KALPHAZNKA,
wxID_KALPHAGAKA,wxID_KALPHAINKA,
] = [wx.NewId() for _init_coll_KALPHA_Items in range(11)]

[wxID_ABSORBABOUT] = [wx.NewId() for _init_coll_ABOUT_Items in range(1)]

class Absorb(wx.Frame):
    '''Creates a frame where input for absorption calculation is supplied
    '''
    Elems = []
    Wave = 1.5405      #CuKa default
    Kev = 12.397639    #keV for 1A x-rays
    for arg in sys.argv:
        if '-w' in arg:
            Wave = float(arg.split('-w')[1])
        elif '-e' in arg:
            E = float(arg.split('-e')[1])
            Wave = Kev/E
        elif '-h' in arg:
            print ('''
Absorb.py can take the following arguments:
-h   -  this help listing
-wv  -  set default wavelength to v, e.g. -w1.54 sets wavelength to 1.54A
-ev  -  set default energy to v, e.g. -e27 sets energy to 27keV
without arguments Absorb uses CuKa as default (Wave=1.54052A, E=8.0478keV)
''')
            sys.exit()
    Wmin = 0.05        #wavelength range
    Wmax = 3.0
    Wres = 0.004094    #plot resolution step size as const delta-lam/lam - gives 1000 steps for Wmin to Wmax
    Eres = 1.5e-4      #typical energy resolution for synchrotron x-ray sources
    Energy = Kev/Wave
    ifWave = True
    Volume = 0
    ifVol = False
    Zcell = 1
    Pack = 0.50
    Radius = 0.4
    muT = 0.0
    muR = 0.0
    def _init_coll_ABOUT_Items(self, parent):

        parent.Append(wxID_ABSORBABOUT,'About')
        self.Bind(wx.EVT_MENU, self.OnABOUTItems0Menu, id=wxID_ABSORBABOUT)

    def _init_coll_menuBar1_Menus(self, parent):

        parent.Append(menu=self.ABSORB, title='Absorb')
        parent.Append(menu=self.KALPHA, title='Kalpha')
        parent.Append(menu=self.ABOUT, title='About')

    def _init_coll_KALPHA_Items(self, parent):
        "Set of characteristic radiation from sealed tube sources"
        def OnCrkaMenu(event):
            self.SetWaveEnergy(2.28962)

        def OnMnkaMenu(event):
            self.SetWaveEnergy(2.10174)

        def OnFekaMenu(event):
            self.SetWaveEnergy(1.93597)

        def OnCokaMenu(event):
            self.SetWaveEnergy(1.78896)

        def OnNikaMenu(event):
            self.SetWaveEnergy(1.65784)

        def OnCukaMenu(event):
            self.SetWaveEnergy(1.54052)

        def OnZnkaMenu(event):
            self.SetWaveEnergy(1.43510)

        def OnGakaMenu(event):
            self.SetWaveEnergy(1.34134)

        def OnMokaMenu(event):
            self.SetWaveEnergy(0.70926)

        def OnAgkaMenu(event):
            self.SetWaveEnergy(0.55936)

        def OnInkaMenu(event):
            self.SetWaveEnergy(0.51357)

        parent.Append(wxID_KALPHACRKA, 'CrKa')
        parent.Append(wxID_KALPHAMNKA, 'MnKa')
        parent.Append(wxID_KALPHAFEKA, 'FeKa')
        parent.Append(wxID_KALPHACOKA, 'CoKa')
        parent.Append(wxID_KALPHANIKA, 'NiKa')
        parent.Append(wxID_KALPHACUKA, 'CuKa')
        parent.Append(wxID_KALPHAZNKA, 'ZnKa')
        parent.Append(wxID_KALPHAGAKA, 'GaKa')
        parent.Append(wxID_KALPHAMOKA, 'MoKa')
        parent.Append(wxID_KALPHAAGKA, 'AgKa')
        parent.Append(wxID_KALPHAINKA, 'InKa')
        self.Bind(wx.EVT_MENU, OnCrkaMenu, id=wxID_KALPHACRKA)
        self.Bind(wx.EVT_MENU, OnMnkaMenu, id=wxID_KALPHAMNKA)
        self.Bind(wx.EVT_MENU, OnFekaMenu, id=wxID_KALPHAFEKA)
        self.Bind(wx.EVT_MENU, OnCokaMenu, id=wxID_KALPHACOKA)
        self.Bind(wx.EVT_MENU, OnNikaMenu, id=wxID_KALPHANIKA)
        self.Bind(wx.EVT_MENU, OnCukaMenu, id=wxID_KALPHACUKA)
        self.Bind(wx.EVT_MENU, OnZnkaMenu, id=wxID_KALPHAZNKA)
        self.Bind(wx.EVT_MENU, OnGakaMenu, id=wxID_KALPHAGAKA)
        self.Bind(wx.EVT_MENU, OnMokaMenu, id=wxID_KALPHAMOKA)
        self.Bind(wx.EVT_MENU, OnAgkaMenu, id=wxID_KALPHAAGKA)
        self.Bind(wx.EVT_MENU, OnInkaMenu, id=wxID_KALPHAINKA)

    def _init_coll_ABSORB_Items(self, parent):
        parent.Append(wxID_NEW,'&New Element','Add new element')
        self.Delete = parent.Append(wxID_DELETE,'&Delete Element','Delete an element')
        self.Delete.Enable(False)
        parent.Append(wxID_EXIT,'&Exit','Exit Fprime')
        self.Bind(wx.EVT_MENU, self.OnExitMenu, id=wxID_EXIT)
        self.Bind(wx.EVT_MENU, self.OnNewMenu, id=wxID_NEW)
        self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=wxID_DELETE)

    def _init_utils(self):
        self.ABSORB = wx.Menu(title='')

        self.KALPHA = wx.Menu(title='')
        self.KALPHA.SetEvtHandlerEnabled(True)

        self.ABOUT = wx.Menu(title='')

        self.menuBar1 = wx.MenuBar()

        self._init_coll_ABSORB_Items(self.ABSORB)
        self._init_coll_KALPHA_Items(self.KALPHA)
        self._init_coll_ABOUT_Items(self.ABOUT)
        self._init_coll_menuBar1_Menus(self.menuBar1)

    def _init_ctrls(self, parent):
        wx.Frame.__init__(self, parent=parent,
              size=wx.Size(500, 400),style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX, title='Absorb')
        self._init_utils()
        self.SetMenuBar(self.menuBar1)
        self.DrawPanel()

    def SetSize(self):
        w,h = self.GetClientSize()
        self.panel.SetSize(wx.Size(w,h))

    def DrawPanel(self):
        self.panel = wx.Panel(self)

        mainSizer = wx.BoxSizer(wx.VERTICAL)
        self.Results = wx.TextCtrl( parent=self.panel,
            style=wx.TE_MULTILINE|wx.TE_DONTWRAP )
        self.Results.SetEditable(False)
        mainSizer.Add(self.Results,1,wx.EXPAND)
        mainSizer.Add((10,15),0)

        if self.Elems:
            lablSizer = wx.BoxSizer(wx.HORIZONTAL)
            lablSizer.Add((5,10),0)
            lablSizer.Add(wx.StaticText(parent=self.panel,label='Chemical Formula:'),0,
                wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
            mainSizer.Add(lablSizer,0)
            mainSizer.Add((5,5),0)
            nRow = len(self.Elems)//5
            compSizer = wx.FlexGridSizer(nRow+1,10,0,0)
            for Elem in self.Elems:
                compSizer.Add(wx.StaticText(parent=self.panel,label="  "+Elem[0].capitalize(),
                    size=wx.Size(30,20)),0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
                numElem = wx.TextCtrl(id=wxID_NUMELEM,parent=self.panel,name=Elem[0],
                    size=wx.Size(70,20),value="%.2f" % (Elem[2]),style=wx.TE_PROCESS_ENTER)
                compSizer.Add(numElem,0)
                numElem.Bind(wx.EVT_TEXT_ENTER, self.OnNumElem, id=wxID_NUMELEM)
            mainSizer.Add(compSizer,0)
            mainSizer.Add((10,15),0)

        selSizer = wx.BoxSizer(wx.HORIZONTAL)
        selSizer.Add((5,10),0)
        selSizer.Add(wx.StaticText(parent=self.panel, label='Wavelength:'),0,wx.EXPAND)
        selSizer.Add((5,10),0)
        self.SpinText1 = wx.TextCtrl(id=wxID_SPINTEXT1, parent=self.panel,
            size=wx.Size(100,20), value = "%.4f" % (self.Wave),style=wx.TE_PROCESS_ENTER )
        selSizer.Add(self.SpinText1,0)
        selSizer.Add((5,10),0)
        self.SpinText1.Bind(wx.EVT_TEXT_ENTER, self.OnSpinText1, id=wxID_SPINTEXT1)

        selSizer.Add(wx.StaticText(parent=self.panel, label='Energy:'),0,wx.EXPAND)
        selSizer.Add((5,10),0)
        self.SpinText2 = wx.TextCtrl(id=wxID_SPINTEXT2, parent=self.panel,
            size=wx.Size(100,20), value = "%.4f" % (self.Energy),style=wx.TE_PROCESS_ENTER)
        selSizer.Add(self.SpinText2,0)
        selSizer.Add((5,10),0)
        self.SpinText2.Bind(wx.EVT_TEXT_ENTER, self.OnSpinText2, id=wxID_SPINTEXT2)

        selSizer.Add(wx.StaticText(parent=self.panel, label='Plot scale:'),0,wx.EXPAND)
        selSizer.Add((5,10),0)
        self.choice1 = wx.ComboBox(id=wxID_CHOICE1, parent=self.panel, value='Wavelength',
             choices=['Wavelength','Energy'],style=wx.CB_READONLY|wx.CB_DROPDOWN)
        selSizer.Add(self.choice1,0)
        selSizer.Add((10,10),0)
        self.choice1.Bind(wx.EVT_COMBOBOX, self.OnChoice1, id=wxID_CHOICE1)
        mainSizer.Add(selSizer,0)
        mainSizer.Add((10,10),0)

        slideSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.SpinButton = wx.SpinButton(id=wxID_SPINBUTTON, parent=self.panel,
              size=wx.Size(25,24), style=wx.SP_VERTICAL | wx.SP_ARROW_KEYS)
        slideSizer.Add(self.SpinButton)
        self.SpinButton.SetRange(-1,1)
        self.SpinButton.SetValue(0)
        self.SpinButton.Bind(wx.EVT_SPIN, self.OnSpinButton, id=wxID_SPINBUTTON)

        self.slider1 = G2G.G2Slider(id=wxID_SLIDER1, maxValue=int(1000.*self.Wmax),
            minValue=int(1000.*self.Wmin), parent=self.panel,style=wx.SL_HORIZONTAL,
            value=int(self.Wave*1000.), )
        slideSizer.Add(self.slider1,1,wx.EXPAND)
        self.slider1.Bind(wx.EVT_SLIDER, self.OnSlider1, id=wxID_SLIDER1)
        mainSizer.Add(slideSizer,0,wx.EXPAND)
        mainSizer.Add((10,10),0)

        cellSizer = wx.BoxSizer(wx.HORIZONTAL)
        cellSizer.Add((5,10),0)
        cellSizer.Add(wx.StaticText(parent=self.panel, label='Volume:'),0,wx.EXPAND)
        cellSizer.Add((5,10),0)
        self.SpinText3 = wx.TextCtrl(id=wxID_SPINTEXT3, parent=self.panel,
              size=wx.Size(100,20), value = "%.2f" % (self.Volume),style=wx.TE_PROCESS_ENTER )
        cellSizer.Add(self.SpinText3,0)
        cellSizer.Add((5,10),0)
        self.SpinText3.Bind(wx.EVT_TEXT_ENTER, self.OnSpinText3, id=wxID_SPINTEXT3)

        cellSizer.Add((5,10),0)
        cellSizer.Add(wx.StaticText(parent=self.panel, label='Z(vol):'),0,wx.EXPAND)
        cellSizer.Add((5,10),0)
        self.SpinText4 = wx.TextCtrl(id=wxID_SPINTEXT4, parent=self.panel,
              size=wx.Size(50,20), value = "%d" % (self.Zcell),style=wx.TE_PROCESS_ENTER )
        cellSizer.Add(self.SpinText4,0)
        cellSizer.Add((5,10),0)
        self.SpinText4.Bind(wx.EVT_TEXT_ENTER, self.OnSpinText4, id=wxID_SPINTEXT4)

        cellSizer.Add((5,10),0)
        cellSizer.Add(wx.StaticText(parent=self.panel, label='Sample R:'),0,wx.EXPAND)
        cellSizer.Add((5,10),0)
        self.SpinText5 = wx.TextCtrl(id=wxID_SPINTEXT5, parent=self.panel,
              size=wx.Size(50,20), value = "%.2f" % (self.Radius),style=wx.TE_PROCESS_ENTER )
        cellSizer.Add(self.SpinText5,0)
        cellSizer.Add((5,10),0)
        self.SpinText5.Bind(wx.EVT_TEXT_ENTER, self.OnSpinText5, id=wxID_SPINTEXT5)

        cellSizer.Add((5,10),0)
        cellSizer.Add(wx.StaticText(parent=self.panel, label='packing:'),0,wx.EXPAND)
        cellSizer.Add((5,10),0)
        self.SpinText6 = wx.TextCtrl(id=wxID_SPINTEXT6, parent=self.panel,
              size=wx.Size(50,20), value = "%.2f" % (self.Pack),style=wx.TE_PROCESS_ENTER )
        cellSizer.Add(self.SpinText6,0)
        cellSizer.Add((5,10),0)
        self.SpinText6.Bind(wx.EVT_TEXT_ENTER, self.OnSpinText6, id=wxID_SPINTEXT6)

        mainSizer.Add(cellSizer,0)
        mainSizer.Add((10,10),0)
        self.panel.SetSizer(mainSizer)
        self.panel.Fit()
        self.panel.GetParent().SetSize()

    def __init__(self, parent):
        self._init_ctrls(parent)
        self.parent = parent
        self.Lines = []
        self.Elems = []
        self.linePicked = None

    def OnExitMenu(self, event):
        self.parent.G2plotNB.Delete('Absorb')
        self.Close()
        self.Destroy()

    def OnNewMenu(self, event):
        ElList = []
        for Elem in self.Elems: ElList.append(Elem[0])
        PE = G2elemGUI.PickElements(self,ElList)
        if PE.ShowModal() == wx.ID_OK:
            Elem = PE.Elem
        PE.Destroy()
        if Elem:
            for El in Elem:
                ElemSym = El.strip().upper()
                if ElemSym not in ElList:
                    atomData = G2elem.GetAtomInfo(ElemSym.capitalize())
                    FormFactors = G2elem.GetFormFactorCoeff(ElemSym)
                    for FormFac in FormFactors:
                        FormSym = FormFac['Symbol'].strip()
                        if FormSym == ElemSym:
                            Z = FormFac['Z']                #At. No.
                            N = 1.                          #no atoms / formula unit
                            Orbs = G2elem.GetXsectionCoeff(ElemSym)
                            Elem = [ElemSym,Z,N,FormFac,Orbs,atomData]
                    self.Elems.append(Elem)
            self.ifVol = False
            self.Delete.Enable(True)
            self.panel.Destroy()
            self.DrawPanel()
            self.NewFPPlot = True
            self.SetWaveEnergy(self.Wave)

    def OnDeleteMenu(self, event):
        if len(self.Elems):
            ElList = []
            for Elem in self.Elems: ElList.append(Elem[0])
            S = []
            DE = G2elemGUI.DeleteElement(self,ElList)
            if DE.ShowModal() == wx.ID_OK:
                El = DE.GetDeleteElement().strip().upper()
                for Elem in self.Elems:
                    if Elem[0] != El:
                        S.append(Elem)
                self.Elems = S
                self.CalcFPPS()
                if not self.Elems:
                    self.Delete.Enable(False)
                self.panel.Destroy()
                self.DrawPanel()
                self.ifVol = False
                self.NewFPPlot = True
                self.SetWaveEnergy(self.Wave)

    def OnNumElem(self, event):
        for Elem in self.Elems:
            if event.GetEventObject().GetName() == Elem[0]:
                Elem[2] = float(event.GetEventObject().GetValue())
                event.GetEventObject().SetValue("%8.2f" % (Elem[2]))
                self.ifVol = False
            self.SetWaveEnergy(self.Wave)

    def OnSpinText1(self, event):
        self.SetWaveEnergy(float(self.SpinText1.GetValue()))

    def OnSpinText2(self, event):
        self.SetWaveEnergy(self.Kev/(float(self.SpinText2.GetValue())))

    def OnSpinText3(self,event):
        self.Volume = max(10.,float(self.SpinText3.GetValue()))
        self.ifVol = True
        self.SetWaveEnergy(self.Wave)

    def OnSpinText4(self,event):
        self.Zcell = max(1,float(self.SpinText4.GetValue()))
        self.SetWaveEnergy(self.Wave)

    def OnSpinText5(self, event):
        self.Radius = max(0.01,float(self.SpinText5.GetValue()))
        self.SetWaveEnergy(self.Wave)

    def OnSpinText6(self, event):
        self.Pack = min(1.0,max(0.01,float(self.SpinText6.GetValue())))
        self.SetWaveEnergy(self.Wave)

    def OnSpinButton(self, event):
        move = self.SpinButton.GetValue()/10000.
        self.Wave = min(max(self.Wave+move,self.Wmin),self.Wmax)
        self.SpinButton.SetValue(0)
        self.SetWaveEnergy(self.Wave)

    def OnSlider1(self, event):
        if self.ifWave:
            Wave = float(self.slider1.GetValue())/1000.
        else:
            Wave = self.Kev/(float(self.slider1.GetValue())/1000.)
        self.SetWaveEnergy(Wave)

    def SetWaveEnergy(self,Wave):
        self.Wave = Wave
        self.Energy = self.Kev/self.Wave
        self.Energy = round(self.Energy,4)
        E = self.Energy
        DE = E*self.Eres                         #smear by defined source resolution
        self.SpinText1.SetValue("%.4f" % (self.Wave))
        self.SpinText2.SetValue("%.4f" % (self.Energy))
        self.SpinText1.Update()
        self.SpinText2.Update()
        if self.ifWave:
            self.slider1.SetValue(int(1000.*self.Wave))
        else:
            self.slider1.SetValue(int(1000.*self.Energy))
        Text = ''
        if not self.ifVol:
            self.Volume = 0
            for Elem in self.Elems:
                self.Volume += 10.*Elem[2]
        muT = 0
        Mass = 0
        Fo = 0
        Fop = 0
        for Elem in self.Elems:
            Mass += self.Zcell*Elem[2]*Elem[5]['Mass']
            r1 = G2elem.FPcalc(Elem[4],E+DE)
            r2 = G2elem.FPcalc(Elem[4],E-DE)
            Els = Elem[0]
            Els = Els.ljust(2).lower().capitalize()
            mu = 0
            Fo += Elem[2]*Elem[1]
            if Elem[1] > 78 and self.Energy+DE > self.Kev/0.16:
                mu = self.Zcell*Elem[2]*(r1[2]+r2[2])/2.0
                Text += "%s\t%s%8.2f  %s%6s  %s%6.3f  %s%10.2f %s\n" %    (
                    'Element: '+str(Els),"N = ",Elem[2]," f'=",'not valid',
                    ' f"=',(r1[1]+r2[1])/2.0,' '+Gkmu+'=',mu,'barns')
            elif Elem[1] > 94 and self.Energy-DE < self.Kev/2.67:
                mu = 0
                Text += "%s\t%s%8.2f  %s%6s  %s%6s  %s%10s%s\n" %    (
                    'Element: '+str(Els),"N = ",Elem[2]," f'=",'not valid',
                    ' f"=','not valid',' '+Gkmu+'=',mu,'not valid')
            else:
                mu = self.Zcell*Elem[2]*(r1[2]+r2[2])/2.0
                Fop += Elem[2]*(Elem[1]+(r1[0]+r2[0])/2.0)
                Text += "%s\t%s%8.2f  %s%6.3f  %s%6.3f  %s%10.2f %s\n" %    (
                    'Element: '+str(Els),"N = ",Elem[2]," f'=",(r1[0]+r2[0])/2.0,
                    ' f"=',(r1[1]+r2[1])/2.0,' '+Gkmu+'=',mu,'barns')
            muT += mu
            self.muT = muT

        if self.Volume:
            self.muR = self.Radius*self.Pack*muT/(10.0*self.Volume)
            Text += "%s %s%10.4g %s" % ("Total",' '+Gkmu+' =',self.Pack*muT/self.Volume,'cm'+Pwrm1+', ')
            Text += "%s%10.4g%s" % ('Total '+Gkmu+'R =',self.muR,', ')
            Text += "%s%10.4f%s\n" % ('Transmission exp(-2'+Gkmu+'R) =', \
                100.0*math.exp(-2.*self.Radius*self.Pack*muT/(10.0*self.Volume)),'%')
            if muT > 0.:
                pene = 10./(self.Pack*muT/self.Volume)
                if pene > 0.01:
                    Text += "%s %10.4g mm\n"%("1/e (~27.2%) penetration depth = ",pene)
                else:
                    Text += "%s %10.4g %sm\n"%("1/e (~27.2%) penetration depth = ",1000.0*pene,Gkmu)
                Tth = np.array([0.0,140.0])
                Xabs = 1./G2pwd.Absorb('Cylinder',self.muR,Tth)
                Text += "%s %10.4g to %10.4g\n"%("Cylinder absorption correction extremes:",Xabs[0],Xabs[1])
            self.Results.SetValue(Text)
            den = Mass/(0.602*self.Volume)
            if self.ifVol:
                Text += '%s' % ('Theor. density =')
            else:
                Text += '%s' % ('Est. density =')
            Text += '%6.3f %s%.3f %s\n' % (den,'g/cm'+Pwr3+', Powder density =',self.Pack*den,'g/cm'+Pwr3)
            Text += '%s%10.2f%s\n'%('X-ray small angle scattering contrast',(28.179*Fo/self.Volume)**2,'*10'+Pwr20+'/cm'+Pwr4)
            if Fop:
                Text += '%s%10.2f%s\n'%('Anomalous X-ray small angle scattering contrast',(28.179*Fop/self.Volume)**2,'*10'+Pwr20+'/cm'+Pwr4)
            self.Results.SetValue(Text)
        self.Results.Update()
        self.SpinText3.SetValue("%.2f" % (self.Volume))
        self.SpinText3.Update()
        self.SpinText4.SetValue("%d" % (self.Zcell))
        self.SpinText4.Update()
        self.SpinText5.SetValue("%.2f" % (self.Radius))
        self.SpinText5.Update()
        self.SpinText6.SetValue("%.2f" % (self.Pack))
        self.SpinText6.Update()
        if len(self.Elems):
            self.CalcFPPS()
            self.UpDateAbsPlot(Wave,rePlot=True)

    def CalcFPPS(self):
        """generate f" curves for selected elements
           does constant delta-lambda/lambda steps over defined range
        """
        FPPS = []
        if self.Elems:
            wx.BeginBusyCursor()
            Corr = self.Zcell*self.Radius*self.Pack/(10.0*self.Volume)
            try:
                muT = []
                for iE,Elem in enumerate(self.Elems):
                    Els = Elem[0]
                    Els = Els = Els.ljust(2).lower().capitalize()
                    Wmin = self.Wmin
                    Wmax = self.Wmax
                    lWmin = math.log(Wmin)
                    N = int(round(math.log(Wmax/Wmin)/self.Wres))    #number of constant delta-lam/lam steps
                    I = range(N+1)
                    Ws = []
                    for i in I: Ws.append(math.exp(i*self.Wres+lWmin))
                    mus = []
                    Es = []
                    for j,W in enumerate(Ws):
                        E = self.Kev/W
                        DE = E*self.Eres                         #smear by defined source resolution
                        res1 = G2elem.FPcalc(Elem[4],E+DE)
                        res2 = G2elem.FPcalc(Elem[4],E-DE)
                        muR = Corr*Elem[2]*(res1[2]+res2[2])/2.0
                        mus.append(muR)
                        if iE:
                            muT[j] += muR
                        else:
                            muT.append(muR)
                        Es.append(E)
                    if self.ifWave:
                        Fpps = (Els,Ws,mus)
                    else:
                        Fpps = (Els,Es,mus)
                    FPPS.append(Fpps)
                if self.ifWave:
                    Fpps = ('Total',Ws,muT)
                else:
                    Fpps = ('Total',Es,muT)
                FPPS.append(Fpps)
            finally:
                wx.EndBusyCursor()
        self.FPPS = FPPS

    def OnChoice1(self, event):
        if event.GetString() == "Wavelength":
            self.ifWave = True
            self.NewFPPlot = True
            self.Wave = round(self.Wave,4)
            self.slider1.SetRange(int(1000.*self.Wmin),int(1000.*self.Wmax))
            self.slider1.SetValue(int(1000.*self.Wave))
            self.SpinText1.SetValue("%6.4f" % (self.Wave))
            self.SpinText2.SetValue("%7.4f" % (self.Energy))
        else:
            self.ifWave = False
            self.NewFPPlot = True
            Emin = self.Kev/self.Wmax
            Emax = self.Kev/self.Wmin
            self.Energy = round(self.Energy,4)
            self.slider1.SetRange(int(1000.*Emin),int(1000.*Emax))
            self.slider1.SetValue(int(1000.*self.Energy))
            self.SpinText1.SetValue("%6.4f" % (self.Wave))
            self.SpinText2.SetValue("%7.4f" % (self.Energy))
        if len(self.Elems):
            self.CalcFPPS()
            self.UpDateAbsPlot(self.Wave,rePlot=False)

    def OnKeyPress(self,event):
        if event.key == 'g':
            mpl.rcParams['axes.grid'] = not mpl.rcParams['axes.grid']
            self.UpDateAbsPlot(self.Wave,rePlot=False)

    def UpDateAbsPlot(self,Wave,rePlot=True):
        """Plot mu vs wavelength 0.05-3.0A"""
        xylim = []
        try:
            if rePlot:
                asb = self.Page.figure.get_axes()[1]
                xylim = asb.get_xlim(),asb.get_ylim()
            newPlot = False
        except:
            new,plotNum,self.Page,self.fplot,lim = self.parent.G2plotNB.FindPlotTab('Absorb','mpl')
            self.Page.canvas.mpl_connect('pick_event', self.OnPick)
            self.Page.canvas.mpl_connect('button_release_event', self.OnRelease)
            self.Page.canvas.mpl_connect('motion_notify_event', self.OnMotion)
            self.Page.canvas.mpl_connect('key_press_event', self.OnKeyPress)
            newPlot = True
            GS_kw = {'width_ratios':[1,1],}
            self.ax,self.bx = self.Page.figure.subplots(1,2,gridspec_kw=GS_kw)
        self.fplot.set_visible(False)
        self.Page.Choice = (' key press','g: toggle grid',)
        self.Page.keyPress = self.OnKeyPress
        self.ax.clear()
        self.bx.clear()
        self.ax.set_title('X-Ray Absorption',x=0,ha='left')
        self.ax.set_ylabel(r"$\mu R$",fontsize=14)
        self.bx.set_title(r"Cylinder abs. corr. for $\lambda= %.4f\AA$"%self.Wave,x=0,ha='left')
        self.bx.set_xlabel(r"$2\theta$",fontsize=14)
        Tth = np.arange(0.,140.0,0.1)
        Xabs = 1./G2pwd.Absorb('Cylinder',self.muR,Tth)
        self.bx.plot(Tth,Xabs)
        Ymin = 0.0
        Ymax = 0.0
        if self.FPPS:
            for Fpps in self.FPPS:
                Ymin = min(Ymin,min(Fpps[2]))
                Ymax = max(Ymax,max(Fpps[2]))
                fppsP1 = np.array(Fpps[1])
                fppsP2 = np.array(Fpps[2])
                self.ax.plot(fppsP1,fppsP2,label=r'$\mu R$ '+Fpps[0])
        if self.ifWave:
            self.ax.set_xlabel(r'$\mathsf{\lambda, \AA}$',fontsize=14)
            self.ax.axvline(x=Wave,picker=3,color='black')
        else:
            self.ax.set_xlabel(r'$\mathsf{E, keV}$',fontsize=14)
            self.ax.set_xscale('log')
            self.ax.axvline(x=self.Kev/Wave,picker=3,color='black')
        self.ax.axhline(y=1.0,color='b')
        self.ax.axhline(y=5.0,color='r')
        self.ax.set_ylim(Ymin,Ymax)
        if self.FPPS:
            self.ax.legend(loc='best')
        if newPlot:
            newPlot = False
            self.Page.canvas.draw()
        else:
            if rePlot:
                tb = self.Page.canvas.toolbar
                tb.push_current()
                self.ax.set_xlim(xylim[0])
                self.ax.set_ylim(xylim[1])
                xylim = []
                tb.push_current()
            self.Page.canvas.draw()

    def OnPick(self, event):
        self.linePicked = event.artist

    def OnMotion(self,event):
        xpos = event.xdata
        if xpos and xpos>0.1:
            ypos = event.ydata
            if self.ifWave:
                Wave = xpos
            else:
                Wave = self.Kev/xpos
            Wave = min(max(Wave,self.Wmin),self.Wmax)
            self.parent.G2plotNB.status.SetStatusText('Wavelength: %.4f, Energy: %.3f, %sR: %.3f'%(Wave,self.Kev/Wave,Gkmu,ypos),1)
        if self.linePicked:
            self.SetWaveEnergy(Wave)

    def OnRelease(self, event):
        if self.linePicked is None: return
        self.linePicked = None
        xpos = event.xdata
        if xpos:
            if self.ifWave:
                Wave = xpos
            else:
                Wave = self.Kev/xpos
            self.SetWaveEnergy(Wave)

    def OnABOUTItems0Menu(self, event):
        '''Displays the About window
        '''
        try:
            import wx.adv as wxadv  # AboutBox moved here in Phoenix
        except:
            wxadv = wx
        info = wxadv.AboutDialogInfo()
        info.Name = 'Absorb'
        info.Copyright = '''
Robert B. Von Dreele, 2009(C)
Argonne National Laboratory
This product includes software developed
by the UChicago Argonne, LLC, as
Operator of Argonne National Laboratory.        '''
        info.Description = '''
For calculating X-ray absorption factors to 250keV for cylindrical
powder samples; based on Fortran program Fprime of Cromer & Liberman
(D. T. Cromer and D. A. Liberman, Acta Cryst. (1981). A37, 267-268.)
corrected for Kissel & Pratt energy term; Jensen term not included
        '''
        wxadv.AboutBox(info)

if __name__ == "__main__":
    from . import GSASIIplot as G2plt
    app = wx.App()
    GSASIIpath.InvokeDebugOpts()
    frm = wx.Frame(None) # create a frame
    frm.Show(False)
    size = wx.Size(700,700)
    frm.plotFrame = wx.Frame(frm,-1,'GSASII Plots',size=size,
            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
    frm.plotFrame.Show()
    frm.G2plotNB = G2plt.G2PlotNoteBook(frm.plotFrame,G2frame=frm)
    abswin = Absorb(frm)
    abswin.Show()
    abswin.Bind(wx.EVT_WINDOW_DESTROY,lambda event: sys.exit())
    app.MainLoop()
