41#include <gsl/gsl_histogram.h>
42#include <gsl/gsl_linalg.h>
43#include <gsl/gsl_randist.h>
44#include <gsl/gsl_rng.h>
45#include <gsl/gsl_sf_erf.h>
47#include <boost/regex.hpp>
48#include <boost/numeric/odeint/stepper/runge_kutta4.hpp>
72 for (
unsigned int i = 0; i < 6u; ++i) {
82 "The DISTRIBUTION statement defines data for the 6D particle distribution."),
124 defaultDistribution->
builtin =
true;
129 delete defaultDistribution;
133 randGen_m = gsl_rng_alloc(gsl_rng_default);
207 randGen_m = gsl_rng_alloc(gsl_rng_default);
234 if (myNode < remainder)
263 size_t numberOfLocalParticles = numberOfParticles;
265 numberOfLocalParticles = (numberOfParticles + 1) / 2;
273 mySeed = tv.tv_sec + tv.tv_usec;
278 *
gmsg <<
level2 <<
"* Generation of distribution with seed = " << mySeed <<
" + core_id\n"
279 <<
"* is scalable with number of particles and cores." <<
endl;
282 *
gmsg <<
level2 <<
"* Generation of distribution with seed = " << mySeed <<
"\n"
283 <<
"* isn't scalable with number of particles and cores." <<
endl;
312 "Unknown \"TYPE\" of \"DISTRIBUTION\"");
317 unsigned int numAdditionalRNsPerParticle = 0;
322 numAdditionalRNsPerParticle = 2;
325 numAdditionalRNsPerParticle = 40;
327 numAdditionalRNsPerParticle = 20;
331 int saveProcessor = -1;
336 for (
size_t partIndex = 0; partIndex < numberOfLocalParticles; ++ partIndex) {
340 if (saveProcessor >= numNodes)
343 if (scalable || myNode == saveProcessor) {
344 std::vector<double> rns;
345 for (
unsigned int i = 0; i < numAdditionalRNsPerParticle; ++ i) {
351 for (
unsigned int i = 0; i < numAdditionalRNsPerParticle; ++ i) {
383 size_t firstParticle = numParticlesPerNode *
Ippl::myNode();
384 size_t lastParticle = firstParticle + numParticlesPerNode - 1;
386 lastParticle = numParticles - 1;
389 numParticles = lastParticle - firstParticle + 1;
392 beam->
create(numParticles);
395 dataSource->
readStep(beam, firstParticle, lastParticle);
399 double actualT = beam->
getT();
405 *
gmsg <<
"Total number of particles in the h5 file= " << beam->
getTotalNum() <<
"\n"
406 <<
"Global step= " << gtstep <<
"; Local step= " << ltstep <<
"; "
407 <<
"restart step= " << restartStep <<
"\n"
414 const int specifiedNumBunch,
419 INFOMSG(
"---------------- Start reading hdf5 file----------------" <<
endl);
424 size_t firstParticle = numParticlesPerNode *
Ippl::myNode();
425 size_t lastParticle = firstParticle + numParticlesPerNode - 1;
427 lastParticle = numParticles - 1;
430 numParticles = lastParticle - firstParticle + 1;
433 beam->
create(numParticles);
436 dataSource->
readStep(beam, firstParticle, lastParticle);
446 INFOMSG(
"total number of particles = " << globalN <<
endl);
447 INFOMSG(
"* Restart Energy = " << meanE <<
" (MeV), Path lenght = " << beam->
get_sPos() <<
" (m)" <<
endl);
452 double beta = std::sqrt(1.0 - (1.0 / std::pow(gamma, 2)));
454 INFOMSG(
"* Gamma = " << gamma <<
", Beta = " << beta <<
endl);
457 INFOMSG(
"Restart from hdf5 file generated by OPAL-cycl" <<
endl);
458 if (specifiedNumBunch > 1) {
465 INFOMSG(
"Restart from hdf5 file generated by OPAL-t" <<
endl);
470 for (
unsigned int i = 0; i < newLocalN; ++i) {
471 for (
int d = 0; d < 3; ++d) {
472 meanR(d) += beam->
R[i](d);
473 meanP(d) += beam->
P[i](d);
480 INFOMSG(
"Rmean = " << meanR <<
"[m], Pmean=" << meanP <<
endl);
482 for (
unsigned int i = 0; i < newLocalN; ++i) {
488 INFOMSG(
"---------------Finished reading hdf5 file---------------" <<
endl);
496 throw OpalException(
"Distribution::find()",
"Distribution \"" +
name +
"\" not found.");
513 double tratio = std::sqrt(2.0 * std::log(10.0)) - std::sqrt(2.0 * std::log(10.0 / 9.0));
521 double inv_erf08 = 0.906193802436823;
522 double sqr2 = std::sqrt(2.);
523 double t =
a - sqr2 * sig * inv_erf08;
526 for (
int i = 0; i < 10; ++ i) {
527 sig = (t +
tRise_m -
a) / (sqr2 * inv_erf08);
528 t =
a - 0.5 * sqr2 * (sig + tmps) * inv_erf08;
529 sig = (0.5 * (t + tmpt) +
tRise_m -
a) / (sqr2 * inv_erf08);
549 <<
"* ************* D I S T R I B U T I O N ********************************************" <<
endl;
552 os <<
"* In restart. Distribution read in from .h5 file." <<
endl;
555 os <<
"* Main Distribution" <<
endl
556 <<
"-----------------" <<
endl;
563 size_t distCount = 1;
566 os <<
"* Added Distribution #" << distCount <<
endl;
567 os <<
"* ----------------------" <<
endl;
581 os <<
"* Distribution is emitted. " <<
endl;
588 os <<
"* Distribution is injected." <<
endl;
592 os <<
"*\n* Write initial distribution to file '" <<
outFilename_m <<
"'" <<
endl;
596 os <<
"* **********************************************************************************" <<
endl;
607 std::vector<Distribution *>::iterator addedDistIt;
613 for (
double dist : (*addedDistIt)->getXDist()) {
616 (*addedDistIt)->eraseXDist();
618 for (
double dist : (*addedDistIt)->getBGxDist()) {
621 (*addedDistIt)->eraseBGxDist();
623 for (
double dist : (*addedDistIt)->getYDist()) {
626 (*addedDistIt)->eraseYDist();
628 for (
double dist : (*addedDistIt)->getBGyDist()) {
631 (*addedDistIt)->eraseBGyDist();
633 for (
double dist : (*addedDistIt)->getTOrZDist()) {
636 (*addedDistIt)->eraseTOrZDist();
638 for (
double dist : (*addedDistIt)->getBGzDist()) {
641 (*addedDistIt)->eraseBGzDist();
665 double phi = 2.0 * std::acos(std::sqrt(additionalRNs[0]));
682 std::vector<double> &additionalRNs) {
690 unsigned int counter = 0;
693 double randFuncValue = additionalRNs[counter++];
695 double funcValue = ((1.0
696 - 1.0 / (1.0 + expRelativeEnergy * expRelativeLaserEnergy)) /
697 (1.0 + expRelativeEnergy));
699 if (randFuncValue <= funcValue)
702 if (counter == additionalRNs.size()) {
703 for (
unsigned int i = 0; i < counter; ++ i) {
704 additionalRNs[i] = gsl_rng_uniform(
randGen_m);
711 while (additionalRNs.size() - counter < 2) {
713 additionalRNs[counter] = gsl_rng_uniform(
randGen_m);
718 double energyExternal = energy - lowEnergyLimit;
720 double thetaInMax = std::acos(std::sqrt((lowEnergyLimit +
laserEnergy_m) / (energyInternal)));
721 double thetaIn = additionalRNs[counter++] * thetaInMax;
722 double sinThetaOut = std::sin(thetaIn) * std::sqrt(energyInternal / energyExternal);
726 double betaGammaExternal
729 bgx = betaGammaExternal * sinThetaOut * std::cos(phi);
730 bgy = betaGammaExternal * sinThetaOut * std::sin(phi);
731 bgz = betaGammaExternal * std::sqrt(1.0 - std::pow(sinThetaOut, 2));
742 std::map<unsigned int, size_t> nPartFromFiles;
743 double totalWeight = 0.0;
750 std::ifstream inputFile;
753 inputFile.open(fileName.c_str());
756 nPartFromFiles.insert(std::make_pair(i, nPart));
757 if (nPart > numberOfParticles) {
759 "Number of particles is too small");
762 numberOfParticles -= nPart;
768 size_t numberOfCommittedPart = 0;
777 size_t particlesCurrentDist = numberOfParticles * currDist->
getWeight() / totalWeight;
779 numberOfCommittedPart += particlesCurrentDist;
784 if (numberOfParticles != numberOfCommittedPart) {
785 size_t diffNumber = numberOfParticles - numberOfCommittedPart;
797 if (diffNumber != 0) {
799 "Particles can't be distributed to distributions in array");
815 if (emissionSteps == 0)
846 size_t numberOfDistParticles =
tOrZDist_m.size();
849 if (numberOfDistParticles == 0) {
851 "Zero particles in the distribution! "
852 "The number of particles needs to be specified.");
857 "A single particle distribution works serially on single node");
860 if (numberOfDistParticles != numberOfParticles) {
862 "The number of particles in the initial\n"
864 std::to_string(numberOfDistParticles) +
"\n"
865 "is different from the number of particles\n"
866 "defined by the BEAM command\n" +
867 std::to_string(numberOfParticles) +
".\n"
868 "This often happens when using a FROMFILE type\n"
869 "distribution and not matching the number of\n"
870 "particles in the input distribution file(s) with\n"
871 "the number given in the BEAM command.");
878 if (momentumTol > 0 &&
881 "The z-momentum of the particle distribution\n" +
882 std::to_string(
pmean_m[2]) +
"\n"
883 "is different from the momentum given in the \"BEAM\" command\n" +
885 "When using a \"FROMFILE\" type distribution\n"
886 "the momentum in the \"BEAM\" command should be\n"
887 "the same as the momentum of the particles in the file.");
895 static const std::map<std::string, InputMomentumUnits> stringInputMomentumUnits_s = {
901 if (inputUnits.empty()) {
934 int saveProcessor = -1;
941 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
942 double x = 0.0, y = 0.0, tOrZ = 0.0;
943 double px = 0.0, py = 0.0, pz = 0.0;
953 double randNums[2] = {0.0, 0.0};
955 if (quasiRandGen2D !=
nullptr) {
956 gsl_qrng_get(quasiRandGen2D, randNums);
958 randNums[0] = gsl_rng_uniform(
randGen_m);
959 randNums[1] = gsl_rng_uniform(
randGen_m);
965 for (
unsigned i = 0; i <
nPeaks_m; i++)
967 allow = (r <= proba);
988 if (saveProcessor >= numNodes)
991 if (scalable || myNode == saveProcessor) {
1001 gsl_qrng_free(quasiRandGen2D);
1006 size_t numberOfParticlesRead = 0;
1008 const boost::regex commentExpr(
"[[:space:]]*#.*");
1009 const std::string repl(
"");
1011 std::stringstream linestream;
1015 std::getline(inputFile, line);
1016 line = boost::regex_replace(line, commentExpr, repl);
1017 }
while (line.length() == 0 && !inputFile.fail());
1019 linestream.str(line);
1020 linestream >> tempInt;
1022 throw OpalException(
"Distribution::getNumberOfParticlesInFile",
1025 "' does not seem to be an ASCII file containing a distribution.");
1027 numberOfParticlesRead =
static_cast<size_t>(tempInt);
1031 return numberOfParticlesRead;
1036 std::ifstream inputFile;
1038 if (!std::filesystem::exists(fileName)) {
1040 "Distribution::createDistributionFromFile",
1041 "Open file operation failed, please check if '" + fileName +
"' really exists.");
1044 inputFile.open(fileName.c_str());
1052 unsigned int saveProcessor = 0;
1056 unsigned int distributeFrequency = 1000;
1057 size_t singleDataSize = 6;
1058 unsigned int dataSize = distributeFrequency * singleDataSize;
1059 std::vector<double> data(dataSize);
1062 constexpr unsigned int bufferSize = 1024;
1063 char lineBuffer[bufferSize];
1064 unsigned int numParts = 0;
1065 std::vector<double>::iterator currentPosition = data.begin();
1066 while (!inputFile.eof()) {
1067 inputFile.getline(lineBuffer, bufferSize);
1071 std::istringstream line(lineBuffer);
1091 if (saveProcessor > 0u) {
1092 currentPosition = std::copy(&(R[0]), &(R[0]) + 3, currentPosition);
1093 currentPosition = std::copy(&(P[0]), &(P[0]) + 3, currentPosition);
1095 if (currentPosition == data.end()) {
1097 MPI_Bcast(&(data[0]), dataSize, MPI_DOUBLE, 0,
Ippl::getComm());
1099 currentPosition = data.begin();
1115 (numberOfParticlesRead == numParts ? currentPosition - data.begin()
1116 : std::numeric_limits<unsigned int>::max());
1119 if (numberOfParticlesRead != numParts) {
1121 "Distribution::createDistributionFromFile",
1122 "Found " + std::to_string(numParts) +
" particles in file '" + fileName
1123 +
"' instead of " + std::to_string(numberOfParticlesRead));
1125 MPI_Bcast(&(data[0]), dataSize, MPI_DOUBLE, 0,
Ippl::getComm());
1130 if (dataSize == std::numeric_limits<unsigned int>::max()) {
1132 "Distribution::createDistributionFromFile",
1133 "Couldn't find " + std::to_string(numberOfParticlesRead)
1134 +
" particles in file '" + fileName +
"'");
1136 MPI_Bcast(&(data[0]), dataSize, MPI_DOUBLE, 0,
Ippl::getComm());
1139 while (i < dataSize) {
1141 const double* tmp = &(data[i]);
1149 i += singleDataSize;
1156 }
while (dataSize == distributeFrequency * singleDataSize);
1159 pmean_m /= numberOfParticlesRead;
1177 if (lineName.empty())
return;
1180 if (lineSequence ==
nullptr)
1181 throw OpalException(
"Distribution::CreateMatchedGaussDistribution",
1182 "didn't find any Cyclotron element in line");
1186 size_t NumberOfCyclotrons = CyclotronVisitor.
size();
1188 if (NumberOfCyclotrons > 1) {
1189 throw OpalException(
"Distribution::createMatchedGaussDistribution",
1190 "I am confused, found more than one Cyclotron element in line");
1192 if (NumberOfCyclotrons == 0) {
1193 throw OpalException(
"Distribution::createMatchedGaussDistribution",
1194 "didn't find any Cyclotron element in line");
1207 throw OpalException(
"Distribution::createMatchedGaussDistribution()",
1208 "Negative number of integration steps");
1211 throw OpalException(
"Distribution::createMatchedGaussDistribution()",
1212 "Negative number of sectors");
1214 if ( Nsectors > 1 && full ==
false )
1215 throw OpalException(
"Distribution::createMatchedGaussDistribution()",
1216 "Averaging over sectors can only be done with SECTOR=FALSE");
1218 *
gmsg <<
"* ----------------------------------------------------" <<
endl;
1219 *
gmsg <<
"* About to find closed orbit and matched distribution " <<
endl;
1225 *
gmsg <<
"* SECTOR: " <<
"match using all sectors, with" <<
endl
1226 <<
"* NSECTORS = " << Nsectors <<
" to average the field over" <<
endl;
1229 *
gmsg <<
"* SECTOR: " <<
"match using single sector" <<
endl;
1231 *
gmsg <<
"* NSTEPS = " << Nint <<
endl
1235 <<
"* ----------------------------------------------------" <<
endl;
1237 if ( CyclotronElement->
getFMLowE() < 0 ||
1240 throw OpalException(
"Distribution::createMatchedGaussDistribution()",
1241 "Missing attributes 'FMLOWE' and/or 'FMHIGHE' in "
1242 "'CYCLOTRON' definition.");
1245 std::size_t maxitCOF =
1254 if ( denergy < 0.0 )
1255 throw OpalException(
"Distribution:createMatchedGaussDistribution()",
1262 *
gmsg <<
"* Stopping after closed orbit and tune calculation" <<
endl;
1263 typedef std::vector<double> container_t;
1264 typedef boost::numeric::odeint::runge_kutta4<container_t> rk4_t;
1267 cof_t cof(massIneV *
Units::eV2MeV, charge, Nint, CyclotronElement, full, Nsectors);
1268 cof.findOrbit(accuracy, maxitCOF,
E_m *
Units::eV2MeV, denergy, rguess,
true);
1271 "Do only tune calculation.");
1274 bool writeMap =
true;
1276 std::unique_ptr<SigmaGenerator> siggen = std::unique_ptr<SigmaGenerator>(
1290 if (siggen->match(accuracy,
1298 std::array<double,3> Emit = siggen->getEmittances();
1301 *
gmsg <<
"* RGUESS " << rguess <<
" (m) " <<
endl;
1303 *
gmsg <<
"* Converged (Ex, Ey, Ez) = (" << Emit[0] <<
", " << Emit[1] <<
", "
1305 *
gmsg <<
"* Sigma-Matrix " <<
endl;
1307 for (
unsigned int i = 0; i < siggen->getSigma().size1(); ++ i) {
1308 *
gmsg << std::setprecision(4) << std::setw(11) << siggen->getSigma()(i,0);
1309 for (
unsigned int j = 1; j < siggen->getSigma().size2(); ++ j) {
1310 if (std::abs(siggen->getSigma()(i,j)) < 1.0e-15) {
1311 *
gmsg <<
" & " << std::setprecision(4) << std::setw(11) << 0.0;
1314 *
gmsg <<
" & " << std::setprecision(4) << std::setw(11) << siggen->getSigma()(i,j);
1323 CyclotronElement->
setRinit(siggen->getInjectionRadius());
1324 CyclotronElement->
setPRinit(siggen->getInjectionMomentum());
1329 throw OpalException(
"Distribution::CreateMatchedGaussDistribution",
1330 "didn't find any matched distribution.");
1347 size_t numberOfParticles,
1348 double current,
const Beamline &) {
1356 size_t numberOfPartToCreate = numberOfParticles;
1409 std::vector<Distribution *> addedDistributions,
1410 size_t &numberOfParticles) {
1417 size_t &numberOfParticles) {
1440 addedDist->setDistType();
1466 size_t distCount = 1;
1523 std::vector<std::vector<double> > mirrored;
1531 std::vector<double> tmp;
1532 tmp.push_back((*it).front());
1533 tmp.push_back((*it).back() + 0.5);
1534 mirrored.push_back(tmp);
1539 std::vector<double> tmp((*it).begin() + numAdditionals, (*it).end());
1540 mirrored.push_back(tmp);
1541 (*it).erase((*it).begin() + numAdditionals, (*it).end());
1586 size_t numberOfEmittedParticles = beam->
getLocalNum();
1587 size_t oldNumberOfEmittedParticles = numberOfEmittedParticles;
1596 std::vector<size_t> particlesToBeErased;
1602 for (
size_t particleIndex = 0; particleIndex <
tOrZDist_m.size(); particleIndex++) {
1610 particlesToBeErased.push_back(particleIndex);
1613 double deltaT =
tOrZDist_m.at(particleIndex);
1614 beam->
dt[numberOfEmittedParticles] = deltaT;
1616 double oneOverCDt = 1.0 / (
Physics::c * deltaT);
1618 double px =
pxDist_m.at(particleIndex);
1619 double py =
pyDist_m.at(particleIndex);
1620 double pz =
pzDist_m.at(particleIndex);
1621 std::vector<double> additionalRNs;
1626 "not enough additional particles");
1630 double particleGamma
1636 beam->
R[numberOfEmittedParticles]
1638 + px * deltaT *
Physics::c / (2.0 * particleGamma)),
1639 oneOverCDt * (
yDist_m.at(particleIndex)
1640 + py * deltaT *
Physics::c / (2.0 * particleGamma)),
1641 pz / (2.0 * particleGamma));
1642 beam->
P[numberOfEmittedParticles]
1647 beam->
Ef[numberOfEmittedParticles] =
Vector_t(0.0);
1648 beam->
Bf[numberOfEmittedParticles] =
Vector_t(0.0);
1651 beam->
TriID[numberOfEmittedParticles] = 0;
1652 numberOfEmittedParticles++;
1668 std::vector<size_t>::reverse_iterator ptbErasedIt;
1669 for (ptbErasedIt = particlesToBeErased.rbegin();
1670 ptbErasedIt < particlesToBeErased.rend();
1710 <<
" has emitted all particles (new emit)." <<
endl);
1738 size_t currentEmittedParticles = numberOfEmittedParticles - oldNumberOfEmittedParticles;
1742 return currentEmittedParticles;
1773 double randNums[2] = {0.0, 0.0};
1775 if (quasiRandGen2D !=
nullptr)
1776 gsl_qrng_get(quasiRandGen2D, randNums);
1778 randNums[0] = gsl_rng_uniform(
randGen_m);
1779 randNums[1] = gsl_rng_uniform(
randGen_m);
1782 x1 = 2 * randNums[0] - 1;
1783 x2 = 2 * randNums[1] - 1;
1784 allow = (std::pow(x1, 2) + std::pow(x2, 2) <= 1);
1794 const size_t numberOfParticles =
tOrZDist_m.size();
1795 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
1809 for (
size_t particleIndex = 0; particleIndex <
tOrZDist_m.size(); particleIndex++) {
1811 std::vector<double> partCoord;
1813 partCoord.push_back(
xDist_m.at(particleIndex));
1814 partCoord.push_back(
yDist_m.at(particleIndex));
1815 partCoord.push_back(
tOrZDist_m.at(particleIndex));
1816 partCoord.push_back(
pxDist_m.at(particleIndex));
1817 partCoord.push_back(
pyDist_m.at(particleIndex));
1818 partCoord.push_back(
pzDist_m.at(particleIndex));
1819 partCoord.push_back(0.0);
1849 gsl_qrng *quasiRandGen = gsl_qrng_alloc(gsl_qrng_halton, 2);
1851 int numberOfSampleBins
1853 int numberOfEnergyBins
1856 int binTotal = numberOfSampleBins * numberOfEnergyBins;
1858 double *distributionTable =
new double[binTotal + 1];
1862 double inv_erf08 = 0.906193802436823;
1863 double sqr2 = std::sqrt(2.0);
1864 double t =
a - sqr2 * sig * inv_erf08;
1868 for (
int i = 0; i < 10; ++ i) {
1869 sig = (t +
tRise_m -
a) / (sqr2 * inv_erf08);
1870 t =
a - 0.5 * sqr2 * (sig + tmps) * inv_erf08;
1871 sig = (0.5 * (t + tmpt) +
tRise_m -
a) / (sqr2 * inv_erf08);
1883 double lo = -
tBin_m / 2.0 * numberOfEnergyBins;
1884 double hi =
tBin_m / 2.0 * numberOfEnergyBins;
1885 double dx =
tBin_m / numberOfSampleBins;
1888 double weight = 2.0;
1891 for (
int i = 0; i < binTotal + 1; ++ i, x += dx, weight = 6. - weight) {
1892 distributionTable[i] = gsl_sf_erf((x +
a) / (sqr2 * sig)) - gsl_sf_erf((x -
a) / (sqr2 * sig));
1893 tot += distributionTable[i] * weight;
1895 tot -= distributionTable[binTotal] * (5. - weight);
1896 tot -= distributionTable[0];
1898 int saveProcessor = -1;
1902 double tCoord = 0.0;
1904 int effectiveNumParticles = 0;
1906 std::vector<int> numParticlesInBin(numberOfEnergyBins,0);
1907 for (
int k = 0; k < numberOfEnergyBins; ++ k) {
1908 double loc_fraction = -distributionTable[numberOfSampleBins * k] / tot;
1911 for (
int i = numberOfSampleBins * k; i < numberOfSampleBins * (k + 1) + 1;
1912 ++ i, weight = 6. - weight) {
1913 loc_fraction += distributionTable[i] * weight / tot;
1915 loc_fraction -= distributionTable[numberOfSampleBins * (k + 1)]
1916 * (5. - weight) / tot;
1917 numParticlesInBin[k] =
static_cast<int>(std::round(loc_fraction * numberOfParticles));
1918 effectiveNumParticles += numParticlesInBin[k];
1919 if (numParticlesInBin[k] > numParticlesInBin[largestBin]) largestBin = k;
1922 numParticlesInBin[largestBin] += (numberOfParticles - effectiveNumParticles);
1924 for (
int k = 0; k < numberOfEnergyBins; ++ k) {
1925 gsl_ran_discrete_t *table
1926 = gsl_ran_discrete_preproc(numberOfSampleBins,
1927 &(distributionTable[numberOfSampleBins * k]));
1929 for (
int i = 0; i < numParticlesInBin[k]; i++) {
1931 gsl_qrng_get(quasiRandGen, xx);
1932 tCoord = hi * (xx[1] +
static_cast<int>(gsl_ran_discrete(
randGen_m, table))
1933 - binTotal / 2 + k * numberOfSampleBins) / (binTotal / 2);
1936 if (saveProcessor >= numNodes)
1939 if (scalable || myNode == saveProcessor) {
1944 gsl_ran_discrete_free(table);
1947 gsl_qrng_free(quasiRandGen);
1948 delete [] distributionTable;
1976 for (
unsigned int index = 0; index < 3; index++) {
1980 if (std::abs(emittance(index)) > std::numeric_limits<double>::epsilon()) {
1981 beta(index) = std::pow(
sigmaR_m[index], 2) / emittance(index);
1982 gamma(index) = std::pow(
sigmaP_m[index], 2) / emittance(index);
1984 beta(index) = std::sqrt(std::numeric_limits<double>::max());
1985 gamma(index) = std::sqrt(std::numeric_limits<double>::max());
1988 * std::sqrt(beta(index) * gamma(index));
1995 for (
unsigned int index = 0; index < 3; index++) {
1998 COSCHI[index] = std::sqrt(1.0 / (1.0 + std::pow(alpha(index), 2)));
1999 SINCHI[index] = -alpha(index) * COSCHI[index];
2000 CHI[index] = std::atan2(SINCHI[index], COSCHI[index]);
2002 M[index] = std::sqrt(emittance(index) * beta(index));
2003 PM[index] = std::sqrt(emittance(index) * gamma(index));
2004 L[index] = std::sqrt((
mBinomial_m[index] + 1.0) / 2.0) * M[index];
2005 PL[index] = std::sqrt((
mBinomial_m[index] + 1.0) / 2.0) *
PM[index];
2008 X[index] = L[index];
2009 PX[index] = PL[index];
2012 X[index] = M[index];
2013 PX[index] =
PM[index];
2018 int saveProcessor = -1;
2024 const double tempa = std::copysign(std::sqrt(std::abs(temp)), temp);
2028 const double l33 = std::copysign(std::sqrt(std::abs(temp)), temp);
2035 const double l44 = std::copysign(std::sqrt(std::abs(temp)), temp);
2039 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
2043 double Ux = 0.0, U = 0.0;
2044 double Vx = 0.0, V = 0.0;
2046 A = splitter[0]->get(gsl_rng_uniform(
randGen_m));
2048 Ux = A * std::cos(AL);
2049 Vx = A * std::sin(AL);
2051 p[0] = PX[0] * (Ux * SINCHI[0] + Vx * COSCHI[0]);
2053 A = splitter[1]->get(gsl_rng_uniform(
randGen_m));
2055 U = A * std::cos(AL);
2056 V = A * std::sin(AL);
2058 p[1] = PX[1] * (U * SINCHI[1] + V * COSCHI[1]);
2060 A = splitter[2]->get(gsl_rng_uniform(
randGen_m));
2062 U = A * std::cos(AL);
2063 V = A * std::sin(AL);
2069 if (saveProcessor >= numNodes)
2072 if (scalable || myNode == saveProcessor) {
2082 for (
unsigned int index = 0; index < 3; index++) {
2083 delete splitter[index];
2089 int saveProcessor = -1;
2094 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
2105 if (saveProcessor >= numNodes)
2108 if (scalable || myNode == saveProcessor) {
2127 int saveProcessor = -1;
2131 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
2144 if (saveProcessor >= numNodes)
2147 if (scalable || myNode == saveProcessor) {
2156 gsl_qrng_free(quasiRandGen2D);
2170 int saveProcessor = -1;
2175 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
2188 if (quasiRandGen1D !=
nullptr)
2189 gsl_qrng_get(quasiRandGen1D, &z);
2197 if (saveProcessor >= numNodes)
2200 if (scalable || myNode == saveProcessor) {
2210 gsl_qrng_free(quasiRandGen1D);
2211 gsl_qrng_free(quasiRandGen2D);
2216 gsl_matrix * corMat = gsl_matrix_alloc (6, 6);
2217 gsl_vector * rx = gsl_vector_alloc(6);
2218 gsl_vector * ry = gsl_vector_alloc(6);
2220 for (
unsigned int i = 0; i < 6; ++ i) {
2222 for (
unsigned int j = 0; j < i; ++ j) {
2230 *
gmsg <<
"* m before gsl_linalg_cholesky_decomp" <<
endl;
2231 for (
int i = 0; i < 6; i++) {
2232 for (
int j = 0; j < 6; j++) {
2234 *
gmsg <<
"* r(" << std::setprecision(1) << i <<
", : ) = "
2235 << std::setprecision(4) << std::setw(10) << gsl_matrix_get (corMat, i, j);
2237 *
gmsg <<
" & " << std::setprecision(4) << std::setw(10) << gsl_matrix_get (corMat, i, j);
2246 int errcode = gsl_linalg_cholesky_decomp(corMat);
2275 if (errcode == GSL_EDOM) {
2277 "gsl_linalg_cholesky_decomp failed");
2280 for (
int i = 0; i < 5; ++ i) {
2281 for (
int j = i+1; j < 6 ; ++ j) {
2282 gsl_matrix_set (corMat, i, j, 0.0);
2287 *
gmsg <<
"* m after gsl_linalg_cholesky_decomp" <<
endl;
2288 for (
int i = 0; i < 6; i++) {
2289 for (
int j = 0; j < 6; j++) {
2291 *
gmsg <<
"* r(" << std::setprecision(1) << i <<
", : ) = "
2292 << std::setprecision(4) << std::setw(10) << gsl_matrix_get (corMat, i, j);
2294 *
gmsg <<
" & " << std::setprecision(4) << std::setw(10) << gsl_matrix_get (corMat, i, j);
2300 int saveProcessor = -1;
2305 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
2316 gsl_vector_set(rx, 0, gsl_ran_gaussian(
randGen_m, 1.0));
2317 gsl_vector_set(rx, 1, gsl_ran_gaussian(
randGen_m, 1.0));
2318 gsl_vector_set(rx, 2, gsl_ran_gaussian(
randGen_m, 1.0));
2319 gsl_vector_set(rx, 3, gsl_ran_gaussian(
randGen_m, 1.0));
2320 gsl_vector_set(rx, 4, gsl_ran_gaussian(
randGen_m, 1.0));
2321 gsl_vector_set(rx, 5, gsl_ran_gaussian(
randGen_m, 1.0));
2323 gsl_blas_dgemv(CblasNoTrans, 1.0, corMat, rx, 0.0, ry);
2325 x = gsl_vector_get(ry, 0);
2326 px = gsl_vector_get(ry, 1);
2327 y = gsl_vector_get(ry, 2);
2328 py = gsl_vector_get(ry, 3);
2329 z = gsl_vector_get(ry, 4);
2330 pz = gsl_vector_get(ry, 5);
2332 bool xAndYOk = (std::pow( x /
cutoffR_m[0], 2) + std::pow( y /
cutoffR_m[1], 2) <= 1.0);
2333 bool pxAndPyOk = (std::pow(px /
cutoffP_m[0], 2) + std::pow(py /
cutoffP_m[1], 2) <= 1.0);
2335 bool zOk = (std::abs(z) <=
cutoffR_m[2]);
2336 bool pzOk = (std::abs(pz) <=
cutoffP_m[2]);
2338 allow = (xAndYOk && pxAndPyOk && zOk && pzOk);
2350 if (saveProcessor >= numNodes)
2353 if (scalable || myNode == saveProcessor) {
2365 gsl_vector_free(rx);
2366 gsl_vector_free(ry);
2367 gsl_matrix_free(corMat);
2371 size_t numberOfParticles,
double massIneV)
2384 for (
unsigned int i = 0; i < 3; ++ i) {
2385 if ( sigma(2 * i, 2 * i) < 0 || sigma(2 * i + 1, 2 * i + 1) < 0 )
2387 "Negative value on the diagonal of the sigma matrix.");
2397 sigmaR_m[0] = std::sqrt(sigma(0, 0));
2398 sigmaP_m[0] = std::sqrt(sigma(1, 1)) * bgam;
2401 sigmaR_m[1] = std::sqrt(sigma(4, 4));
2402 sigmaP_m[1] = std::sqrt(sigma(5, 5)) * bgam;
2405 sigmaR_m[2] = std::sqrt(sigma(2, 2));
2406 sigmaP_m[2] = std::sqrt(sigma(3, 3)) * bgam;
2424 A(0, 0) = sigma(0, 0);
2425 A(1, 1) = sigma(1, 1);
2426 A(2, 2) = sigma(4, 4);
2427 A(3, 3) = sigma(5, 5);
2429 A(0, 1) = sigma(0, 1);
2430 A(0, 2) = sigma(0, 4);
2431 A(0, 3) = sigma(0, 5);
2432 A(1, 0) = sigma(1, 0);
2433 A(2, 0) = sigma(4, 0);
2434 A(3, 0) = sigma(5, 0);
2436 A(1, 2) = sigma(1, 4);
2437 A(2, 1) = sigma(4, 1);
2438 A(1, 3) = sigma(1, 5);
2439 A(3, 1) = sigma(5, 1);
2440 A(2, 3) = sigma(4, 5);
2441 A(3, 2) = sigma(5, 4);
2448 for (
int i = 0; i < 4; ++i) {
2449 variances(i) = std::sqrt(A(i, i));
2458 A(2, 2) = sigma(2, 2);
2459 A(3, 3) = sigma(3, 3);
2460 A(2, 3) = sigma(2, 3);
2461 A(3, 2) = sigma(3, 2);
2465 for (
int i = 0; i < 4; ++i) {
2466 variances(4 + i) = std::sqrt(A(i, i));
2469 int saveProcessor = -1;
2475 for (
size_t i = 0; i < numberOfParticles; i++) {
2476 for (
int j = 0; j < 4; j++) {
2477 p1(j) = gsl_ran_gaussian(
randGen_m, 1.0) * variances(j);
2478 p2(j) = gsl_ran_gaussian(
randGen_m, 1.0) * variances(4 + j);
2481 p1 = boost::numeric::ublas::prod(R1, p1);
2482 p2 = boost::numeric::ublas::prod(R2, p2);
2486 if (saveProcessor >= numNodes)
2489 if (scalable || myNode == saveProcessor) {
2505 if (flattopTime < 0.0)
2509 double distArea = flattopTime
2513 size_t numRise = numberOfParticles *
sigmaTRise_m * normalizedFlankArea / distArea;
2514 size_t numFall = numberOfParticles *
sigmaTFall_m * normalizedFlankArea / distArea;
2515 size_t numFlat = numberOfParticles - numRise - numFall;
2518 int saveProcessor = -1;
2523 for (
size_t partIndex = 0; partIndex < numFall; partIndex++) {
2539 if (saveProcessor >= numNodes)
2542 if (scalable || myNode == saveProcessor) {
2553 if (modulationAmp > 1.0)
2554 modulationAmp = 1.0;
2555 double numModulationPeriods
2557 double modulationPeriod = 0.0;
2558 if (numModulationPeriods != 0.0)
2559 modulationPeriod = flattopTime / numModulationPeriods;
2564 for (
size_t partIndex = 0; partIndex < numFlat; partIndex++) {
2569 if (modulationAmp == 0.0 || numModulationPeriods == 0.0) {
2571 if (quasiRandGen1D !=
nullptr)
2572 gsl_qrng_get(quasiRandGen1D, &t);
2576 t = flattopTime * t;
2581 double randNums[2] = {0.0, 0.0};
2583 if (quasiRandGen2D !=
nullptr) {
2584 gsl_qrng_get(quasiRandGen2D, randNums);
2586 randNums[0]= gsl_rng_uniform(
randGen_m);
2587 randNums[1]= gsl_rng_uniform(
randGen_m);
2589 t = randNums[0] * flattopTime;
2591 double funcValue = (1.0 + modulationAmp
2593 / (1.0 + std::abs(modulationAmp));
2595 allow = (randNums[1] <= funcValue);
2603 if (saveProcessor >= numNodes)
2606 if (scalable || myNode == saveProcessor) {
2613 for (
size_t partIndex = 0; partIndex < numRise; partIndex++) {
2629 if (saveProcessor >= numNodes)
2632 if (scalable || myNode == saveProcessor) {
2638 gsl_qrng_free(quasiRandGen1D);
2639 gsl_qrng_free(quasiRandGen2D);
2645 gsl_matrix * corMat = gsl_matrix_alloc (4, 4);
2646 gsl_vector * rx = gsl_vector_alloc(4);
2647 gsl_vector * ry = gsl_vector_alloc(4);
2649 for (
unsigned int i = 0; i < 4; ++ i) {
2651 for (
unsigned int j = 0; j < i; ++ j) {
2657 int errcode = gsl_linalg_cholesky_decomp(corMat);
2659 if (errcode == GSL_EDOM) {
2660 throw OpalException(
"Distribution::GenerateTransverseGauss",
2661 "gsl_linalg_cholesky_decomp failed");
2664 for (
int i = 0; i < 3; ++ i) {
2665 for (
int j = i+1; j < 4 ; ++ j) {
2666 gsl_matrix_set (corMat, i, j, 0.0);
2670 int saveProcessor = -1;
2675 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
2685 gsl_vector_set(rx, 0, gsl_ran_gaussian (
randGen_m,1.0));
2686 gsl_vector_set(rx, 1, gsl_ran_gaussian (
randGen_m,1.0));
2687 gsl_vector_set(rx, 2, gsl_ran_gaussian (
randGen_m,1.0));
2688 gsl_vector_set(rx, 3, gsl_ran_gaussian (
randGen_m,1.0));
2690 gsl_blas_dgemv(CblasNoTrans, 1.0, corMat, rx, 0.0, ry);
2691 x = gsl_vector_get(ry, 0);
2692 px = gsl_vector_get(ry, 1);
2693 y = gsl_vector_get(ry, 2);
2694 py = gsl_vector_get(ry, 3);
2696 bool xAndYOk = (std::pow( x /
cutoffR_m[0], 2) + std::pow( y /
cutoffR_m[1], 2) <= 1.0);
2697 bool pxAndPyOk = (std::pow(px /
cutoffP_m[0], 2) + std::pow(py /
cutoffP_m[1], 2) <= 1.0);
2699 allow = (xAndYOk && pxAndPyOk);
2709 if (saveProcessor >= numNodes)
2712 if (scalable || myNode == saveProcessor) {
2720 gsl_matrix_free(corMat);
2721 gsl_vector_free(rx);
2722 gsl_vector_free(ry);
2744 bool hasID1 = !id1.empty();
2745 bool hasID2 = !id2.empty();
2747 if (hasID1 || hasID2)
2748 *
gmsg <<
"* Use special ID1 or ID2 particle in distribution" <<
endl;
2751 size_t numberOfParticles =
tOrZDist_m.size();
2752 beam->
create(numberOfParticles);
2753 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
2769 beam->
TriID[partIndex] = 0;
2772 beam->
Bin[partIndex] = binNumber;
2775 beam->
Bin[partIndex] = 0;
2778 if (beam->
ID[partIndex] == 1) {
2779 beam->
R[partIndex] =
Vector_t(id1[0],id1[1],id1[2]);
2780 beam->
P[partIndex] =
Vector_t(id1[3],id1[4],id1[5]);
2785 if (beam->
ID[partIndex] == 2) {
2786 beam->
R[partIndex] =
Vector_t(id2[0],id2[1],id2[2]);
2787 beam->
P[partIndex] =
Vector_t(id2[3],id2[4],id2[5]);
2813 double maxTOrZ = std::numeric_limits<int>::min();
2826 double minTOrZ = std::numeric_limits<int>::max();
2883 if (numberOfParticles > 0) {
2886 os <<
"* Number of particles: "
2892 os <<
"* Distribution input momentum units: ";
2895 os <<
"[Beta Gamma]" <<
"\n* " <<
endl;
2899 os <<
"[eV/c]" <<
"\n* " <<
endl;
2904 "Unknown \"INPUTMOUNITS\" for \"DISTRIBUTION\" command");
2930 "Unknown \"TYPE\" of \"DISTRIBUTION\"");
2936 os <<
"* Distribution type: BINOMIAL" <<
endl;
2941 os <<
"* SIGMAT = " <<
sigmaR_m[2] <<
" [sec]" <<
endl;
2944 os <<
"* SIGMAPX = " <<
sigmaP_m[0] <<
" [Beta Gamma]" <<
endl;
2945 os <<
"* SIGMAPY = " <<
sigmaP_m[1] <<
" [Beta Gamma]" <<
endl;
2946 os <<
"* SIGMAPZ = " <<
sigmaP_m[2] <<
" [Beta Gamma]" <<
endl;
2967 os <<
"* Distribution type: ASTRAFLATTOPTH" <<
endl;
2971 os <<
"* Distribution type: GUNGAUSSFLATTOPTH" <<
endl;
2975 os <<
"* Distribution type: FLATTOP" <<
endl;
2983 os <<
"* Transverse profile determined by laser image: " <<
endl
3000 os <<
"* Time Rise = " <<
tRise_m
3001 <<
" [sec]" <<
endl;
3003 <<
" [sec]" <<
endl;
3007 <<
" [sec]" <<
endl;
3009 <<
" [sec]" <<
endl;
3011 <<
" [sec]" <<
endl;
3012 os <<
"* Longitudinal cutoff = " <<
cutoffR_m[2]
3013 <<
" [units of Sigma Time]" <<
endl;
3014 os <<
"* Flat top modulation amplitude = "
3016 <<
" [Percent of distribution amplitude]" <<
endl;
3017 os <<
"* Flat top modulation periods = "
3029 os <<
"* Distribution type: MULTIGAUSS" <<
endl;
3036 std::string longUnits;
3038 longUnits =
" [sec]";
3042 os <<
"* SIGMAZ = " <<
sigmaR_m[2] << longUnits <<
endl;
3043 os <<
"* CUTOFFLONG = " <<
cutoffR_m[2] <<
" [units of SIGMAZ]" <<
endl;
3048 os <<
"* SIGMAPX = " <<
sigmaP_m[0] <<
" [Beta Gamma]" <<
endl;
3049 os <<
"* SIGMAPY = " <<
sigmaP_m[1] <<
" [Beta Gamma]" <<
endl;
3050 os <<
"* SIGMAPZ = " <<
sigmaP_m[2] <<
" [Beta Gamma]" <<
endl;
3051 os <<
"* CUTOFFPX = " <<
cutoffP_m[0] <<
" [units of SIGMAPX]" <<
endl;
3052 os <<
"* CUTOFFPY = " <<
cutoffP_m[1] <<
" [units of SIGMAPY]" <<
endl;
3053 os <<
"* CUTOFFPZ = " <<
cutoffP_m[2] <<
" [units of SIGMAPZ]" <<
endl;
3058 os <<
"* Distribution type: FROMFILE" <<
endl;
3060 os <<
"* Input file: '"
3066 os <<
"* Distribution type: MATCHEDGAUSS" <<
endl;
3070 os <<
"* SIGMAPX = " <<
sigmaP_m[0] <<
" [Beta Gamma]" <<
endl;
3071 os <<
"* SIGMAPY = " <<
sigmaP_m[1] <<
" [Beta Gamma]" <<
endl;
3072 os <<
"* SIGMAPZ = " <<
sigmaP_m[2] <<
" [Beta Gamma]" <<
endl;
3091 os <<
"* Distribution type: GAUSS" <<
endl;
3095 <<
" [sec]" <<
endl;
3097 <<
" [sec]" <<
endl;
3099 <<
" [sec]" <<
endl;
3100 os <<
"* Longitudinal cutoff = " <<
cutoffR_m[2]
3101 <<
" [units of Sigma Time]" <<
endl;
3102 os <<
"* Flat top modulation amplitude = "
3104 <<
" [Percent of distribution amplitude]" <<
endl;
3105 os <<
"* Flat top modulation periods = "
3110 os <<
"* SIGMAPX = " <<
sigmaP_m[0]
3111 <<
" [Beta Gamma]" <<
endl;
3112 os <<
"* SIGMAPY = " <<
sigmaP_m[1]
3113 <<
" [Beta Gamma]" <<
endl;
3117 <<
" [units of SIGMAX]" <<
endl;
3119 <<
" [units of SIGMAY]" <<
endl;
3121 <<
" [units of SIGMAPX]" <<
endl;
3123 <<
" [units of SIGMAPY]" <<
endl;
3128 os <<
"* SIGMAPX = " <<
sigmaP_m[0] <<
" [Beta Gamma]" <<
endl;
3129 os <<
"* SIGMAPY = " <<
sigmaP_m[1] <<
" [Beta Gamma]" <<
endl;
3130 os <<
"* SIGMAPZ = " <<
sigmaP_m[2] <<
" [Beta Gamma]" <<
endl;
3131 os <<
"* AVRGPZ = " <<
avrgpz_m <<
" [Beta Gamma]" <<
endl;
3140 os <<
"* CUTOFFX = " <<
cutoffR_m[0] <<
" [units of SIGMAX]" <<
endl;
3141 os <<
"* CUTOFFY = " <<
cutoffR_m[1] <<
" [units of SIGMAY]" <<
endl;
3142 os <<
"* CUTOFFLONG = " <<
cutoffR_m[2] <<
" [units of SIGMAZ]" <<
endl;
3143 os <<
"* CUTOFFPX = " <<
cutoffP_m[0] <<
" [units of SIGMAPX]" <<
endl;
3144 os <<
"* CUTOFFPY = " <<
cutoffP_m[1] <<
" [units of SIGMAPY]" <<
endl;
3145 os <<
"* CUTOFFPZ = " <<
cutoffP_m[2] <<
" [units of SIGMAPY]" <<
endl;
3151 os <<
"* ------------- THERMAL EMITTANCE MODEL --------------------------------------------" <<
endl;
3168 os <<
"* ----------------------------------------------------------------------------------" <<
endl;
3173 os <<
"* THERMAL EMITTANCE in ASTRA MODE" <<
endl;
3174 os <<
"* Kinetic energy (thermal emittance) = "
3176 <<
" [eV] " <<
endl;
3180 os <<
"* THERMAL EMITTANCE in NONE MODE" <<
endl;
3181 os <<
"* Kinetic energy added to longitudinal momentum = "
3183 <<
" [eV] " <<
endl;
3187 os <<
"* THERMAL EMITTANCE in NONEQUIL MODE" <<
endl;
3204 <<
" contains " <<
sum <<
" particles" <<
endl;
3229 for (
size_t partIndex = 0; partIndex < currentNumPart; partIndex++) {
3242 (numberOfParticles + 1) / 2 != numberOfParticles / 2) {
3264 for (
size_t particleIndex = 0; particleIndex <
tOrZDist_m.size(); ++ particleIndex) {
3265 xDist_m.at(particleIndex) *= xmult;
3266 pxDist_m.at(particleIndex) *= pxmult;
3267 yDist_m.at(particleIndex) *= ymult;
3268 pyDist_m.at(particleIndex) *= pymult;
3270 pzDist_m.at(particleIndex) *= pzmult;
3276 gsl_qrng *quasiRandGen =
nullptr;
3280 quasiRandGen = gsl_qrng_alloc(gsl_qrng_halton, dimension);
3282 quasiRandGen = gsl_qrng_alloc(gsl_qrng_sobol, dimension);
3284 quasiRandGen = gsl_qrng_alloc(gsl_qrng_niederreiter_2, dimension);
3287 quasiRandGen = gsl_qrng_alloc(gsl_qrng_halton, dimension);
3290 return quasiRandGen;
3301 "GUNGAUSSFLATTOPTH",
3309 =
Attributes::makeReal(
"EX",
"Projected normalized emittance EX (m-rad), used to create matched distribution ", 1E-6);
3311 =
Attributes::makeReal(
"EY",
"Projected normalized emittance EY (m-rad) used to create matched distribution ", 1E-6);
3313 =
Attributes::makeReal(
"ET",
"Projected normalized emittance ET (m-rad) used to create matched distribution ", 1E-6);
3317 =
Attributes::makeReal(
"RESIDUUM",
"Residuum for the closed orbit finder and sigma matrix generator ", 1e-8);
3326 " (false: using all sectors) (default: true)",
3329 =
Attributes::makeReal(
"NSTEPS",
"Number of integration steps of closed orbit finder (matched gauss)"
3330 " (default: 720)", 720);
3339 =
Attributes::makeReal(
"NSECTORS",
"Number of sectors to average field, for closed orbit finder ", 1);
3351 "distribution list.", 1.0);
3359 "an injected beam.",
false);
3366 {
"NONE",
"ASTRA",
"NONEQUIL"},
"NONE");
3369 "model (eV). (Thermal energy added in with random "
3370 "number generator.)", 1.0);
3373 "emission. (Default 255 nm light.)", 4.86);
3376 " (Default atomically clean copper.)", 4.31);
3379 " (Default atomically clean copper.)", 7.0);
3382 " (Default 300 K.)", 300.0);
3385 "charge solve.", 0.0);
3431 "Gaussian peaks in MultiGauss "
3432 "distribution.", 0.0);
3434 " pulses in MultiGauss "
3435 "distribution.", 0.0);
3438 "0.0 ... infinity.", 10001.0);
3441 "0.0 ... infinity.", 10001.0);
3444 "0.0 ... infinity.", 10001.0);
3447 "0.0 ... infinity.", 10001.0);
3450 "direction in units of sigma.", 3.0);
3452 "direction in units of sigma.", 3.0);
3454 "direction in units of sigma.", 3.0);
3457 "units of sigma.", 3.0);
3459 "dimension in units of sigma.", 3.0);
3461 "dimension in units of sigma.", 3.0);
3463 "dimension in units of sigma.", 3.0);
3467 "on flat top portion of emitted GAUSS "
3468 "distribtuion (in percent of flat top "
3472 "flat top portion of emitted GAUSS "
3473 "distribution", 0.0);
3512 "profile (x,y).",
"");
3517 "image profile, in % of max intensity.",
3524 =
Attributes::makeBool(
"ROTATE90",
"Rotate laser profile 90 degrees counter clockwise",
false);
3526 =
Attributes::makeBool(
"ROTATE180",
"Rotate laser profile 180 degrees counter clockwise",
false);
3528 =
Attributes::makeBool(
"ROTATE270",
"Rotate laser profile 270 degrees counter clockwise",
false);
3542 "respect of number of particles and number of cores",
false);
3556 "when emitting a distribution.", 100.0);
3606 "The attribute \"DISTRIBUTION\" isn't supported any more, use \"TYPE\" instead");
3609 static const std::map<std::string, DistributionType> typeStringToDistType_s = {
3624 "The attribute \"TYPE\" isn't set for the \"DISTRIBUTION\"!");
3652 WARNMSG(
"The attribute SIGMAPT may be removed in a future version\n"
3653 <<
"use SIGMAPZ instead" <<
endl);
3690 double deltaT = maxT - minT;
3704 double deltaT = maxT - minT;
3721 throw OpalException(
"Distribution::setDistParametersBinomial",
3722 "Attribute R is not supported for binomial distribution\n"
3723 "use CORR[X|Y|Z] and R51, R52, R61, R62 instead");
3799 double timeRatio = std::sqrt(2.0 * std::log(10.0)) - std::sqrt(2.0 * std::log(10.0 / 9.0));
3884 if (cr.size() == 15) {
3885 *
gmsg <<
"* Use r to specify correlations" <<
endl;
3887 for (
unsigned int i = 0; i < 5; ++ i) {
3888 for (
unsigned int j = i + 1; j < 6; ++ j, ++ k) {
3896 "Inconsistent set of correlations specified, check manual");
3932 double timeRatio = std::sqrt(2.0 * std::log(10.0)) - std::sqrt(2.0 * std::log(10.0 / 9.0));
3950 for (
int i=0; i<3; i++) {
3952 cutoffR_m[i] = std::numeric_limits<double>::max();
3954 cutoffP_m[i] = std::numeric_limits<double>::max();
3960 static const std::map<std::string, EmissionModel> stringEmissionModel_s = {
3967 if (model.empty()) {
4009 size_t numParticles =
pzDist_m.size();
4012 avgPz /= numParticles;
4059 "PT is obsolete. The moments of the beam is defined with OFFSETPZ");
4062 const double pz = beam->
getP()/beam->
getM();
4063 double gamma = std::hypot(pz, 1.0);
4108 double avgZ[] = {0.0, 1.0 *
tOrZDist_m.size()};
4129 size_t startIdx = 0;
4144 "Attribute T isn't supported anymore; use OFFSETZ instead");
4147 double deltaTOrZ = 0.0;
4157 WARNMSG(
"PT & PZ are obsolete and will be ignored. The moments of the beam is defined with PC" <<
endl);
4167 for (
size_t particleIndex = startIdx; particleIndex < endIdx; ++ particleIndex) {
4168 xDist_m.at(particleIndex) += deltaX;
4169 pxDist_m.at(particleIndex) += deltaPx;
4170 yDist_m.at(particleIndex) += deltaY;
4171 pyDist_m.at(particleIndex) += deltaPy;
4173 pzDist_m.at(particleIndex) += deltaPz;
4197 if (outputFile.bad()) {
4200 outputFile.setf(std::ios::left);
4202 outputFile.width(17);
4203 outputFile <<
"x [m]";
4204 outputFile.width(17);
4205 outputFile <<
"px [betax gamma]";
4206 outputFile.width(17);
4207 outputFile <<
"y [m]";
4208 outputFile.width(17);
4209 outputFile <<
"py [betay gamma]";
4211 outputFile.width(17);
4212 outputFile <<
"t [s]";
4214 outputFile.width(17);
4215 outputFile <<
"z [m]";
4217 outputFile.width(17);
4218 outputFile <<
"pz [betaz gamma]" ;
4220 outputFile.width(17);
4221 outputFile <<
"Bin Number" << std::endl;
4224 outputFile.width(17);
4225 outputFile <<
"Bin Number";
4227 outputFile << std::endl;
4229 outputFile <<
"# " << totalNum << std::endl;
4250 std::vector<char> msgbuf;
4251 const size_t bitsPerParticle = (6 *
sizeof(double) +
sizeof(size_t));
4252 size_t totalSendBits =
xWrite_m.size() * bitsPerParticle;
4266 if (totalSendBits > 0) {
4267 msgbuf.reserve(totalSendBits);
4269 for (
size_t idx = 0; idx <
xWrite_m.size(); ++ idx) {
4270 buffer =
reinterpret_cast<const char*
>(&(
xWrite_m[idx]));
4271 msgbuf.insert(msgbuf.end(), buffer, buffer +
sizeof(
double));
4272 buffer =
reinterpret_cast<const char*
>(&(
pxWrite_m[idx]));
4273 msgbuf.insert(msgbuf.end(), buffer, buffer +
sizeof(
double));
4274 buffer =
reinterpret_cast<const char*
>(&(
yWrite_m[idx]));
4275 msgbuf.insert(msgbuf.end(), buffer, buffer +
sizeof(
double));
4276 buffer =
reinterpret_cast<const char*
>(&(
pyWrite_m[idx]));
4277 msgbuf.insert(msgbuf.end(), buffer, buffer +
sizeof(
double));
4278 buffer =
reinterpret_cast<const char*
>(&(
tOrZWrite_m[idx]));
4279 msgbuf.insert(msgbuf.end(), buffer, buffer +
sizeof(
double));
4280 buffer =
reinterpret_cast<const char*
>(&(
pzWrite_m[idx]));
4281 msgbuf.insert(msgbuf.end(), buffer, buffer +
sizeof(
double));
4282 buffer =
reinterpret_cast<const char*
>(&(
binWrite_m[idx]));
4283 msgbuf.insert(msgbuf.end(), buffer, buffer +
sizeof(
size_t));
4286 Ippl::Comm->raw_send(&(msgbuf[0]), totalSendBits, 0, tag);
4290 if (outputFile.bad()) {
4293 if (numberOfBits[node] == 0)
continue;
4294 char *recvbuf =
new char[numberOfBits[node]];
4295 Ippl::Comm->raw_receive(recvbuf, numberOfBits[node], node, tag);
4300 outputFile.precision(9);
4301 outputFile.setf(std::ios::scientific);
4302 outputFile.setf(std::ios::right);
4304 for (
size_t partIndex = 0; partIndex <
xWrite_m.size(); partIndex++) {
4306 outputFile << std::setw(17) <<
xWrite_m.at(partIndex)
4307 << std::setw(17) <<
pxWrite_m.at(partIndex)
4308 << std::setw(17) <<
yWrite_m.at(partIndex)
4309 << std::setw(17) <<
pyWrite_m.at(partIndex)
4311 << std::setw(17) <<
pzWrite_m.at(partIndex)
4312 << std::setw(17) <<
binWrite_m.at(partIndex) << std::endl;
4317 if (numberOfBits[i] > 0) numSenders ++;
4320 for (
int i = 0; i < numSenders; ++ i) {
4323 const int bufsize =
Ippl::Comm->raw_probe_receive(recvbuf, node, tag);
4326 while (j < bufsize) {
4327 const double *dbuffer =
reinterpret_cast<const double*
>(recvbuf + j);
4328 const size_t *sbuffer =
reinterpret_cast<const size_t*
>(recvbuf + j + 6 *
sizeof(double));
4329 outputFile << std::setw(17) << dbuffer[0]
4330 << std::setw(17) << dbuffer[1]
4331 << std::setw(17) << dbuffer[2]
4332 << std::setw(17) << dbuffer[3]
4333 << std::setw(17) << dbuffer[4]
4334 << std::setw(17) << dbuffer[5]
4335 << std::setw(17) << sbuffer[0]
4337 j += bitsPerParticle;
4365 for (
int nodeIndex = 0; nodeIndex <
Ippl::getNodes(); nodeIndex++) {
4368 size_t numberOfParticles = 0;
4371 if (outputFile.bad()) {
4376 outputFile.precision(9);
4377 outputFile.setf(std::ios::scientific);
4378 outputFile.setf(std::ios::right);
4381 for (
size_t partIndex = 0; partIndex < numberOfParticles; partIndex++) {
4383 outputFile.width(17);
4384 outputFile <<
xDist_m.at(partIndex);
4385 outputFile.width(17);
4386 outputFile <<
pxDist_m.at(partIndex);
4387 outputFile.width(17);
4388 outputFile <<
yDist_m.at(partIndex);
4389 outputFile.width(17);
4390 outputFile <<
pyDist_m.at(partIndex);
4391 outputFile.width(17);
4393 outputFile.width(17);
4394 outputFile <<
pzDist_m.at(partIndex);
4397 outputFile.width(17);
4398 outputFile << binNumber;
4400 outputFile << std::endl;
4413 return 2.0 * std::sqrt(1.0 - std::pow(rand,
ami_m));
4417 return std::sqrt(-2.0 * std::log(rand));
4439 for (
unsigned int i = 0; i <
pzDist_m.size(); ++ i) {
4442 (std::pow(
pxDist_m[i] + deltaPx, 2) +
4445 allreduce(&(avrg[0]), 6, std::plus<double>());
4451 for (
unsigned int i = 0; i <
pzDist_m.size(); ++ i) {
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
Tps< T > exp(const Tps< T > &x)
Exponential.
boost::numeric::ublas::matrix< double > matrix_t
constexpr double SMALLESTCUTOFF
void allreduce(const T *input, T *output, int count, Op op)
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
T::PETE_Expr_t::PETE_Return_t sum(const PETE_Expr< T > &expr)
Inform & level2(Inform &inf)
Inform & endl(Inform &inf)
Inform & level1(Inform &inf)
Inform & level3(Inform &inf)
Attribute makeBool(const std::string &name, const std::string &help)
Make logical attribute.
double getReal(const Attribute &attr)
Return real value.
Attribute makePredefinedString(const std::string &name, const std::string &help, const std::initializer_list< std::string > &predefinedStrings)
Make predefined string attribute.
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
bool getBool(const Attribute &attr)
Return logical value.
Attribute makeRealArray(const std::string &name, const std::string &help)
Create real array attribute.
std::vector< double > getRealArray(const Attribute &attr)
Get array value.
std::string getString(const Attribute &attr)
Get string value.
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
constexpr double kB
Boltzman's constant in eV/K.
constexpr double two_pi
The value of.
constexpr double epsilon_0
The permittivity of vacuum in As/Vm.
constexpr double q_e
The elementary charge in As.
constexpr double m_e
The electron rest mass in GeV.
constexpr double c
The velocity of light in m/s.
constexpr double pi
The value of.
constexpr double rad2mrad
std::string rngtype
random number generator
bool cloTuneOnly
Do closed orbit and tune calculation only.
bool cZero
If true create symmetric distribution.
int seed
The current random seed.
std::string combineFilePath(std::initializer_list< std::string > ilist)
double convertMomentumEVoverCToBetaGamma(double p, double mass)
double getBetaGamma(double Ekin, double mass)
The base class for all OPAL beam lines and sequences.
virtual Beamline * fetchLine() const =0
Return the embedded CLASSIC beam line.
static BeamSequence * find(const std::string &name)
Find a BeamSequence by name.
Definition(int size, const char *name, const char *help)
Constructor for exemplars.
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
const std::string & getOpalName() const
Return object name.
Object(int size, const char *name, const char *help)
Constructor for exemplars.
std::vector< Attribute > itsAttr
The object attributes.
bool builtin
Built-in flag.
void setEnergyBins(int numberOfEnergyBins)
ParticleAttrib< Vector_t > Ef
ParticleAttrib< int > Bin
int getSteptoLastInj() const
void setNumBunch(short n)
double getMassPerParticle() const
double getQ() const
Access to reference data.
double getChargePerParticle() const
get the macro particle charge
size_t getLocalNum() const
ParticleAttrib< double > M
size_t getTotalNum() const
ParticleAttrib< Vector_t > P
ParticleAttrib< ParticleType > PType
ParticleAttrib< ParticleOrigin > POrigin
ParticleAttrib< double > Q
double getInitialGamma() const
ParticleType getPType() const
IpplTimings::TimerRef distrReload_m
timer for IC, can not be in Distribution.h
long long getLocalTrackStep() const
short getNumBunch() const
ParticleAttrib< int > TriID
ParticleAttrib< double > dt
ParticleAttrib< Vector_t > Bf
IpplTimings::TimerRef distrCreate_m
double getMomentumTolerance() const
void setPBins(PartBins *pbin)
long long getGlobalTrackStep() const
void setTEmission(double t)
void iterateEmittedBin(int binNumber)
std::string getInputBasename()
get input file name without extension
double getGlobalPhaseShift()
units: (sec)
Object * find(const std::string &name)
Find entry.
static OpalData * getInstance()
void define(Object *newObject)
Define a new object.
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
void addProblemCharacteristicValue(const std::string &name, unsigned int value)
virtual double getCyclHarm() const
virtual std::string getFieldMapFN() const
virtual double getFMHighE() const
virtual double getPHIinit() const
void setPRinit(double prinit)
void setRinit(double rinit)
virtual double getFMLowE() const
virtual void execute()
Execute the algorithm on the attached beam line.
An abstract sequence of beam line components.
void shiftDistCoordinates(double massIneV)
static Distribution * find(const std::string &name)
void setDistParametersBinomial(double massIneV)
std::vector< double > & getBGzDist()
std::vector< double > & getTOrZDist()
PartData particleRefData_m
std::vector< double > xWrite_m
Vector_t pmean_m
Total thermal momentum.
void generateFlattopT(size_t numberOfParticles)
double cathodeTemp_m
Cathode material Fermi energy (eV).
void createOpalCycl(PartBunchBase< double, 3 > *beam, size_t numberOfParticles, double current, const Beamline &bl)
void adjustPhaseSpace(double massIneV)
std::vector< double > pxWrite_m
void writeOutFileHeader()
void checkEmissionParameters()
std::string outFilename_m
std::vector< double > tOrZDist_m
double tPulseLengthFWHM_m
int getNumberOfEnergyBins()
virtual void execute()
Execute the command.
gsl_histogram * energyBinHist_m
Distribution energy bins.
void setupEmissionModelAstra(PartBunchBase< double, 3 > *beam)
void printEnergyBins(Inform &os) const
std::vector< std::vector< double > > additionalRNs_m
Upper limit on emission energy distribution (eV).
std::vector< double > pxDist_m
std::vector< double > yWrite_m
double getEmissionDeltaT()
void printDistBinomial(Inform &os) const
double cathodeFermiEnergy_m
Laser photon energy (eV).
double emitEnergyUpperLimit_m
Cathode temperature (K).
void calcPartPerDist(size_t numberOfParticles)
unsigned int numberOfDistributions_m
List of Distribution types.
void initializeBeam(PartBunchBase< double, 3 > *beam)
void doRestartOpalT(PartBunchBase< double, 3 > *p, size_t Np, int restartStep, H5PartWrapper *h5wrapper)
void applyEmissModelNonEquil(double eZ, double &px, double &py, double &pz, std::vector< double > &additionalRNs)
std::vector< double > & getBGxDist()
void createOpalT(PartBunchBase< double, 3 > *beam, std::vector< Distribution * > addedDistributions, size_t &numberOfParticles)
void generateAstraFlattopT(size_t numberOfParticles)
size_t getNumberOfParticlesInFile(std::ifstream &inputFile)
void createDistributionBinomial(size_t numberOfParticles, double massIneV)
void setupEmissionModelNone(PartBunchBase< double, 3 > *beam)
virtual bool canReplaceBy(Object *object)
Distribution can only be replaced by another distribution.
std::vector< Distribution * > addedDistributions_m
Vector of distributions to be added to this distribution.
void doRestartOpalCycl(PartBunchBase< double, 3 > *p, size_t Np, int restartStep, const int specifiedNumBunch, H5PartWrapper *h5wrapper)
std::vector< double > tOrZWrite_m
std::vector< double > & getXDist()
size_t getNumberOfEmissionSteps()
void injectBeam(PartBunchBase< double, 3 > *beam)
std::string laserImageName_m
void create(size_t &numberOfParticles, double massIneV, double charge)
std::vector< double > pyDist_m
int getLastEmittedEnergyBin()
void createDistributionMultiGauss(size_t numberOfParticles, double massIneV)
double laserEnergy_m
Cathode material work function (eV).
void setEmissionTime(double &maxT, double &minT)
matrix_t correlationMatrix_m
void setupEnergyBins(double maxTOrZ, double minTOrZ)
void printEmissionModelNone(Inform &os) const
DistributionType distrTypeT_m
Distribution type strings.
LaserProfile * laserProfile_m
std::vector< double > yDist_m
void generateFlattopZ(size_t numberOfParticles)
std::vector< size_t > particlesPerDist_m
void generateMatchedGauss(const SigmaGenerator::matrix_t &, size_t numberOfParticles, double massIneV)
double tRise_m
time binned distribution with thermal energy
void setSigmaP_m(double massIneV)
std::string laserProfileFileName_m
std::vector< double > & getYDist()
void printDistFromFile(Inform &os) const
virtual Distribution * clone(const std::string &name)
Return a clone.
double getEmissionTimeShift() const
void printDistMultiGauss(Inform &os) const
void reflectDistribution(size_t &numberOfParticles)
std::vector< double > pzWrite_m
virtual void update()
Update this object.
void generateLongFlattopT(size_t numberOfParticles)
void setDistParametersFlattop(double massIneV)
void printDistFlattop(Inform &os) const
void printDistMatchedGauss(Inform &os) const
static const double percentTEmission_m
void writeOutFileEmission()
void printEmissionModelAstra(Inform &os) const
void printEmissionModelNonEquil(Inform &os) const
void generateBinomial(size_t numberOfParticles)
std::vector< double > & getBGyDist()
void setupParticleBins(double massIneV, PartBunchBase< double, 3 > *beam)
void sampleUniformDisk(gsl_qrng *quasiRandGen2D, double &x1, double &x2)
double currentEmissionTime_m
std::vector< size_t > binWrite_m
double getEnergyBinDeltaT()
void createDistributionFromFile(size_t numberOfParticles, double massIneV)
size_t totalNumberParticles_m
double pTotThermal_m
Random number generator.
void setDistToEmitted(bool emitted)
void setDistParametersMultiGauss(double massIneV)
void createDistributionFlattop(size_t numberOfParticles, double massIneV)
void chooseInputMomentumUnits(InputMomentumUnits inputMoUnits)
void checkFileMomentum(double momentumTol)
size_t findEBin(double tOrZ)
void scaleDistCoordinates()
std::vector< double > pyWrite_m
size_t getNumOfLocalParticlesToCreate(size_t n)
std::vector< double > pzDist_m
InputMomentumUnits inputMoUnits_m
double tEmission_m
Emission parameters.
void generateFlattopLaserProfile(size_t numberOfParticles)
gsl_qrng * selectRandomGenerator(std::string, unsigned int dimension)
Select and allocate gsl random number generator.
void generateGaussZ(size_t numberOfParticles)
void printDist(Inform &os, size_t numberOfParticles) const
void applyEmissModelNone(double &pz)
void writeOutFileInjection()
size_t emitParticles(PartBunchBase< double, 3 > *beam, double eZ)
void applyEmissionModel(double lowEnergyLimit, double &px, double &py, double &pz, std::vector< double > &additionalRNs)
void applyEmissModelAstra(double &px, double &py, double &pz, std::vector< double > &additionalRNs)
void setupEmissionModelNonEquil()
void setupEmissionModel(PartBunchBase< double, 3 > *beam)
void printDistGauss(Inform &os) const
void printEmissionModel(Inform &os) const
void setDistParametersGauss(double massIneV)
Inform & printInfo(Inform &os) const
void checkParticleNumber(size_t &numberOfParticles)
void createMatchedGaussDistribution(size_t numberOfParticles, double massIneV, double charge)
void createDistributionGauss(size_t numberOfParticles, double massIneV)
void shiftBeam(double &maxTOrZ, double &minTOrZ)
EmissionModel emissionModel_m
Emission Model.
size_t totalNumberEmittedParticles_m
std::vector< double > xDist_m
double laserIntensityCut_m
void generateTransverseGauss(size_t numberOfParticles)
virtual double get(double rand)
virtual double get(double rand)
boost::numeric::ublas::compressed_matrix< double, boost::numeric::ublas::row_major > sparse_matrix_t
Sparse matrix type definition.
boost::numeric::ublas::matrix< double > matrix_t
Dense matrix type definition.
boost::numeric::ublas::vector< double, std::vector< double > > vector_t
Dense vector type definition.
void diagonalize(matrix_t &, sparse_matrix_t &, sparse_matrix_t &)
RealDiracMatrix::matrix_t matrix_t
Type for storing maps.
size_t getNumParticles() const
virtual void readStep(PartBunchBase< double, 3 > *, h5_ssize_t firstParticle, h5_ssize_t lastParticle)=0
virtual bool predecessorIsSameFlavour() const =0
virtual void readHeader()=0
The base class for all OPAL exceptions.
static MPI_Comm getComm()
static Communicate * Comm
static void stopTimer(TimerRef t)
static void startTimer(TimerRef t)
Vektor< double, 3 > Vector_t