# This file is part of Dyna.
#
# Dyna is a free open source 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2008-present CNRS, stephane.grenier@neel.cnrs.fr
"""
ExperimentClass
"""
import numpy as np
from dyna.functions.Functions import F0, F0F1Ref
# import scipy.constants as cst
[docs]
class Experiment :
r"""
a simulation ("sim") is an instance of this class,
it creates the attributes with memory allocations to the calculations
Methods:
Alloc
Attributes :
Formalism
polarizations
Pol_in_state
Pol_out_state
Pol_in
Pol_out
Data
DataWeight
DataName
Energy
Angle
FixQ
EffXIntervall
SampleLength
BeamThickness
CalcNorm
CalcBkg
CalcXShift
DataNorm
DataBkg
DataXShift
Mag_or_Pol_InvertedToggle
LinLogToggle
XRange
AngleRangeRad
EnergyRange
RefCalc
RefPost
TransCalc
TransPost
RefCalcPhi
RefPostPhi
TransCalcPhi
TransPostPhi
Imprint
"""
def __init__(self):
# DEFINING FUNCTION TO USE
self._FormalismList = {0: F0, # ascan parrat
1: F0, # escan parrat
2: F0F1Ref, # ascan elzo
3: F0F1Ref}# escan elzo
self.Formalism = 0
# DEFINING POLARIZATION
self.PolarizationIndex = {0: 'unpolarized',
1: 'circ +',
2: 'circ -',
3: 'sigma',
4: 'pi'}
self.Polarizations = {0: np.array([[np.sqrt(.5)],
[np.sqrt(.5)]], dtype=complex),
1: np.array([[-np.sqrt(.5)],
[-1j*np.sqrt(.5)]], dtype=complex),
2: np.array([[ np.sqrt(.5)],
[-1j*np.sqrt(.5)]], dtype=complex),
3: np.array([[1+0.j], [0.j]], dtype=complex),
4: np.array([[0.j], [1+0.j]], dtype=complex)}
self.Pol_in_index = 3 # index for experiment gui
self.Pol_out_index = 0 # index for experiment gui
self.Pol_in = self.Polarizations[self.Pol_in_index]
self.Pol_out = self.Polarizations[self.Pol_out_index]
# DATA
self.Data = np.array([])
self.DataWeight = 1 # weight for refinements
self.DataName = ""
# MEASUREMENT PARAMETERS
self.Energy = [8047, 9000, 1, 0] # ini, final, step, resolution correction
self.Angle = [0.001, 2, .002, 0]
self.FixQ = [2 * np.sin(np.deg2rad(self.Angle[0])) * 8047 / 12.39842]
self.EffXIntervall = [self.Angle[0], self.Angle[1]] # for optimization
self.SampleLength = 100
self.BeamThickness = 1 # sin th * Length/Thick
# ADJUSTMENTS
self.CalcNorm = [1e-2, 1, 10]
self.CalcBkg = [0, 0, 1e-3]
self.CalcXShift = [-20 ,0, 20]
self.DataNorm = [1e-2, 1, 1e2]
self.DataBkg = [0, 0, 100]
self.DataXShift = [-20, 0, 20]
# plot preferences for the simulation
self.Mag_or_Pol_InvertedToggle = True # could go in a plot class
self.LinLogToggle = False # log scale by default
self.ThetaQzToggle = False # theta unit by default
self.RatioReflectivityToggle = False # Reflectivity by default
self.Alloc(False)
def __str__(self):
"""String representation of this class"""
class_str = 'Describes one measurements, angular or energy scan\n\n'
return class_str
[docs]
def SetPolFunc(self, _Pol_index):
self.Pol_in_index = _Pol_index[0]
self.Pol_out_index = _Pol_index[1]
self.Pol_in = self.Polarizations[_Pol_index[0]]
self.Pol_out = np.conjugate(self.Polarizations[_Pol_index[1]])
return self.Pol_in, self.Pol_out
[docs]
def Alloc(self, _OptimFlag) -> None :
"""
Memory allocation used in calculations + calculates sc. factors
Defining Angle and Energy ranges, array size depends on formalisms
values depend on data or from GUI
sim.EnergyRange and sim.AngleRange are determined by GUI or data
Data are usualy as column x, y so format for calculations are the same
"""
self.Func = self._FormalismList[self.Formalism]
# IF OPTIMIZATION THEN XPOINTS FROM DATA
if _OptimFlag :
self.XRange = self.Data[:,0] + self.DataXShift[1] - self.CalcXShift[1]
#.AngleRangeRad = np.pi / 180 * self.XRange
if self.Angle[3]>0: #angular resolution
self.XRange = np.append(np.append(self.XRange, self.XRange-self.Angle[3]), self.XRange+self.Angle[3])
#self.AngleRangeRad = np.pi / 180 * self.XRange[:int(len(self.XRange)/3)]
# IF FIX ENERGY SIMULATION "ASCAN"
if self.Formalism in (0,2):
if not _OptimFlag :
self.XRange = np.linspace(self.Angle[0], self.Angle[1],
int((self.Angle[1] - self.Angle[0])/self.Angle[2]) + 1)
#self.AngleRangeRad = np.pi / 180 * self.XRange
if self.Angle[3]>0: #angular resolution
self.XRange = np.append(np.append(self.XRange, self.XRange-self.Angle[3]), self.XRange+self.Angle[3])
#self.AngleRangeRad = np.pi / 180 * self.XRange[:int(len(self.XRange)/3)]
self.AngleRangeRad = np.pi / 180 * self.XRange
self.EnergyRange = self.Energy[0] * np.ones(1)
# IF FIX ANGLE SIMULATION "ESCAN"
if self.Formalism in (1,3): # Fix Angle
if not _OptimFlag :
self.XRange = np.linspace(self.Energy[0], self.Energy[1],
int((self.Energy[1] - self.Energy[0]) / self.Energy[2]) + 1)
self.AngleRangeRad = np.pi / 180 * self.Angle[0] * np.ones(1)
self.EnergyRange = self.XRange
# IF FIX MAGNETIC SIMULATION, ADD REVERSED FIELD POLARIZATION TO ALLOCATION
if self.Formalism in (2,3):
self.RefCalcPhi = np.zeros(len(self.XRange))
self.TransCalcPhi = np.zeros(len(self.XRange))
if self.Angle[3]>0 : #angular resolution
self.RefPostPhi = np.zeros(int(len(self.XRange)/3))
self.TransPostPhi = np.zeros(int(len(self.XRange)/3))
else :
self.RefPostPhi = np.zeros(len(self.XRange))
self.TransPostPhi = np.zeros(len(self.XRange))
# Calc for F0 or first magnetization.
self.RefCalc = np.zeros(len(self.XRange))
self.TransCalc = np.zeros(len(self.XRange))
if self.Angle[3]>0:
self.RefPost = np.zeros(int(len(self.XRange)/3))
self.TransPost = np.zeros(int(len(self.XRange)/3))
self.Imprint = np.minimum(np.sin(self.AngleRangeRad[:int(len(self.XRange)/3)]) * self.SampleLength/(self.BeamThickness), 1)
else :
self.Imprint = np.minimum(np.sin(self.AngleRangeRad) * self.SampleLength/(self.BeamThickness), 1)
self.RefPost = np.zeros(len(self.XRange))
self.TransPost = np.zeros(len(self.XRange))
# self.Imprint = np.minimum(np.sin(self.AngleRangeRad + 1e-5) * self.SampleLength/(self.BeamThickness + 1e-4), 1)
self.Imprint = self.Imprint.reshape((len(self.Imprint),1)) # ugly line to change from col to line