00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00018
00027
00028
00029
00031
00032
00033 #include <cassert>
00034 #include <cfloat>
00035 #include <cmath>
00036
00037
00038 #include <qapplication.h>
00039 #include <qmutex.h>
00040
00041
00042 #include "orbitalthread.h"
00043
00047
00049 OrbitalThread::OrbitalThread(QWidget* parentWidget, QMutex* sharedMutex, std::vector<Point3D<float> >* coordinates,
00050 const unsigned int type, const unsigned int atom, const unsigned int n,
00051 const unsigned int l, const int m, const float res, const float prob,
00052 const unsigned int dots) : QThread(),
00053 receiver(parentWidget),
00054 mutex(sharedMutex),
00055 coords(coordinates),
00056 atomNumber(atom),
00057 qnPrincipal(n),
00058 qnOrbital(l),
00059 qnMomentum(m),
00060 calculationType(type),
00061 probability(prob),
00062 resolution(res),
00063 numDots(dots),
00064 stopRequested(false)
00067 {
00068 assert(parentWidget != 0);
00069 assert(sharedMutex != 0);
00070 assert(coordinates != 0);
00071 assert(atom > 0);
00072 assert(prob >= 0.0f && prob <= 1.0f);
00073 assert(res > 1.0f);
00074 assert(n > l);
00075 assert(l >= static_cast<unsigned int>(abs(m)));
00076 assert(type < 3);
00077
00078
00079
00080
00081
00082
00086 }
00087
00089 OrbitalThread::~OrbitalThread()
00091 {
00092
00093 }
00094
00096 void OrbitalThread::stop()
00098 {
00099 stopRequested = true;
00100 }
00101
00103 double OrbitalThread::boundingSphereRadius()
00105 {
00106 return static_cast<double>(maximumRadius);
00107 }
00108
00112
00114 void OrbitalThread::run()
00117 {
00119 unsigned int neededPrecision = PRECISION_UNKNOWN;
00120 if(calculationType != AngularPart)
00121 {
00123
00124 if(largestResult<float>(qnPrincipal, qnOrbital, qnMomentum, atomNumber) != HUGE_VAL)
00125
00126 neededPrecision = PRECISION_FLOAT;
00127
00128 else if(largestResult<double>(qnPrincipal, qnOrbital, qnMomentum, atomNumber) != HUGE_VAL)
00129
00130 neededPrecision = PRECISION_DOUBLE;
00131
00132 else if(largestResult<long double>(qnPrincipal, qnOrbital, qnMomentum, atomNumber) != HUGE_VAL)
00133 neededPrecision = PRECISION_LONG_DOUBLE;
00134 }
00135 else
00136 {
00138
00139 if(factorial<float>(2*qnOrbital) != HUGE_VAL)
00140 neededPrecision = PRECISION_FLOAT;
00141
00142 else if(factorial<float>(2*qnOrbital) != HUGE_VAL)
00143 neededPrecision = PRECISION_DOUBLE;
00144
00145 else if(factorial<float>(2*qnOrbital) != HUGE_VAL)
00146 neededPrecision = PRECISION_LONG_DOUBLE;
00147 }
00148 qDebug("required precision = %d", neededPrecision);
00149 if(neededPrecision == PRECISION_UNKNOWN)
00150 {
00151
00152 QCustomEvent* e = new QCustomEvent(static_cast<QEvent::Type>(1002));
00153 QApplication::postEvent(receiver, e);
00154 qDebug("exceeded long double limits");
00155 return;
00156 }
00157 if(neededPrecision != PRECISION_FLOAT)
00158 {
00159
00160 QCustomEvent* e = new QCustomEvent(static_cast<QEvent::Type>(1002));
00161 QApplication::postEvent(receiver, e);
00162 qDebug("precision higher than float not implemented yet");
00163 return;
00164 }
00165
00166 switch(calculationType)
00167 {
00168 case IsoProbability:
00169 calcIsoProbability();
00170 break;
00171 case AccumulatedProbability:
00172 calcAccumulatedProbability();
00173 break;
00174 case Density:
00175 calcRandomDots();
00176 break;
00177 case RadialPart:
00178 calcRadialPart();
00179 break;
00180 case AngularPart:
00181 calcAngularPart();
00182 break;
00183 }
00184
00185 QCustomEvent* e = new QCustomEvent(static_cast<QEvent::Type>(1002));
00186 QApplication::postEvent(receiver, e);
00187 }
00188
00190 void OrbitalThread::calcIsoProbability()
00193 {
00194 const int updateFreq = static_cast<int>(resolution*resolution)/100;
00195
00196
00197 mutex->lock();
00198 coords->clear();
00199 mutex->unlock();
00200 maximumRadius = 0.0f;
00201 std::vector<Point3D<float> > coordsList;
00202 coordsList.reserve(updateSize);
00203
00204
00205 const unsigned int n = qnPrincipal;
00206 const unsigned int l = qnOrbital;
00207 const int m = qnMomentum;
00208
00209
00210 const float zna = static_cast<float>(atomNumber) / static_cast<float>(n) / abohr;
00211 const float normR = pow(2.0f*zna, 1.5f) * sqrt(factorial<float>(n-l-1)/2.0f/n/factorial<float>(n+l));
00212 const float normTheta = pow(-1.0f, (m + abs(m))/2) * sqrtf( (2*l+1) * factorial<float>(l-abs(m)) / (2.0f * factorial<float>(l+abs(m))));
00213 const float normPhi = 1.0f / sqrtf(Point3D<float>::PI);
00214 const float incTheta = 180.0f/resolution;
00215 const float incPhi = 360.0f/resolution;
00216 const float maxR = 2.0f*static_cast<float>(n*n);
00217 const float incR = maxR / (10.0f * resolution);
00218
00220 for(float theta = 0.0f; theta < 180.0f; theta += incTheta)
00221 {
00223 for(float phi = 0.0f; phi < 360.0f; phi += incPhi)
00224 {
00225
00226 progress = static_cast<int>(theta/incTheta * resolution + phi/incPhi);
00227 if(progress % updateFreq == 0)
00228 {
00229 QCustomEvent* e = new QCustomEvent(static_cast<QEvent::Type>(1001),&progress);
00230 QApplication::postEvent(receiver, e);
00231 }
00232
00233
00234 const float randTheta = theta + random(-incTheta/2.0f, incTheta/2.0f);
00235
00236 if(random(0.0f, 1.0f) > fabs(sinf(randTheta*Point3D<float>::DEGTORAD)))
00237 continue;
00238
00239 const float randPhi = phi + random(-incPhi/2.0f, incPhi/2.0f);
00240
00241
00242 const float partTheta = normTheta * associatedLegendre(cosf(randTheta*Point3D<float>::DEGTORAD), abs(m), l);
00243
00244 float partPhi = normPhi;
00245 if(m == 0)
00246 partPhi /= sqrtf(2.0f);
00247 else if(m > 0)
00248 partPhi *= sinf(m*randPhi*Point3D<float>::DEGTORAD);
00249 else
00250 partPhi *= cosf(m*randPhi*Point3D<float>::DEGTORAD);
00251
00252
00253 const float partY = partTheta * partPhi;
00254
00256 float r = incR;
00257 float newProbability = 0.0f;
00258 const unsigned int maxPoints = l == 0 ? 2*n -1 : 2*(n - l);
00259 unsigned int numPoints = 0;
00260
00261 float oldProbability = pow(partY * normR * associatedLaguerre(0.0f, 2*l+1, n-l-1) , 2);
00262
00263 while(r < maxR && numPoints < maxPoints)
00264 {
00265 if(stopRequested)
00266 return;
00267 const float rho = 2.0f * zna * r;
00268 const float partR = normR * pow(rho, static_cast<int>(l)) * exp(-rho/2.0f) * associatedLaguerre(rho, 2*l+1, n-l-1);
00269
00270 newProbability = partY * partR * partY * partR;
00271
00272
00273 if(r > incR && ((oldProbability <= probability && newProbability >= probability) || (oldProbability >= probability && newProbability <= probability)))
00274 {
00275
00276 const float minProb = oldProbability < newProbability ? oldProbability : newProbability;
00277 const float maxProb = oldProbability > newProbability ? oldProbability : newProbability;
00278 const float interpolatedR = r + incR * (probability - minProb)/(maxProb-minProb);
00279
00280
00281
00282
00283 numPoints++;
00284 Point3D<float> newCoord;
00285 newCoord.setPolar(randTheta, randPhi, interpolatedR);
00286 newCoord.setID(partY*partR > 0.0f ? 1 : 0);
00287 coordsList.push_back(newCoord);
00288 updateList(coordsList);
00289 if(r > maximumRadius) maximumRadius = r;
00290 }
00291 oldProbability = newProbability;
00292 r += incR;
00293 }
00294
00295 if(numPoints < maxPoints && oldProbability > probability)
00296 {
00297
00298
00299
00300
00301 while(true)
00302 {
00303 if(stopRequested)
00304 return;
00305 const float rho = 2.0f * zna * r;
00306 const float partR = normR * pow(rho, static_cast<int>(l)) * exp(-rho/2.0f) * associatedLaguerre(rho, 2*l+1, n-l-1);
00307 newProbability = partY * partR * partY * partR;
00308 if(oldProbability >= probability && newProbability <= probability)
00309 {
00310 const float interpolatedR = r + incR * (probability - newProbability)/(oldProbability-newProbability);
00311
00312
00313
00314
00315 numPoints++;
00316 Point3D<float> newCoord;
00317 newCoord.setPolar(randTheta, randPhi, interpolatedR);
00318 newCoord.setID(partY*partR > 0.0f ? 1 : 0);
00319
00320
00321
00322 coordsList.push_back(newCoord);
00323 updateList(coordsList);
00324 if(r > maximumRadius) maximumRadius = r;
00325 break;
00326 }
00327 oldProbability = newProbability;
00328 r += incR;
00329 }
00330 }
00331 }
00332 }
00333 updateList(coordsList, true);
00334 }
00335
00337 void OrbitalThread::calcAccumulatedProbability()
00340 {
00341 const int updateFreq = static_cast<int>(resolution*resolution)/100;
00342
00343
00344 mutex->lock();
00345 coords->clear();
00346 mutex->unlock();
00347 maximumRadius = 0.0f;
00348 std::vector<Point3D<float> > coordsList;
00349 coordsList.reserve(updateSize);
00350
00351
00352 const unsigned int n = qnPrincipal;
00353 const unsigned int l = qnOrbital;
00354 const int m = qnMomentum;
00355
00356
00357 const float zna = static_cast<float>(atomNumber) / static_cast<float>(n) / abohr;
00358 const float normR = pow(2.0f*zna, 1.5f) * sqrt(factorial<float>(n-l-1)/2.0f/n/factorial<float>(n+l));
00359 const float normTheta = pow(-1.0f, (m + abs(m))/2) * sqrtf( (2*l+1) * factorial<float>(l-abs(m)) / (2.0f * factorial<float>(l+abs(m))));
00360 const float normPhi = 1.0f / sqrtf(Point3D<float>::PI);
00361 const float incTheta = 180.0f/resolution;
00362 const float incPhi = 360.0f/resolution;
00363 const float maxR = 2.0f*static_cast<float>(n*n);
00364 const float incR = maxR / (10.0f * resolution);
00365
00367 for(float theta = 0.0f; theta < 180.0f; theta += incTheta)
00368 {
00369
00371 for(float phi = 0.0f; phi < 360.0f; phi += incPhi)
00372 {
00373
00374 progress = static_cast<int>(theta/incTheta * resolution + phi/incPhi);
00375 if(progress % updateFreq == 0)
00376 {
00377 QCustomEvent* e = new QCustomEvent(static_cast<QEvent::Type>(1001),&progress);
00378 QApplication::postEvent(receiver, e);
00379 }
00380
00381
00382 const float randTheta = theta + random(-incTheta/2.0f, incTheta/2.0f);
00383
00384 if(random(0.0f, 1.0f) > fabs(sinf(randTheta*Point3D<float>::DEGTORAD)))
00385 continue;
00386
00387
00388 const float partTheta = normTheta * associatedLegendre(cosf(randTheta*Point3D<float>::DEGTORAD), abs(m), l);
00389
00390
00391 const float randPhi = phi + random(-incPhi/2.0f, incPhi/2.0f);
00392
00393 float partPhi = normPhi;
00394 if(m == 0)
00395 partPhi /= sqrtf(2.0f);
00396 else if(m > 0)
00397 partPhi *= sinf(m*randPhi*Point3D<float>::DEGTORAD);
00398 else
00399 partPhi *= cosf(m*randPhi*Point3D<float>::DEGTORAD);
00400
00401
00402 const float partY = partTheta * partPhi;
00403
00405 float r = 0.0f;
00406 float totalProbability = 0.0f;
00407 float amplitude = 0.0f;
00408 while (r < maxR)
00409 {
00410 if(stopRequested)
00411 return;
00412 const float rho = 2.0f * zna * r;
00413 const float partR = normR * pow(rho, static_cast<int>(l)) * exp(-rho/2.0f) * associatedLaguerre(rho, 2*l+1, n-l-1);
00414
00415
00416 amplitude = partY * partR;
00417 totalProbability += 4.0f * Point3D<float>::PI * amplitude*amplitude * r*r * incR;
00418
00419
00420 if(totalProbability >= probability)
00421 break;
00422
00423 r += incR;
00424 }
00425
00426
00427
00428 Point3D<float> newCoord;
00429 newCoord.setPolar(randTheta, randPhi, r);
00430 newCoord.setID(amplitude > 0.0f ? 1 : 0);
00431 coordsList.push_back(newCoord);
00432 updateList(coordsList);
00433 if(r > maximumRadius) maximumRadius = r;
00434 }
00435 }
00436 updateList(coordsList, true);
00437 }
00438
00440 void OrbitalThread::calcRandomDots()
00442 {
00443 const int updateFreq = static_cast<int>(numDots)/100;
00444
00445
00446 mutex->lock();
00447 coords->clear();
00448 mutex->unlock();
00449 maximumRadius = 0.0f;
00450 std::vector<Point3D<float> > coordsList;
00451 coordsList.reserve(updateSize);
00452
00453
00454 const unsigned int n = qnPrincipal;
00455 const unsigned int l = qnOrbital;
00456 const int m = qnMomentum;
00457
00458
00459 const float zna = static_cast<float>(atomNumber) / static_cast<float>(n) / abohr;
00460 const float normR = pow(2.0f*zna, 1.5f) * sqrt(factorial<float>(n-l-1)/2.0f/n/factorial<float>(n+l));
00461 const float normTheta = pow(-1.0f, (m + abs(m))/2) * sqrtf( (2*l+1) * factorial<float>(l-abs(m)) / (2.0f * factorial<float>(l+abs(m))));
00462 const float normPhi = 1.0f / sqrtf(Point3D<float>::PI);
00463 const float maxR = 2.0f * static_cast<float>(n*n);
00464 float maxRtest = 0.0f;
00465 if(l == n-1)
00466 maxRtest = static_cast<float>(n*l);
00467 else if(l != 0)
00468 maxRtest = static_cast<float>(l*(l+1));
00469
00470
00471 float maxProb = 0.0f;
00472 float maxProbR = 0.0f;
00473 unsigned int testLimit = numDots/10 < 1000 ? numDots/10 : 1000;
00474 for(unsigned int i = 0; i < testLimit; i++)
00475 {
00476 if(stopRequested)
00477 return;
00478 const float theta = random(0.0f, 180.0f);
00479 const float phi = random(0.0f, 360.0f);
00480 const float r = random(0.0f, maxRtest);
00481
00482 const float partTheta = normTheta * associatedLegendre(cosf(theta*Point3D<float>::DEGTORAD), abs(m), l);
00483 float partPhi = normPhi;
00484 if(m == 0)
00485 partPhi /= sqrtf(2.0f);
00486 else if(m > 0)
00487 partPhi *= sinf(m*phi*Point3D<float>::DEGTORAD);
00488 else
00489 partPhi *= cosf(m*phi*Point3D<float>::DEGTORAD);
00490 const float rho = 2.0f * zna * r;
00491 const float partR = normR * pow(rho, static_cast<int>(l)) * exp(-rho/2.0f) * associatedLaguerre(rho, 2*l+1, n-l-1);
00492 const float probability = pow(partTheta * partPhi * partR, 2);
00493 if(probability > maxProb)
00494 {
00495 maxProb = probability;
00496 maxProbR = r;
00497 }
00498 }
00499 qDebug("estimated maximum probability = %f", maxProb);
00500
00501
00502 unsigned int currentDots = 0;
00503 while(currentDots < numDots)
00504 {
00505 if(stopRequested)
00506 return;
00507
00508
00509 const float theta = random(0.1f, 179.9f);
00510 const float phi = random(0.0f, 360.0f);
00511 const float r = random(0.0f, maxR);
00512
00513
00514 if(random(0.0f, 1.0f) > fabs(sinf(theta*Point3D<float>::DEGTORAD)))
00515 continue;
00516
00517
00518 const float partTheta = normTheta * associatedLegendre(cosf(theta*Point3D<float>::DEGTORAD), abs(m), l);
00519 float partPhi = normPhi;
00520 if(m == 0)
00521 partPhi /= sqrtf(2.0f);
00522 else if(m > 0)
00523 partPhi *= sinf(m*phi*Point3D<float>::DEGTORAD);
00524 else
00525 partPhi *= cosf(m*phi*Point3D<float>::DEGTORAD);
00526 const float rho = 2.0f * zna * r;
00527 const float partR = normR * pow(rho, static_cast<int>(l)) * exp(-rho/2.0f) * associatedLaguerre(rho, 2*l+1, n-l-1);
00528 const float probability = pow(partTheta * partPhi * partR, 2);
00529 if(probability > maxProb)
00530 {
00531 maxProb = probability;
00532 maxProbR = r;
00533 }
00534 if(probability > random(0.0f, maxProb))
00535 {
00536
00537 Point3D<float> newCoord;
00538 newCoord.setPolar(theta, phi, r);
00539 newCoord.setID(partTheta*partPhi*partR > 0.0f ? 1 : 0);
00540 coordsList.push_back(newCoord);
00541 updateList(coordsList);
00542 if(r > maximumRadius) maximumRadius = r;
00543 currentDots++;
00544
00545 if(currentDots % updateFreq == 0)
00546 {
00547 progress = currentDots;
00548 QCustomEvent* e = new QCustomEvent(static_cast<QEvent::Type>(1001),&progress);
00549 QApplication::postEvent(receiver, e);
00550 }
00551 }
00552 }
00553 updateList(coordsList, true);
00554 qDebug("final maximum probability = %f", maxProb);
00555 qDebug(" corresponding radius = %f", maxProbR);
00556 }
00557
00559 void OrbitalThread::calcRadialPart()
00561 {
00562 const int updateFreq = static_cast<int>(10.0f * resolution)/100;
00563
00564
00565 mutex->lock();
00566 coords->clear();
00567 mutex->unlock();
00568 std::vector<Point3D<float> > coordsList;
00569 coordsList.reserve(updateSize);
00570
00571
00572 const unsigned int n = qnPrincipal;
00573 const unsigned int l = qnOrbital;
00574
00575
00576 const float zna = static_cast<float>(atomNumber) / static_cast<float>(n) / abohr;
00577 const float normR = pow(2.0f*zna, 1.5f) * sqrt(factorial<float>(n-l-1)/2.0f/n/factorial<float>(n+l));
00578 const float maxR = 2.0f*static_cast<float>(n*n);
00579 const float incR = maxR / (10.0f * resolution);
00580
00581 maximumRadius = maxR;
00582
00583
00584
00585
00586
00587 for(float r = 0.0f; r < maxR; r += incR)
00588 {
00589 if(stopRequested)
00590 return;
00591
00592
00593 progress = static_cast<unsigned int>(r/incR);
00594 if(progress % updateFreq == 0)
00595 {
00596 QCustomEvent* e = new QCustomEvent(static_cast<QEvent::Type>(1001),&progress);
00597 QApplication::postEvent(receiver, e);
00598 }
00599
00600
00601 const float rho = 2.0f * zna * r;
00602 const float partR = normR * pow(rho, static_cast<int>(l)) * exp(-rho/2.0f) * associatedLaguerre(rho, 2*l+1, n-l-1);
00603
00604
00605 Point3D<float> newCoord1(r, partR, 0.0f);
00606 newCoord1.setID(1);
00607
00608 Point3D<float> newCoord2(r, partR*partR*r*r, 0.0f);
00609 newCoord2.setID(0);
00610
00611 coordsList.push_back(newCoord1);
00612 coordsList.push_back(newCoord2);
00613 updateList(coordsList);
00614
00615
00616
00617
00618
00619
00620
00621 }
00622 updateList(coordsList, true);
00623 }
00624
00626 void OrbitalThread::calcAngularPart()
00628 {
00629 const int updateFreq = static_cast<int>(resolution * resolution)/100;
00630
00631
00632 mutex->lock();
00633 coords->clear();
00634 mutex->unlock();
00635 maximumRadius = 0.0f;
00636 std::vector<Point3D<float> > coordsList;
00637 coordsList.reserve(updateSize);
00638
00639
00640 const unsigned int l = qnOrbital;
00641 const int m = qnMomentum;
00642
00643
00644 const float normTheta = pow(-1.0f, (m + abs(m))/2) * sqrtf( (2*l+1) * factorial<float>(l-abs(m)) / (2.0f * factorial<float>(l+abs(m))));
00645 const float normPhi = 1.0f / sqrtf(Point3D<float>::PI);
00646 const float incTheta = 180.0f/resolution;
00647 const float incPhi = 360.0f/resolution;
00648
00650 for(float theta = 0.0f; theta < 180.0f; theta += incTheta)
00651 {
00652
00654 for(float phi = 0.0f; phi < 360.0f; phi += incPhi)
00655 {
00656 if(stopRequested)
00657 return;
00658
00659
00660 progress = static_cast<int>(theta/incTheta * resolution + phi/incPhi);
00661 if(progress % updateFreq == 0)
00662 {
00663 QCustomEvent* e = new QCustomEvent(static_cast<QEvent::Type>(1001),&progress);
00664 QApplication::postEvent(receiver, e);
00665 }
00666
00667
00668 const float randTheta = theta + random(-incTheta/2.0f, incTheta/2.0f);
00669
00670 if(random(0.0f, 1.0f) > fabs(sinf(randTheta*Point3D<float>::DEGTORAD)))
00671 continue;
00672
00673 const float partTheta = normTheta * associatedLegendre(cosf(randTheta*Point3D<float>::DEGTORAD), abs(m), l);
00674
00675
00676 const float randPhi = phi + random(-incPhi/2.0f, incPhi/2.0f);
00677
00678 float partPhi = normPhi;
00679 if(m == 0)
00680 partPhi /= sqrtf(2.0f);
00681 else if(m > 0)
00682 partPhi *= sinf(m*randPhi*Point3D<float>::DEGTORAD);
00683 else
00684 partPhi *= cosf(m*randPhi*Point3D<float>::DEGTORAD);
00685
00686
00687 const float partY = partTheta * partPhi;
00688
00689
00690 const float r = fabs(partY);
00691 Point3D<float> newCoord;
00692 newCoord.setPolar(randTheta, randPhi, r);
00693 newCoord.setID(partY > 0.0f ? 1 : 0);
00694 coordsList.push_back(newCoord);
00695 updateList(coordsList);
00696 if(r > maximumRadius) maximumRadius = r;
00697 }
00698 }
00699 updateList(coordsList, true);
00700 }
00701
00703 void OrbitalThread::updateList(std::vector<Point3D<float> >& newCoords, bool final)
00706 {
00707 if(newCoords.size() >= updateSize || (final && !newCoords.empty()))
00708 {
00709 mutex->lock();
00710 coords->insert(coords->end(), newCoords.begin(), newCoords.end());
00711 mutex->unlock();
00712 newCoords.clear();
00713 qDebug("Added %d new points", updateSize);
00714 }
00715 }
00716
00718 float OrbitalThread::associatedLegendre(const float x, const int m, const unsigned int l)
00720 {
00721 float prefactor = pow(1.0f - x*x, static_cast<float>(m)/2.0f) / pow(2.0f, static_cast<int>(l));
00722 int upperBound = 0;
00723 if(((l-m) % 2) == 0)
00724 upperBound = (l-m)/2;
00725 else
00726 upperBound = (l-m-1)/2;
00727
00728 float result = 0.0f;
00729 for(int j = 0; j <= upperBound; j++)
00730 {
00731 float tempvar = pow(-1.0f, j)*factorial<float>(2*l-2*j);
00732 tempvar /= factorial<float>(j)*factorial<float>(l-j)*factorial<float>(l-abs(m)-2*j);
00733 tempvar *= pow(x, static_cast<int>(l-m-2*j));
00734 result += tempvar;
00735 }
00736 return prefactor*result;
00737 }
00738
00740 float OrbitalThread::associatedLaguerre(const float x, const int m, const unsigned int n)
00742 {
00743
00744 if(n == 0)
00745 return 1.0f;
00746 float result = 0.0f;
00747 for(unsigned int j = 0; j <= n; j++)
00748 result += pow(-1.0f, static_cast<int>(j)) * factorial<float>(n+m) / factorial<float>(n-j) / factorial<float>(m+j) / factorial<float>(j) * pow(x, static_cast<int>(j));
00749 return result;
00750 }
00751
00753 template <class T> T OrbitalThread::factorial(const unsigned int number)
00758 {
00759 if(number <= 1)
00760 return 1;
00761 unsigned int counter = number - 1;
00762 T result = static_cast<T>(number);
00763 while(counter > 1)
00764 {
00765 result *= static_cast<T>(counter);
00766 counter--;
00767 }
00768 return result;
00769 }
00770
00772 float OrbitalThread::random(const float min, const float max)
00774 {
00775 return min + static_cast<float>(rand())/RAND_MAX*(max - min);
00776 }
00777
00779 template <class T> T OrbitalThread::largestResult(const unsigned int n, const unsigned int l, const int m, const unsigned int Z)
00782 {
00783 T partPhi = static_cast<T>(0.5641895835);
00784 T partTheta = sqrt(factorial<T>(2*l+1) * factorial<T>(l-abs(m)) / 2.0 / factorial<T>(l+abs(m))) * associatedLegendre(1.0f, abs(m), l);
00785 T rmax = static_cast<T>(3*n*n);
00786 T partR = pow(2.0*Z/n/abohr, 1.5) * sqrt(factorial<T>(n-l-1)/2.0/n/factorial<T>(n+l)) * pow(2.0*Z/n/abohr*rmax, static_cast<int>(l)) * associatedLaguerre(2.0*Z/n/abohr*rmax, 2*l+1, n-l-1);
00787 return partPhi*partTheta*partR;
00788 }
00789
00793
00794 const float OrbitalThread::abohr = 1.0f;
00795 const unsigned int OrbitalThread::updateSize = 1000;
00796