// Author: Egon Pavlica <http://www.ses-ng.si/~pavlica/>
#include "LDisorder.h"
#include "nrutil.h"
#include "nr.h"
#include <time.h>
#include <stdlib.h>
#include <iostream>
//________________________________________
// Simulation of hopping in dissordered
// sistem
//
// an exaple of simulation is in file
// final.cc. Full functionallity of this
// class is implemented in file hoppclient.cc
//
// with GetN() we get the time index (0..fmax-1)
// if the value is 0, the simulation didn't
// even started, if its value is equal to value
// returned by GetMax(), than the transient time
// is longer than recording time, since the time
// index could be used also to calculcate transient time
//
// The real time could be obtained also with
// GetTTime(). If value is -1 than particle is trapped
// and has not traveled to oposite electrode.
// if value is 0, than particle exited space in first jump
//
// with GetKTrack() and with GetETrack() we
// get recorded tracks of electron...
// first track is particle position index (k axis base cell index)
// (if someone needs z coordinate the index should
// be multiplied with LDataHeader::fbasez) vs time
// second track is particle energy (eV) vs time
// every array field correspond to time index. Realtime
// is calculated using LDataHeader::fresolution
// array size is defined with LDataHeader::fmax
//
// main function is Walk() and its clone WalkFast()
// with almost no output bla bla.
// for 2D simulation use e.g. SetWSpace(7,1,7) or SetWSpace(1,7,7)
// for 1D simulation use e.g. SetWSpace(1,1,7)
// ...before starting simulation
//
//
// Test(mode) is for testing purposes
//
// Note:
// - fprob zero-indexed
// - fktrack zero-indexed
// - fetrack zero-indexed
// - dont forget to SetTimeResolution()
//
// Logs:
//
// $Log: LDisorder.cc,v $
// Revision 1.12 2004/07/13 09:57:57 cvs
// found bug in tof normalization. solution is to multiply histogram with tof->Scale(data->fvt->GetEntries()/(Double_t)data->fN/(header->rpmax-header->rpmin)/header->fresolution); and then the tof is normalized! This bug was corrected and commited to cvs.
//
// Revision 1.11 2003/12/15 15:54:17 cvs
// i think i found a bug in SaveProperties(int), when saving old value.
//
// Revision 1.10 2003/11/11 17:33:03 cvs
// LServer upgraded
//
// Revision 1.9 2003/08/20 10:26:50 cvs
// Added scripts directory with two utilities now:
// modify_header which modify existing header and send it database
// deliver_header program and script which deliver header to clients
//
// libLComm was made ROOT compatible and GetBias(z) was added to LDataHeader
//
// Revision 1.8 2003/07/25 11:36:26 cvs
// simulation of IV measurements is done with iv program
// some minority fixes to LDisorder - corrected ft to match the recorded position
//
// Revision 1.7 2003/06/26 14:46:16 cvs
// found a bug in LSpace::GetEnergy() with fbias. Bug successfully resolved :)
//
// Revision 1.6 2003/06/26 13:26:05 cvs
// some bugs removed + some test methods implemented in LDisorder
//
// Revision 1.5 2003/06/26 11:24:25 cvs
// modified particle moving with LMiki and faster LDisorder operations
//
// Revision 1.4 2003/06/26 09:27:11 cvs
// added log fields...
//
ClassImp(LDisorder)
LDisorder::LDisorder():LMiki(){
//empty constructor
fe=0;
fspace=0;
fprob=0;
fetrack=0;
fktrack=0;
ft=0.0;
fN=0;
fprob=0;
SetTimeResolution(1.0);
SetMax(10000);
};
LDisorder::LDisorder(LSpace* space):LMiki(space){
//default constructor. Default working space set to 7x7x7
fe=0;
fspace=0;
fprob=0;
fetrack=0;
ftime=0.0;
fktrack=0;
ft=0.0;
fN=0;
fprob=0;
SetTimeResolution(1.0);
SetMax(10000);
};
LDisorder::~LDisorder(){
//default destructor
if (fprob) Tdelete(fprob,0);
if (fktrack) Tdelete(fktrack,0);
if (fetrack) Tdelete(fetrack,0);
}
void LDisorder::SetWSpace(const int a,const int b,const int c){
//set working space size-lattice sites that are included in probablility calculation
//prefered odd numbers!!
fWa=a,fWb=b;fWc=c;
fNprob=fWa*fWb*fWc;
if (fprob) Tdelete(fprob,0);
Tnew(fprob,0,fNprob);//for storing probability
fprob[0]=0.0; //this must be set, used in Walk time calculation
fWa2=fWa/2,fWb2=fWb/2,fWc2=fWc/2;
fWa2c=fWa/2+1,fWb2c=fWb/2+1,fWc2c=fWc/2+1;
idxexclude=fWb*fWc*fWa2+fWc*fWb2+fWc2+1;
if (fWa2==fWa2c) std::cerr<<"Error: SetWSpace(a) - odd number needed!n";
if (fWb2==fWb2c) std::cerr<<"Error: SetWSpace(b) - odd number needed!n";
if (fWc2==fWc2c) std::cerr<<"Error: SetWSpace(c) - odd number needed!n";
}
void LDisorder::SetMax(const long max){
//Set maximum number of records
//must be called before Walk() and similar methods
//which need fktrack and fetrack
if (!fktrack) fmax=max;
else std::cerr<<"Error: SetMax() called too late, ignored!n";
}
void LDisorder::SetTimeResolution(const float delta){
//Set time resolution of records
//must be called before Walk() and similar methods,
//where the particle track is recorded
if (!fN) ftime=delta;
else std::cerr<<"Error: SetTimeResolution() called too late, ignored!n";
}
void LDisorder::Init(){
//get fe,fspace,fwspace and fmonitor from LMiki class
if (!fe) fe=GetParticle();
if (!fspace) fspace=GetSpace();
if (!fktrack) Tnew(fktrack,0,fmax-1);
Tclear(fktrack,0,fmax-1);
if (!fetrack) Tnew(fetrack,0,fmax-1);
Tclear(fetrack,0,fmax-1);
ft=0; //time is measured from zero
fN=0;
if (!fprob) SetWSpace(7,7,7);
//this was in Probability
// boltzkT=ftemperature*1.3806503e-23;// J
boltzkTeV=8.617342e-5*ftemperature;// eV
}
void LDisorder::Walk(){
//do a disorder hopping simulation of the particle
//for more information get the report of this project.
//for further references get the article:
// H.Baessler:phys.stat.sol.B 175, 15, 1993.
//
//Note:
// If monitor is set, then it outputs to monitor.
// this is nice but VERY slow
Init();//linking to other classes
//physical properties here
//I set them elsewhere
if (fverbose) std::cout<<"Disorder Hopping simulationn";
//initial savings
SaveProperties(1);//first position
if (!fspace->IsInside(fe)) return;
while (1){
if (fN>=fmax) break;//out of time
if (ft<=fe->time) {
SaveProperties(1);
continue;
}
if (!Step()) break;//out of space
}
ft-=ftime;//since the ft points to the time where should store next
//some verbosity
if (fN<fmax)
if (fverbose)
std::cout<<"Particle exited the space at "<<fe->i<<","<<fe->j<<","<<fe->k<<std::endl;
else {
if (fverbose)
std::cout<<"Particle timeout"<<std::endl;
}
}
int LDisorder::Where(const float a) const {
//return position k in array, which satisfies arr[k-1]<a<=arr[k]
//used with fprob
unsigned long ju=fNprob+1,jm,jl=0;
//if(a>fprob[fNprob-1]) return fNprob;//obsolete
if(a<=fprob[1]) return 1;
while(ju-jl>1){
jm=(ju+jl)>>1;//compute midpoint
if(a>fprob[jm]) jl=jm; else ju=jm;
}
return ju;
}
long LDisorder::initseed() const{
//inits seed
long seed=-time(NULL);
//if (fverbose) std::cout<<"Seed: "<<seed<<std::endl;
return seed;
}
inline
int LDisorder::Step(){
//A single step in dissorder hopping simulation
//time is set as exponentially distributed deviate with average value of inverse of probability of jump
static long seed=initseed();//for random number generator
int idx;//unity index of lattice positions
int i0=fe->i-fWa2c;
int j0=fe->j-fWb2c;
int k0=fe->k-fWc2c;
float e1=fe->GetEnergy();//current energy
float e2,r,sum=0.0;
//calculate probabilities
for(int i=1;i<=fWa;i++)
for(int j=1;j<=fWb;j++)
for(int k=1;k<=fWc;k++){
idx=fWb*fWc*(i-1)+fWc*(j-1)+k;
if (idx!=idxexclude){//exclude sumation over the site of origin
e2=fspace->GetEnergy(i0+i,j0+j,k0+k);
r=fspace->Distance(idx);//to speed up
//r=fspace->Distance(i-fWa2c,j-fWb2c,k-fWc2c);
sum+=Probability(r,e1,e2);
fprob[idx]=sum;
} else fprob[idx]=sum; //so will never be selected in Where
}
idx=Where(sum*ran1(&seed));//where to jump?
//inverse tranformation
int x,z,y;
idx--;
x=idx/(fWb*fWc);
y=(idx-x*fWb*fWc)/fWc;
z=idx-x*fWb*fWc-y*fWc+1;
idx++;x++;y++;
// fe->time+=(expdev(&seed)*0.166667*sum*exp(2.0*fgamma));
//fe->time+=(expdev(&seed2)*0.166667*exp(2.0*fgamma));
fe->time+=(expdev(&seed)*sum/(fprob[idx]-fprob[idx-1]));//no scale
int answ=MoveTo(x-fWa2c,y-fWb2c,z-fWc2c);//move particle
if (fverbose) if (e1>fe->GetEnergy()) std::cout<<"."; else std::cout<<"*";//down the energy and up the energy
if (fverbose) std::cout<<"Time: "<<fe->time<<" Energy: "<<fe->GetEnergy()<<" eV Position: "<<fe->i<<","<<fe->j<<","<<fe->k<<std::endl;
return answ;
}
inline
float LDisorder::Probability(const float r,const float e1,const float e2) const{
//Miller-Abrahams probabiliry for jump of length r
//from energy e1 to energy e2 (in eV). fgamma, and ftemperature
//are used too. Here it is assumed, that electron
//orbitals are spherical. If not, the r must be vector!
//this is for HOLES!!!!!
float bla1=exp(-2.0*fgamma*r);
//this is in Init now
// boltzkT=ftemperature*1.3806503e-23;// J
// boltzkTeV=8.617342e-5*ftemperature;// eV
//FOR HOLES
if (e1>e2) return bla1*exp((e2-e1)/boltzkTeV);
return bla1;
//FOR ELECTRONS
// if (e2>e1) return bla1*exp((e1-e2)/boltzkTeV);
// return bla1;
}
inline
void LDisorder::SaveProperties(const int save){
//save particle properties (position,energy) and increment fN and ft
//if save=1 it save position else it copy previous
if (save)
SaveProperties(fe->k,fe->GetEnergy());
else
SaveProperties(fktrack[fN-1],fetrack[fN-1]);
}
inline
void LDisorder::SaveProperties(const float position,const float energy){
//save particle properties (position,energy) and increment fN and ft
fktrack[fN]=position;
fetrack[fN]=energy;
fN++;
ft+=ftime;
}
void LDisorder::WalkFast(){
//like LDisorder::Walk but optimized
//no LMonitor connectivity and no verbose
Init();
SaveProperties(1);
if (!fspace->IsInside(fe)) return;
while (1){
if (fN>=fmax) break;//out of time
if (ft<=fe->time) {
SaveProperties(1);
continue;
}
if (!StepFast()) break;//out of space
}
ft-=ftime;//since the ft points to the time where should store next
}
inline
int LDisorder::StepFast(){
//like LDisorder:Step but optimized with no LMonitor connectivity
//to use with WalkFast
static long seed=initseed();
int idx;
int i0=fe->i-fWa2c;
int j0=fe->j-fWb2c;
int k0=fe->k-fWc2c;
float e1=fe->GetEnergy();//current energy but no gradient
float e2,r,sum=0.0;
//calculate probabilities
for(int i=1;i<=fWa;i++)
for(int j=1;j<=fWb;j++)
for(int k=1;k<=fWc;k++){
idx=fWb*fWc*(i-1)+fWc*(j-1)+k;
if (idx!=idxexclude){//exclude sumation over the site of origin
e2=fspace->GetEnergy(i0+i,j0+j,k0+k);
r=fspace->Distance(idx);//to speed up
//r=fspace->Distance(i-fWa2c,j-fWb2c,k-fWc2c);
sum+=Probability(r,e1,e2);
fprob[idx]=sum;
} else fprob[idx]=sum; //so will never be selected in Where
}
float a;a=sum*ran1(&seed);
unsigned long jm,jl=0;
idx=fNprob+1;
if(a>fprob[fNprob-1]) idx=fNprob;
else if(a<=fprob[1]) idx=1;
else
while(idx-jl>1){
jm=(idx+jl)>>1;//compute midpoint
if(a>fprob[jm]) jl=jm; else idx=jm;
}
int x,z,y;
idx--;
x=idx/(fWb*fWc);
y=(idx-x*fWb*fWc)/fWc;
z=idx-x*fWb*fWc-y*fWc+1;
idx++;x++;y++;
fe->time+=(expdev(&seed)*sum/(fprob[idx]-fprob[idx-1]));//no scale
return MoveTo(x-fWa2c,y-fWb2c,z-fWc2c);//move particle
}
void
LDisorder::Test(int testmode){
//this is for testing only
//tests are:
//1 - particle is moving in k direction until it exits space
//2 - particle is moving in -k direction until it exits space
Init();
std::cout<<"ft:"<<ft<<" t:"<<fe->time<<" k:"<<fe->k<<" e:"<<fe->GetEnergy()<<" fN"<<fN<<std::endl;
SaveProperties(1);
while(fspace->IsInside(fe)){
if (fN>=fmax) break;
switch (testmode){
case 1: if (!MoveTo(0,0,1)) return;
break;
case 2: if (!MoveTo(0,0,-1)) return;
break;
}
fe->time+=ftime;
std::cout<<"ft:"<<ft<<" t:"<<fe->time<<" k:"<<fe->k<<" e:"<<fe->GetEnergy()<<" fN"<<fN<<std::endl;
SaveProperties(1);
}
}
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.