Source code for dyna.ExperimentClass

# 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