/*************************************************************************** TPofBCalc.cpp Author: Bastian M. Wojek e-mail: bastian.wojek@psi.ch 2008/09/04 ***************************************************************************/ /*************************************************************************** * Copyright (C) 2009 by Bastian M. Wojek * * * * * * This program is free 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, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "TPofTCalc.h" #include #include #include #include #include #ifdef HAVE_GOMP #include #endif /* USED FOR DEBUGGING----------------------------------- #include #include /-------------------------------------------------------*/ TPofBCalc::TPofBCalc(const vector ¶) : fBmin(0.0), fBmax(0.0), fDT(para[0]), fDB(para[1]), fPBExists(false) { fPBSize = static_cast(1.0/(gBar*fDT*fDB)); if (fPBSize % 2) { fPBSize += 1; } else { fPBSize += 2; } fB = new double[fPBSize]; fPB = new double[fPBSize]; int i; #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) #endif for (i = 0; i < static_cast(fPBSize); ++i) { fB[i] = static_cast(i)*fDB; fPB[i] = 0.0; } } // Do not actually calculate P(B) but take it from a B and a P(B) vector of the same size TPofBCalc::TPofBCalc(const vector& b, const vector& pb, double dt) { assert(b.size() == pb.size() && b.size() >= 2); fPBSize = pb.size(); fB = new double[fPBSize]; fPB = new double[fPBSize]; int i; #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) #endif for (i = 0; i < static_cast(fPBSize); ++i) { fB[i] = b[i]; fPB[i] = pb[i]; } vector::const_iterator iter, iterB; iterB = b.begin(); for(iter = pb.begin(); iter != pb.end(); ++iter){ if(*iter != 0.0) { fBmin = *iterB; // cout << fBmin << endl; break; } ++iterB; } for( ; iter != b.end(); ++iter){ if(*iter == 0.0) { fBmax = *(iterB-1); // cout << fBmax << endl; break; } ++iterB; } fDT = dt; // needed if a convolution should be done fDB = b[1]-b[0]; // cout << fDB << endl; fPBExists = true; } void TPofBCalc::UnsetPBExists() { int i; #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) #endif for (i = 0; i < static_cast(fPBSize); ++i) { fPB[i] = 0.0; } fPBExists = false; } void TPofBCalc::Normalize(unsigned int minFilledIndex = 0, unsigned int maxFilledIndex = 0) const { if (!maxFilledIndex) maxFilledIndex = fPBSize - 1; int i; double pBsum(0.0); #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) reduction(+:pBsum) #endif for (i = minFilledIndex; i <= static_cast(maxFilledIndex); ++i) pBsum += fPB[i]; pBsum *= fDB; #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) #endif for (i = minFilledIndex; i <= static_cast(maxFilledIndex); ++i) fPB[i] /= pBsum; } void TPofBCalc::Calculate(const string &type, const vector ¶) { if (type == "skg"){ // skewed Gaussian fBmin = 0.0; fBmax = para[2]/gBar+10.0*fabs(para[4])/(2.0*pi*gBar); int a3(static_cast(floor(fBmax/fDB))); int a4(static_cast(ceil(fBmax/fDB))); int BmaxIndex((a3 < a4) ? a4 : (a4 + 1)); int B0Index(static_cast(ceil(para[2]/(gBar*fDB)))); double expominus(para[3]*para[3]/(2.0*pi*pi*gBar*gBar)); double expoplus(para[4]*para[4]/(2.0*pi*pi*gBar*gBar)); double B0(para[2]/(gBar)); int i; #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) #endif for (i = 0; i < B0Index; ++i) { fPB[i] = exp(-(fB[i]-B0)*(fB[i]-B0)/expominus); } #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) #endif for (i = B0Index; i <= BmaxIndex; ++i) { fPB[i] = exp(-(fB[i]-B0)*(fB[i]-B0)/expoplus); } Normalize(0, BmaxIndex); } fPBExists = true; return; } //----------- // Calculate-method that does the P(B) calculation for given analytical inverse of B(z) and its derivative and n(z) // Parameters: dt[us], dB[G], Energy[keV], Bbg[G], width[us^{-1}], weight[1] //----------- void TPofBCalc::Calculate(const TBofZCalcInverse *BofZ, const TTrimSPData *dataTrimSP, const vector ¶) { if(fPBExists) return; fBmin = BofZ->GetBmin(); fBmax = BofZ->GetBmax(); int a1(static_cast(floor(fBmin/fDB))); int a2(static_cast(ceil(fBmin/fDB))); int a3(static_cast(floor(fBmax/fDB))); int a4(static_cast(ceil(fBmax/fDB))); unsigned int firstZerosEnd ((a1 < a2) ? a1 : ((a1 > 0) ? (a1 - 1) : 0)); unsigned int lastZerosStart ((a3 < a4) ? a4 : (a4 + 1)); if (lastZerosStart >= fPBSize) { lastZerosStart = fPBSize - 1; } unsigned int i; // calculate p(B) from the inverse of B(z) for (i = firstZerosEnd; i <= lastZerosStart; ++i) { vector< pair > inv; inv = BofZ->GetInverseAndDerivative(fB[i]); for (unsigned int j(0); j < inv.size(); ++j) { fPB[i] += dataTrimSP->GetNofZ(inv[j].first, para[2])*fabs(inv[j].second); } // if (fPB[i]) // cout << fB[i] << " " << fPB[i] << endl; } // normalize p(B) Normalize(firstZerosEnd, lastZerosStart); if(para.size() == 6 && para[5] != 0.0) AddBackground(para[3], para[4], para[5]); } //----------- // Calculate-method that does the P(B) calculation for given B(z) and n(z) // Parameters: dt[us], dB[G], Energy[keV] //----------- void TPofBCalc::Calculate(const TBofZCalc *BofZ, const TTrimSPData *dataTrimSP, const vector ¶, unsigned int zonk) { if(fPBExists) return; fBmin = BofZ->GetBmin(); fBmax = BofZ->GetBmax(); int a1(static_cast(floor(fBmin/fDB))); int a2(static_cast(ceil(fBmin/fDB))); int a3(static_cast(floor(fBmax/fDB))); int a4(static_cast(ceil(fBmax/fDB))); unsigned int firstZerosEnd ((a1 < a2) ? a1 : ((a1 > 0) ? (a1 - 1) : 0)); unsigned int lastZerosStart ((a3 < a4) ? a4 : (a4 + 1)); double BB, BBnext; double zm, zp, zNext, dz; // calculate p(B) from B(z) vector *bofzZ = BofZ->DataZ(); vector *bofzBZ = BofZ->DataBZ(); double ddZ(BofZ->GetDZ()); /* USED FOR DEBUGGING----------------------------------- cout << "Bmin = " << fBmin << ", Bmax = " << fBmax << endl; time_t seconds; seconds = time (NULL); char debugfile[50]; int n = sprintf (debugfile, "test_Bz_%ld_%f.dat", seconds, fBmin); if (n > 0) { ofstream of(debugfile); // assure(of, debugfile); for (unsigned int i(0); i 0) { ofstream of1(debugfile1); // assure(of1, debugfile1); dataTrimSP.Normalize(para[2]); for (unsigned int i(0); i 0) { ofstream of2(debugfile2); // assure(of1, debugfile1); dataTrimSP.ConvolveGss(10.0,para[2]); dataTrimSP.Normalize(para[2]); for (unsigned int i(0); isize() - 1; j++ ) { if ( (*bofzBZ)[j] >= BB && (*bofzBZ)[j+1] <= BB ) { zm = (BB-(*bofzBZ)[j])*ddZ/((*bofzBZ)[j+1]-(*bofzBZ)[j]) + (*bofzZ)[j]; for (unsigned int k(0); k < j; k++) { if ( ( (*bofzBZ)[j-k] <= BBnext && (*bofzBZ)[j-k-1] >= BBnext ) ) { // cout << "1 " << j << " " << k << endl; zNext = (BBnext-(*bofzBZ)[j-k-1])*ddZ/((*bofzBZ)[j-k]-(*bofzBZ)[j-k-1]) + (*bofzZ)[j-k-1]; zNextFound = true; break; } } if(zNextFound) { zNextFound = false; dz = zNext-zm; nn = dataTrimSP->GetNofZ(zm, para[2]); if (nn != -1.0) { // cout << "zNext = " << zNextm << ", zm = " << zm << ", dz = " << dz << endl; fPB[i] += nn*fabs(dz/fDB); } } } else if ((*bofzBZ)[j] <= BB && (*bofzBZ)[j+1] >= BB ) { zp = (BB-(*bofzBZ)[j])*ddZ/((*bofzBZ)[j+1]-(*bofzBZ)[j]) + (*bofzZ)[j]; for (unsigned int k(0); k < bofzZ->size() - j - 1; k++) { if ( ( (*bofzBZ)[j+k] <= BBnext && (*bofzBZ)[j+k+1] >= BBnext ) ) { // cout << "2 " << j << " " << k << endl; zNext = (BBnext-(*bofzBZ)[j+k])*ddZ/((*bofzBZ)[j+k+1]-(*bofzBZ)[j+k]) + (*bofzZ)[j+k]; zNextFound = true; break; } } if(zNextFound) { zNextFound = false; dz = zNext-zp; nn = dataTrimSP->GetNofZ(zp, para[2]); if (nn != -1.0) { // cout << "zNext = " << zNextp << ", zp = " << zp << ", dz = " << dz << endl; fPB[i] += nn*fabs(dz/fDB); } } } } } bofzZ = 0; bofzBZ = 0; // normalize p(B) Normalize(firstZerosEnd, lastZerosStart); fPBExists = true; return; } //----------- // Calculate method that does the P(B) calculation for a bulk vortex lattice // Parameters: dt[us], dB[G] [, Bbg[G], width[us^{-1}], weight[1] ] //----------- void TPofBCalc::Calculate(const TBulkVortexFieldCalc *vortexLattice, const vector ¶) { if(fPBExists) return; fBmin = vortexLattice->GetBmin(); fBmax = vortexLattice->GetBmax(); // int a1(static_cast(floor(fBmin/fDB))); // int a2(static_cast(ceil(fBmin/fDB))); int a3(static_cast(floor(fBmax/fDB))); int a4(static_cast(ceil(fBmax/fDB))); //unsigned int firstZerosEnd ((a1 < a2) ? a1 : ((a1 > 0) ? (a1 - 1) : 0)); unsigned int lastZerosStart ((a3 < a4) ? a4 : (a4 + 1)); unsigned int numberOfSteps(vortexLattice->GetNumberOfSteps()); unsigned int numberOfStepsSq(numberOfSteps*numberOfSteps); unsigned int numberOfSteps_2(numberOfSteps/2); //unsigned int numberOfStepsSq_2(numberOfStepsSq/2); if (lastZerosStart >= fPBSize) lastZerosStart = fPBSize - 1; // cout << endl << fBmin << " " << fBmax << " " << firstZerosEnd << " " << lastZerosStart << " " << numberOfSteps << endl; if (!vortexLattice->GridExists()) { vortexLattice->CalculateGrid(); } double *vortexFields = vortexLattice->DataB(); unsigned int fill_index; if (para.size() == 7 && para[6] == 1.0 && para[5] != 0.0 && vortexLattice->IsTriangular()) { // weight distribution with Gaussian around vortex-cores double Rsq1, Rsq2, Rsq3, Rsq4, Rsq5, Rsq6, sigmaSq(-0.5*para[5]*para[5]); for (unsigned int j(0); j < numberOfSteps_2; ++j) { for (unsigned int i(0); i < numberOfSteps_2; ++i) { fill_index = static_cast(ceil(fabs((vortexFields[i + numberOfSteps*j]/fDB)))); if (fill_index < fPBSize) { Rsq1 = static_cast(3*i*i + j*j)/static_cast(numberOfStepsSq); Rsq2 = static_cast(3*(numberOfSteps_2 - i)*(numberOfSteps_2 - i) \ + (numberOfSteps_2 - j)*(numberOfSteps_2 - j))/static_cast(numberOfStepsSq); Rsq3 = static_cast(3*(numberOfSteps - i)*(numberOfSteps - i) \ + j*j)/static_cast(numberOfStepsSq); Rsq4 = static_cast(3*(numberOfSteps_2 - i)*(numberOfSteps_2 - i) \ + (numberOfSteps_2 + j)*(numberOfSteps_2 + j))/static_cast(numberOfStepsSq); Rsq5 = static_cast(3*i*i \ + (numberOfSteps - j)*(numberOfSteps - j))/static_cast(numberOfStepsSq); Rsq6 = static_cast(3*(numberOfSteps_2 + i)*(numberOfSteps_2 + i) \ + (numberOfSteps_2 - j)*(numberOfSteps_2 - j))/static_cast(numberOfStepsSq); fPB[fill_index] += exp(sigmaSq*Rsq1) + exp(sigmaSq*Rsq2) + exp(sigmaSq*Rsq3) \ + exp(sigmaSq*Rsq4) + exp(sigmaSq*Rsq5) + exp(sigmaSq*Rsq6); } } } } else if (para.size() == 7 && para[6] == 2.0 && para[5] != 0.0 && vortexLattice->IsTriangular()) { // weight distribution with Lorentzian around vortex-cores double Rsq1, Rsq2, Rsq3, Rsq4, Rsq5, Rsq6, sigmaSq(para[5]*para[5]); // ofstream of("LorentzWeight.dat"); for (unsigned int j(0); j < numberOfSteps_2; ++j) { for (unsigned int i(0); i < numberOfSteps_2; ++i) { fill_index = static_cast(ceil(fabs((vortexFields[i + numberOfSteps*j]/fDB)))); if (fill_index < fPBSize) { Rsq1 = static_cast(3*i*i + j*j)/static_cast(numberOfStepsSq); Rsq2 = static_cast(3*(numberOfSteps_2 - i)*(numberOfSteps_2 - i) \ + (numberOfSteps_2 - j)*(numberOfSteps_2 - j))/static_cast(numberOfStepsSq); Rsq3 = static_cast(3*(numberOfSteps - i)*(numberOfSteps - i) \ + j*j)/static_cast(numberOfStepsSq); Rsq4 = static_cast(3*(numberOfSteps_2 - i)*(numberOfSteps_2 - i) \ + (numberOfSteps_2 + j)*(numberOfSteps_2 + j))/static_cast(numberOfStepsSq); Rsq5 = static_cast(3*i*i \ + (numberOfSteps - j)*(numberOfSteps - j))/static_cast(numberOfStepsSq); Rsq6 = static_cast(3*(numberOfSteps_2 + i)*(numberOfSteps_2 + i) \ + (numberOfSteps_2 - j)*(numberOfSteps_2 - j))/static_cast(numberOfStepsSq); fPB[fill_index] += 1.0/(1.0+sigmaSq*Rsq1) + 1.0/(1.0+sigmaSq*Rsq2) + 1.0/(1.0+sigmaSq*Rsq3) \ + 1.0/(1.0+sigmaSq*Rsq4) + 1.0/(1.0+sigmaSq*Rsq5) + 1.0/(1.0+sigmaSq*Rsq6); /* of << 1.0/(1.0+sigmaSq*Rsq1) + 1.0/(1.0+sigmaSq*Rsq2) + 1.0/(1.0+sigmaSq*Rsq3) \ + 1.0/(1.0+sigmaSq*Rsq4) + 1.0/(1.0+sigmaSq*Rsq5) + 1.0/(1.0+sigmaSq*Rsq6) << " "; */ } } // of << endl; } // of.close(); } else if (para.size() == 8 && para[6] == 3.0 && para[5] != 0.0 && vortexLattice->IsTriangular()) { // add antiferromagnetic fields in the vortex cores double field, Rsq1, Rsq2, Rsq3, Rsq4, Rsq5, Rsq6, one_xiSq(-1.0/(para[7]*para[7])); // ofstream of("AFfields.dat"); for (unsigned int j(0); j < numberOfSteps_2; ++j) { for (unsigned int i(0); i < numberOfSteps_2; ++i) { Rsq1 = static_cast(3*i*i + j*j)/static_cast(numberOfStepsSq); Rsq2 = static_cast(3*(numberOfSteps_2 - i)*(numberOfSteps_2 - i) \ + (numberOfSteps_2 - j)*(numberOfSteps_2 - j))/static_cast(numberOfStepsSq); Rsq3 = static_cast(3*(numberOfSteps - i)*(numberOfSteps - i) \ + j*j)/static_cast(numberOfStepsSq); Rsq4 = static_cast(3*(numberOfSteps_2 - i)*(numberOfSteps_2 - i) \ + (numberOfSteps_2 + j)*(numberOfSteps_2 + j))/static_cast(numberOfStepsSq); Rsq5 = static_cast(3*i*i \ + (numberOfSteps - j)*(numberOfSteps - j))/static_cast(numberOfStepsSq); Rsq6 = static_cast(3*(numberOfSteps_2 + i)*(numberOfSteps_2 + i) \ + (numberOfSteps_2 - j)*(numberOfSteps_2 - j))/static_cast(numberOfStepsSq); field = vortexFields[i + numberOfSteps*j] \ + para[5]*(exp(Rsq1*one_xiSq) + exp(Rsq2*one_xiSq) + exp(Rsq3*one_xiSq) \ +exp(Rsq4*one_xiSq) + exp(Rsq5*one_xiSq) + exp(Rsq6*one_xiSq)); /* of << para[5]*(exp(Rsq1*one_xiSq) - exp(Rsq2*one_xiSq) + exp(Rsq3*one_xiSq) \ -exp(Rsq4*one_xiSq) + exp(Rsq5*one_xiSq) - exp(Rsq6*one_xiSq)) << " "; */ fill_index = static_cast(ceil(fabs((field/fDB)))); if (fill_index < fPBSize) { fPB[fill_index] += 1.0; } else { cout << "Field over the limit..." << endl; } } // of << endl; } // of.close(); } else { int i,j; #ifdef HAVE_GOMP // cannot use a reduction clause here (like e.g. in Normalize()), since pBvec[] is not a scalar variable // therefore, we need to work on it a bit more int n(omp_get_num_procs()), tid, offset; vector< vector > pBvec(n, vector(fPBSize, 0)); int indexStep(static_cast(floor(static_cast(numberOfSteps_2)/static_cast(n)))); #pragma omp parallel private(tid, i, j, offset, fill_index) num_threads(n) { tid = omp_get_thread_num(); offset = tid*indexStep; if (tid == n-1) { for (j = offset; j < static_cast(numberOfSteps_2); ++j) { for (i = 0; i < static_cast(numberOfSteps_2); ++i) { fill_index = static_cast(ceil(fabs((vortexFields[i + numberOfSteps*j]/fDB)))); if (fill_index < fPBSize) { pBvec[tid][fill_index] += 1; } } } } else { for (j = 0; j < indexStep; ++j) { for (i = 0; i < static_cast(numberOfSteps_2); ++i) { fill_index = static_cast(ceil(fabs((vortexFields[offset + i + numberOfSteps*j]/fDB)))); if (fill_index < fPBSize) { pBvec[tid][fill_index] += 1; } } } } } for (j = 0; j < n; ++j) { #pragma omp parallel for default(shared) private(i) schedule(dynamic) for (i = 0; i < static_cast(fPBSize); ++i) { fPB[i] += static_cast(pBvec[j][i]); } pBvec[j].clear(); } pBvec.clear(); #else for (j = 0; j < static_cast(numberOfSteps_2); ++j) { for (i = 0; i < static_cast(numberOfSteps_2); ++i) { fill_index = static_cast(ceil(fabs((vortexFields[i + numberOfSteps*j]/fDB)))); if (fill_index < fPBSize) { fPB[fill_index] += 1.0; } } } #endif } vortexFields = 0; // normalize P(B) Normalize(); if(para.size() == 5) AddBackground(para[2], para[3], para[4]); fPBExists = true; return; } // TPofBCalc::AddBackground, Parameters: field B[G], width s[us], weight w void TPofBCalc::AddBackground(double B, double s, double w) { if(!s || w<0.0 || w>1.0 || B<0.0) return; int i; double BsSq(s*s/(gBar*gBar*4.0*pi*pi)); // calculate Gaussian background double bg[fPBSize]; #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) #endif for(i = 0; i < static_cast(fPBSize); ++i) { bg[i] = exp(-(fB[i]-B)*(fB[i]-B)/(2.0*BsSq)); } // normalize background double bgsum(0.0); #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) reduction(+:bgsum) #endif for (i = 0; i < static_cast(fPBSize); ++i) bgsum += bg[i]; bgsum *= fDB; #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) #endif for (i = 0; i < static_cast(fPBSize); ++i) bg[i] /= bgsum; // add background to P(B) #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) #endif for (i = 0; i < static_cast(fPBSize); ++i) fPB[i] = (1.0 - w)*fPB[i] + w*bg[i]; // // check if normalization is still valid // double pBsum(0.0); // for (unsigned int i(0); i < sizePB; i++) // pBsum += fPB[i]; // // cout << "pBsum = " << pBsum << endl; } void TPofBCalc::ConvolveGss(double w) { if(!w) return; unsigned int NFFT(fPBSize); double TBin; fftw_plan FFTplanToTimeDomain; fftw_plan FFTplanToFieldDomain; fftw_complex *FFTout; TBin = 1.0/(gBar*static_cast(NFFT-1)*fDB); FFTout = new fftw_complex[NFFT/2 + 1]; //(fftw_complex *)fftw_malloc(sizeof(fftw_complex) * (NFFT/2+1)); // do the FFT to time domain FFTplanToTimeDomain = fftw_plan_dft_r2c_1d(NFFT, fPB, FFTout, FFTW_ESTIMATE); fftw_execute(FFTplanToTimeDomain); // multiply everything by a gaussian double GssInTimeDomain; double expo(-2.0*PI*PI*gBar*gBar*w*w*TBin*TBin); int i; #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(GssInTimeDomain, i) schedule(dynamic) #endif for (i = 0; i < static_cast(NFFT/2+1); ++i) { GssInTimeDomain = exp(expo*static_cast(i*i)); FFTout[i][0] *= GssInTimeDomain; FFTout[i][1] *= GssInTimeDomain; } // FFT back to the field domain FFTplanToFieldDomain = fftw_plan_dft_c2r_1d(NFFT, FFTout, fPB, FFTW_ESTIMATE); fftw_execute(FFTplanToFieldDomain); // cleanup fftw_destroy_plan(FFTplanToTimeDomain); fftw_destroy_plan(FFTplanToFieldDomain); delete[] FFTout; // fftw_free(FFTout); FFTout = 0; // fftw_cleanup(); // normalize p(B) Normalize(); return; } double TPofBCalc::GetFirstMoment() const { int i; double pBsum(0.0); #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i) schedule(dynamic) reduction(+:pBsum) #endif for (i = 0; i < static_cast(fPBSize); ++i) pBsum += fB[i]*fPB[i]; pBsum *= fDB; return pBsum; } double TPofBCalc::GetCentralMoment(unsigned int n) const { double firstMoment(GetFirstMoment()); double diff; int i; double pBsum(0.0); #ifdef HAVE_GOMP #pragma omp parallel for default(shared) private(i, diff) schedule(dynamic) reduction(+:pBsum) #endif for (i = 0; i < static_cast(fPBSize); ++i) { diff = fB[i]-firstMoment; pBsum += pow(diff, static_cast(n))*fPB[i]; } pBsum *= fDB; return pBsum; } double TPofBCalc::GetSkewnessAlpha() const { double M2(GetCentralMoment(2)); double M3(GetCentralMoment(3)); return M3 > 0.0 ? pow(M3, 1.0/3.0)/pow(M2, 0.5) : -pow(-M3, 1.0/3.0)/pow(M2, 0.5); }