Distribution.cpp 185 KB
Newer Older
gsell's avatar
gsell committed
1 2 3 4 5 6 7 8 9 10 11 12
// ------------------------------------------------------------------------
// $RCSfile: Distribution.cpp,v $
// ------------------------------------------------------------------------
// $Revision: 1.3.4.1 $
// ------------------------------------------------------------------------
// Copyright: see Copyright.readme
// ------------------------------------------------------------------------
//
// Class: Distribution
//   The class for the OPAL Distribution command.
//
// ------------------------------------------------------------------------
kraus's avatar
kraus committed
13 14

#include "Distribution/Distribution.h"
15
#include "Distribution/SigmaGenerator.h"
16
#include "AbsBeamline/SpecificElementVisitor.h"
17

18 19 20 21 22 23
#include <cmath>
#include <cfloat>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
24
#include <numeric>
25
#include <limits>
26

27
#include "AbstractObjects/Expressions.h"
28
#include "Utilities/Options.h"
29 30
#include "AbstractObjects/OpalData.h"
#include "Algorithms/PartBins.h"
frey_m's avatar
frey_m committed
31
#include "Algorithms/PartBunchBase.h"
32
#include "Algorithms/bet/EnvelopeBunch.h"
33
#include "Structure/Beam.h"
34
#include "Structure/BoundaryGeometry.h"
gsell's avatar
gsell committed
35 36 37
#include "Algorithms/PartBinsCyc.h"
#include "BasicActions/Option.h"
#include "Distribution/LaserProfile.h"
38
#include "Elements/OpalBeamline.h"
39
#include "AbstractObjects/BeamSequence.h"
40 41
#include "Structure/H5PartWrapper.h"
#include "Structure/H5PartWrapperForPC.h"
42
#include "Utilities/Util.h"
43 44 45 46

#include <gsl/gsl_cdf.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_sf_erf.h>
47 48
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_blas.h>
49
#include <gsl/gsl_qrng.h>
gsell's avatar
gsell committed
50

51
#include <sys/time.h>
52

kraus's avatar
kraus committed
53 54
#include <boost/regex.hpp>

gsell's avatar
gsell committed
55 56
extern Inform *gmsg;

57
constexpr double SMALLESTCUTOFF = 1e-12;
kraus's avatar
kraus committed
58

snuverink_j's avatar
snuverink_j committed
59 60 61 62 63 64 65
namespace {
    SymTenzor<double, 6> getUnit6x6() {
        SymTenzor<double, 6> unit6x6;
        for (unsigned int i = 0; i < 6u; ++ i) {
            unit6x6(i,i) = 1.0;
        }
        return unit6x6;
66 67 68
    }
}

gsell's avatar
gsell committed
69 70 71 72 73
//
// Class Distribution
// ------------------------------------------------------------------------

Distribution::Distribution():
74
    Definition( Attrib::Legacy::Distribution::SIZE, "DISTRIBUTION",
75
                "The DISTRIBUTION statement defines data for the 6D particle distribution."),
76
    distrTypeT_m(DistrTypeT::NODIST),
77
    numberOfDistributions_m(1),
78 79 80 81 82 83
    emitting_m(false),
    scan_m(false),
    emissionModel_m(EmissionModelT::NONE),
    tEmission_m(0.0),
    tBin_m(0.0),
    currentEmissionTime_m(0.0),
kraus's avatar
kraus committed
84
    currentEnergyBin_m(1),
85
    currentSampleBin_m(0),
86 87 88 89
    numberOfEnergyBins_m(0),
    numberOfSampleBins_m(0),
    energyBins_m(NULL),
    energyBinHist_m(NULL),
90
    randGen_m(NULL),
91
    pTotThermal_m(0.0),
kraus's avatar
kraus committed
92
    pmean_m(0.0),
93 94 95 96 97
    cathodeWorkFunc_m(0.0),
    laserEnergy_m(0.0),
    cathodeFermiEnergy_m(0.0),
    cathodeTemp_m(0.0),
    emitEnergyUpperLimit_m(0.0),
98 99
    totalNumberParticles_m(0),
    totalNumberEmittedParticles_m(0),
100
    avrgpz_m(0.0),
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    inputMoUnits_m(InputMomentumUnitsT::NONE),
    sigmaTRise_m(0.0),
    sigmaTFall_m(0.0),
    tPulseLengthFWHM_m(0.0),
    correlationMatrix_m(getUnit6x6()),
    laserProfileFileName_m(""),
    laserImageName_m(""),
    laserIntensityCut_m(0.0),
    laserProfile_m(NULL),
    darkCurrentParts_m(0),
    darkInwardMargin_m(0.0),
    eInitThreshold_m(0.0),
    workFunction_m(0.0),
    fieldEnhancement_m(0.0),
    fieldThrFN_m(0.0),
    maxFN_m(0),
    paraFNA_m(0.0),
    paraFNB_m(0.0),
    paraFNY_m(0.0),
    paraFNVYSe_m(0.0),
    paraFNVYZe_m(0.0),
    secondaryFlag_m(0),
    ppVw_m(0.0),
    vVThermal_m(0.0),
    I_m(0.0),
126
    E_m(0.0)
127
{
128
    setAttributes();
129 130 131

    Distribution *defaultDistribution = clone("UNNAMED_Distribution");
    defaultDistribution->builtin = true;
gsell's avatar
gsell committed
132 133

    try {
134
        OpalData::getInstance()->define(defaultDistribution);
gsell's avatar
gsell committed
135
    } catch(...) {
136 137 138
        delete defaultDistribution;
    }

139
    // setFieldEmissionParameters();
140 141 142

    gsl_rng_env_setup();
    randGen_m = gsl_rng_alloc(gsl_rng_default);
gsell's avatar
gsell committed
143 144 145 146 147 148 149
}
/**
 *
 *
 * @param name
 * @param parent
 */
150
Distribution::Distribution(const std::string &name, Distribution *parent):
gsell's avatar
gsell committed
151
    Definition(name, parent),
152 153
    distT_m(parent->distT_m),
    distrTypeT_m(DistrTypeT::NODIST),
154
    numberOfDistributions_m(parent->numberOfDistributions_m),
155 156 157 158 159 160
    emitting_m(parent->emitting_m),
    scan_m(parent->scan_m),
    particleRefData_m(parent->particleRefData_m),
    addedDistributions_m(parent->addedDistributions_m),
    particlesPerDist_m(parent->particlesPerDist_m),
    emissionModel_m(parent->emissionModel_m),
gsell's avatar
gsell committed
161
    tEmission_m(parent->tEmission_m),
162 163 164 165 166 167 168 169
    tBin_m(parent->tBin_m),
    currentEmissionTime_m(parent->currentEmissionTime_m),
    currentEnergyBin_m(parent->currentEmissionTime_m),
    currentSampleBin_m(parent->currentSampleBin_m),
    numberOfEnergyBins_m(parent->numberOfEnergyBins_m),
    numberOfSampleBins_m(parent->numberOfSampleBins_m),
    energyBins_m(NULL),
    energyBinHist_m(NULL),
170
    randGen_m(NULL),
171
    pTotThermal_m(parent->pTotThermal_m),
kraus's avatar
kraus committed
172
    pmean_m(parent->pmean_m),
173 174 175 176 177
    cathodeWorkFunc_m(parent->cathodeWorkFunc_m),
    laserEnergy_m(parent->laserEnergy_m),
    cathodeFermiEnergy_m(parent->cathodeFermiEnergy_m),
    cathodeTemp_m(parent->cathodeTemp_m),
    emitEnergyUpperLimit_m(parent->emitEnergyUpperLimit_m),
178 179
    totalNumberParticles_m(parent->totalNumberParticles_m),
    totalNumberEmittedParticles_m(parent->totalNumberEmittedParticles_m),
180 181 182 183 184 185 186 187 188 189 190 191
    xDist_m(parent->xDist_m),
    pxDist_m(parent->pxDist_m),
    yDist_m(parent->yDist_m),
    pyDist_m(parent->pyDist_m),
    tOrZDist_m(parent->tOrZDist_m),
    pzDist_m(parent->pzDist_m),
    xWrite_m(parent->xWrite_m),
    pxWrite_m(parent->pxWrite_m),
    yWrite_m(parent->yWrite_m),
    pyWrite_m(parent->pyWrite_m),
    tOrZWrite_m(parent->tOrZWrite_m),
    pzWrite_m(parent->pzWrite_m),
192
    avrgpz_m(parent->avrgpz_m),
193 194 195 196 197 198 199 200
    inputMoUnits_m(parent->inputMoUnits_m),
    sigmaTRise_m(parent->sigmaTRise_m),
    sigmaTFall_m(parent->sigmaTFall_m),
    tPulseLengthFWHM_m(parent->tPulseLengthFWHM_m),
    sigmaR_m(parent->sigmaR_m),
    sigmaP_m(parent->sigmaP_m),
    cutoffR_m(parent->cutoffR_m),
    cutoffP_m(parent->cutoffP_m),
201
    correlationMatrix_m(parent->correlationMatrix_m),
202 203 204 205
    laserProfileFileName_m(parent->laserProfileFileName_m),
    laserImageName_m(parent->laserImageName_m),
    laserIntensityCut_m(parent->laserIntensityCut_m),
    laserProfile_m(NULL),
gsell's avatar
gsell committed
206 207 208 209 210 211 212 213 214 215 216 217
    darkCurrentParts_m(parent->darkCurrentParts_m),
    darkInwardMargin_m(parent->darkInwardMargin_m),
    eInitThreshold_m(parent->eInitThreshold_m),
    workFunction_m(parent->workFunction_m),
    fieldEnhancement_m(parent->fieldEnhancement_m),
    fieldThrFN_m(parent->fieldThrFN_m),
    maxFN_m(parent->maxFN_m),
    paraFNA_m(parent-> paraFNA_m),
    paraFNB_m(parent-> paraFNB_m),
    paraFNY_m(parent-> paraFNY_m),
    paraFNVYSe_m(parent-> paraFNVYSe_m),
    paraFNVYZe_m(parent-> paraFNVYZe_m),
218 219 220
    secondaryFlag_m(parent->secondaryFlag_m),
    ppVw_m(parent->ppVw_m),
    vVThermal_m(parent->vVThermal_m),
221 222
    I_m(parent->I_m),
    E_m(parent->E_m),
223 224 225 226
    tRise_m(parent->tRise_m),
    tFall_m(parent->tFall_m),
    sigmaRise_m(parent->sigmaRise_m),
    sigmaFall_m(parent->sigmaFall_m),
227
    cutoff_m(parent->cutoff_m)
228
{
229 230
    gsl_rng_env_setup();
    randGen_m = gsl_rng_alloc(gsl_rng_default);
gsell's avatar
gsell committed
231 232 233 234
}

Distribution::~Distribution() {

235 236 237 238
    delete energyBins_m;
    gsl_histogram_free(energyBinHist_m);
    gsl_rng_free(randGen_m);
    delete laserProfile_m;
gsell's avatar
gsell committed
239
}
240

241
/*
242
  void Distribution::printSigma(SigmaGenerator<double,unsigned int>::matrix_type& M, Inform& out) {
243 244
  for (int i=0; i<M.size1(); ++i) {
  for (int j=0; j<M.size2(); ++j) {
245 246 247 248
  *gmsg  << M(i,j) << " ";
  }
  *gmsg << endl;
  }
249 250
  }
*/
gsell's avatar
gsell committed
251

252 253
/**
 * Calculate the local number of particles evenly and adjust node 0
254 255 256
 * such that n is matched exactly.
 * @param n total number of particles
 * @return n / #cores
257 258 259 260 261
 * @param
 */

size_t Distribution::getNumOfLocalParticlesToCreate(size_t n) {

262
    size_t locNumber = n / Ippl::getNodes();
263

264 265 266 267 268
    // make sure the total number is exact
    size_t remainder  = n % Ippl::getNodes();
    size_t myNode = Ippl::myNode();
    if (myNode < remainder)
        ++ locNumber;
269 270 271 272

    return locNumber;
}

273 274 275
/// Distribution can only be replaced by another distribution.
bool Distribution::canReplaceBy(Object *object) {
    return dynamic_cast<Distribution *>(object) != 0;
276 277
}

278 279 280
Distribution *Distribution::clone(const std::string &name) {
    return new Distribution(name, this);
}
281

282 283
void Distribution::execute() {
}
adelmann's avatar
adelmann committed
284

285 286
void Distribution::update() {
}
adelmann's avatar
adelmann committed
287

kraus's avatar
kraus committed
288 289 290 291 292 293 294 295 296 297 298 299
void Distribution::create(size_t &numberOfParticles, double massIneV) {

    /*
     * If Options::cZero is true than we reflect generated distribution
     * to ensure that the transverse averages are 0.0.
     *
     * For now we just cut the number of generated particles in half.
     */
    size_t numberOfLocalParticles = numberOfParticles;
    if (Options::cZero && distrTypeT_m != DistrTypeT::FROMFILE) {
        numberOfLocalParticles = (numberOfParticles + 1) / 2;
    }
adelmann's avatar
adelmann committed
300

301
    size_t mySeed = Options::seed;
adelmann's avatar
adelmann committed
302

303
    if (Options::seed == -1) {
Andreas Adelmann's avatar
Andreas Adelmann committed
304 305
        struct timeval tv;
        gettimeofday(&tv,0);
306
        mySeed = tv.tv_sec + tv.tv_usec;
Andreas Adelmann's avatar
Andreas Adelmann committed
307
    }
308

309
    if (Attributes::getBool(itsAttr[Attrib::Distribution::SCALABLE])) {
kraus's avatar
kraus committed
310
        numberOfLocalParticles = getNumOfLocalParticlesToCreate(numberOfLocalParticles);
311 312 313 314 315 316
        *gmsg << level2 << "* Generation of distribution with seed = " << mySeed << " + core_id\n"
              << "* is scalable with number of particles and cores." << endl;
        mySeed += Ippl::myNode();
    } else {
        *gmsg << level2 << "* Generation of distribution with seed = " << mySeed << "\n"
              << "* isn't scalable with number of particles and cores." << endl;
Andreas Adelmann's avatar
Andreas Adelmann committed
317 318
    }

319 320 321
    gsl_rng_set(randGen_m, mySeed);

    setFieldEmissionParameters();
adelmann's avatar
adelmann committed
322

323
    switch (distrTypeT_m) {
adelmann's avatar
adelmann committed
324

325
    case DistrTypeT::MATCHEDGAUSS:
kraus's avatar
kraus committed
326
        createMatchedGaussDistribution(numberOfLocalParticles, massIneV);
327
        break;
328
    case DistrTypeT::FROMFILE:
kraus's avatar
kraus committed
329
        createDistributionFromFile(numberOfParticles, massIneV);
gsell's avatar
gsell committed
330
        break;
331
    case DistrTypeT::GAUSS:
kraus's avatar
kraus committed
332
        createDistributionGauss(numberOfLocalParticles, massIneV);
gsell's avatar
gsell committed
333
        break;
334
    case DistrTypeT::BINOMIAL:
kraus's avatar
kraus committed
335
        createDistributionBinomial(numberOfLocalParticles, massIneV);
gsell's avatar
gsell committed
336
        break;
337
    case DistrTypeT::FLATTOP:
kraus's avatar
kraus committed
338
        createDistributionFlattop(numberOfLocalParticles, massIneV);
gsell's avatar
gsell committed
339
        break;
340
    case DistrTypeT::GUNGAUSSFLATTOPTH:
kraus's avatar
kraus committed
341
        createDistributionFlattop(numberOfLocalParticles, massIneV);
gsell's avatar
gsell committed
342
        break;
343
    case DistrTypeT::ASTRAFLATTOPTH:
kraus's avatar
kraus committed
344
        createDistributionFlattop(numberOfLocalParticles, massIneV);
gsell's avatar
gsell committed
345
        break;
346 347 348 349
    default:
        INFOMSG("Distribution unknown." << endl;);
        break;
    }
kraus's avatar
kraus committed
350 351

    if (emitting_m) {
352

kraus's avatar
kraus committed
353
        unsigned int numAdditionalRNsPerParticle = 0;
354
        if (emissionModel_m == EmissionModelT::ASTRA ||
355 356
            distrTypeT_m == DistrTypeT::ASTRAFLATTOPTH ||
            distrTypeT_m == DistrTypeT::GUNGAUSSFLATTOPTH) {
357

kraus's avatar
kraus committed
358
            numAdditionalRNsPerParticle = 2;
359
        } else if (emissionModel_m == EmissionModelT::NONEQUIL) {
360 361 362 363 364
            if (Options::cZero) {
                numAdditionalRNsPerParticle = 40;
            } else {
                numAdditionalRNsPerParticle = 20;
            }
kraus's avatar
kraus committed
365 366
        }

367 368 369
        int saveProcessor = -1;
        const int myNode = Ippl::myNode();
        const int numNodes = Ippl::getNodes();
370
        const bool scalable = Attributes::getBool(itsAttr[Attrib::Distribution::SCALABLE]);
371

kraus's avatar
kraus committed
372
        for (size_t partIndex = 0; partIndex < numberOfLocalParticles; ++ partIndex) {
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389

            // Save to each processor in turn.
            ++ saveProcessor;
            if (saveProcessor >= numNodes)
                saveProcessor = 0;

            if (scalable || myNode == saveProcessor) {
                std::vector<double> rns;
                for (unsigned int i = 0; i < numAdditionalRNsPerParticle; ++ i) {
                    double x = gsl_rng_uniform(randGen_m);
                    rns.push_back(x);
                }
                additionalRNs_m.push_back(rns);
            } else {
                for (unsigned int i = 0; i < numAdditionalRNsPerParticle; ++ i) {
                    gsl_rng_uniform(randGen_m);
                }
kraus's avatar
kraus committed
390 391 392 393
            }
        }
    }

394 395
    // Scale coordinates according to distribution input.
    scaleDistCoordinates();
396

kraus's avatar
kraus committed
397 398 399
    // Now reflect particles if Options::cZero is true
    reflectDistribution(numberOfLocalParticles);

400
    adjustPhaseSpace(massIneV);
401

402
    if (Options::seed != -1)
Andreas Adelmann's avatar
Andreas Adelmann committed
403
        Options::seed = gsl_rng_uniform_int(randGen_m, gsl_rng_max(randGen_m));
kraus's avatar
kraus committed
404

405 406 407 408 409
    if (particlesPerDist_m.size() == 0) {
        particlesPerDist_m.push_back(tOrZDist_m.size());
    } else {
        particlesPerDist_m[0] = tOrZDist_m.size();
    }
410
}
gsell's avatar
gsell committed
411

frey_m's avatar
frey_m committed
412
void  Distribution::createPriPart(PartBunchBase<double, 3> *beam, BoundaryGeometry &bg) {
gsell's avatar
gsell committed
413

414
    if (Options::ppdebug) {  // This is Parallel Plate Benchmark.
415 416
        int pc = 0;
        size_t lowMark = beam->getLocalNum();
417 418
        double vw = this->getVw();
        double vt = this->getvVThermal();
419 420 421 422 423 424
        double f_max = vw / vt * exp(-0.5);
        double test_a = vt / vw;
        double test_asq = test_a * test_a;
        size_t count = 0;
        size_t N_mean = static_cast<size_t>(floor(bg.getN() / Ippl::getNodes()));
        size_t N_extra = static_cast<size_t>(bg.getN() - N_mean * Ippl::getNodes());
425
        if (Ippl::myNode() == 0)
426
            N_mean += N_extra;
427 428 429 430
        if (bg.getN() != 0) {
            for (size_t i = 0; i < bg.getN(); i++) {
                if (pc == Ippl::myNode()) {
                    if (count < N_mean) {
431 432 433 434 435
                        /*==============Parallel Plate Benchmark=====================================*/
                        double test_s = 1;
                        double f_x = 0;
                        double test_x = 0;
                        while(test_s > f_x) {
436
                            test_s = gsl_rng_uniform(randGen_m);
437
                            test_s *= f_max;
438
                            test_x = gsl_rng_uniform(randGen_m);
439 440 441 442
                            test_x *= 10 * test_a; //range for normalized emission speed(0,10*test_a);
                            f_x = test_x / test_asq * exp(-test_x * test_x / 2 / test_asq);
                        }
                        double v_emi = test_x * vw;
gsell's avatar
gsell committed
443

444 445 446 447
                        double betaemit = v_emi / Physics::c;
                        double betagamma = betaemit / sqrt(1 - betaemit * betaemit);
                        /*============================================================================ */
                        beam->create(1);
448
                        if (pc != 0) {
449 450
                            beam->R[lowMark + count] = bg.getCooridinate(Ippl::myNode() * N_mean + count + N_extra);
                            beam->P[lowMark + count] = betagamma * bg.getMomenta(Ippl::myNode() * N_mean + count);
gsell's avatar
gsell committed
451
                        } else {
452 453
                            beam->R[lowMark + count] = bg.getCooridinate(count);
                            beam->P[lowMark + count] = betagamma * bg.getMomenta(count);
gsell's avatar
gsell committed
454
                        }
455
                        beam->Bin[lowMark + count] = 0;
kraus's avatar
kraus committed
456
                        beam->PType[lowMark + count] = ParticleType::REGULAR;
457 458 459 460 461 462
                        beam->TriID[lowMark + count] = 0;
                        beam->Q[lowMark + count] = beam->getChargePerParticle();
                        beam->Ef[lowMark + count] = Vector_t(0.0);
                        beam->Bf[lowMark + count] = Vector_t(0.0);
                        beam->dt[lowMark + count] = beam->getdT();
                        count ++;
gsell's avatar
gsell committed
463 464
                    }
                }
465
                pc++;
466
                if (pc == Ippl::getNodes())
467
                    pc = 0;
gsell's avatar
gsell committed
468
            }
469 470 471
            bg.clearCooridinateArray();
            bg.clearMomentaArray();
            beam->boundp();
gsell's avatar
gsell committed
472
        }
473
        *gmsg << *beam << endl;
gsell's avatar
gsell committed
474

475
    } else {// Normal procedure to create primary particles
gsell's avatar
gsell committed
476

477 478 479 480 481
        int pc = 0;
        size_t lowMark = beam->getLocalNum();
        size_t count = 0;
        size_t N_mean = static_cast<size_t>(floor(bg.getN() / Ippl::getNodes()));
        size_t N_extra = static_cast<size_t>(bg.getN() - N_mean * Ippl::getNodes());
gsell's avatar
gsell committed
482

483
        if (Ippl::myNode() == 0)
484
            N_mean += N_extra;
485 486
        if (bg.getN() != 0) {
            for (size_t i = 0; i < bg.getN(); i++) {
gsell's avatar
gsell committed
487

488 489
                if (pc == Ippl::myNode()) {
                    if (count < N_mean) {
490
                        beam->create(1);
491
                        if (pc != 0)
492 493 494 495 496
                            beam->R[lowMark + count] = bg.getCooridinate(Ippl::myNode() * N_mean + count + N_extra); // node 0 will emit the particle with coordinate ID from 0 to N_mean+N_extra, so other nodes should shift to node_number*N_mean+N_extra
                        else
                            beam->R[lowMark + count] = bg.getCooridinate(count); // for node0 the particle number N_mean =  N_mean + N_extra
                        beam->P[lowMark + count] = Vector_t(0.0);
                        beam->Bin[lowMark + count] = 0;
kraus's avatar
kraus committed
497
                        beam->PType[lowMark + count] = ParticleType::REGULAR;
498 499 500 501 502 503
                        beam->TriID[lowMark + count] = 0;
                        beam->Q[lowMark + count] = beam->getChargePerParticle();
                        beam->Ef[lowMark + count] = Vector_t(0.0);
                        beam->Bf[lowMark + count] = Vector_t(0.0);
                        beam->dt[lowMark + count] = beam->getdT();
                        count++;
gsell's avatar
gsell committed
504 505

                    }
506

gsell's avatar
gsell committed
507
                }
508
                pc++;
509
                if (pc == Ippl::getNodes())
510
                    pc = 0;
511

512
            }
513

514 515 516 517 518 519
        }
        bg.clearCooridinateArray();
        beam->boundp();//fixme if bg.getN()==0?
    }
    *gmsg << *beam << endl;
}
520

frey_m's avatar
frey_m committed
521
void Distribution::doRestartOpalT(PartBunchBase<double, 3> *beam, size_t Np, int restartStep, H5PartWrapper *dataSource) {
522

frey_m's avatar
frey_m committed
523
    IpplTimings::startTimer(beam->distrReload_m);
524

525 526
    long numParticles = dataSource->getNumParticles();
    size_t numParticlesPerNode = numParticles / Ippl::getNodes();
gsell's avatar
gsell committed
527

528 529 530 531
    size_t firstParticle = numParticlesPerNode * Ippl::myNode();
    size_t lastParticle = firstParticle + numParticlesPerNode - 1;
    if (Ippl::myNode() == Ippl::getNodes() - 1)
        lastParticle = numParticles - 1;
532

533
    numParticles = lastParticle - firstParticle + 1;
534
    PAssert_GE(numParticles, 0);
535

frey_m's avatar
frey_m committed
536
    beam->create(numParticles);
537

538 539
    dataSource->readHeader();
    dataSource->readStep(beam, firstParticle, lastParticle);
540

frey_m's avatar
frey_m committed
541
    beam->boundp();
542

frey_m's avatar
frey_m committed
543 544 545
    double actualT = beam->getT();
    long long ltstep = beam->getLocalTrackStep();
    long long gtstep = beam->getGlobalTrackStep();
546

frey_m's avatar
frey_m committed
547
    IpplTimings::stopTimer(beam->distrReload_m);
gsell's avatar
gsell committed
548

frey_m's avatar
frey_m committed
549
    *gmsg << "Total number of particles in the h5 file= " << beam->getTotalNum() << "\n"
550 551 552
          << "Global step= " << gtstep << "; Local step= " << ltstep << "; "
          << "restart step= " << restartStep << "\n"
          << "time of restart= " << actualT << "; phishift= " << OpalData::getInstance()->getGlobalPhaseShift() << endl;
gsell's avatar
gsell committed
553 554
}

frey_m's avatar
frey_m committed
555
void Distribution::doRestartOpalCycl(PartBunchBase<double, 3> *beam,
556 557 558 559
                                     size_t Np,
                                     int restartStep,
                                     const int specifiedNumBunch,
                                     H5PartWrapper *dataSource) {
adelmann's avatar
adelmann committed
560

561
    // h5_int64_t rc;
frey_m's avatar
frey_m committed
562
    IpplTimings::startTimer(beam->distrReload_m);
563
    INFOMSG("---------------- Start reading hdf5 file----------------" << endl);
564

565 566
    long numParticles = dataSource->getNumParticles();
    size_t numParticlesPerNode = numParticles / Ippl::getNodes();
567

568 569 570 571
    size_t firstParticle = numParticlesPerNode * Ippl::myNode();
    size_t lastParticle = firstParticle + numParticlesPerNode - 1;
    if (Ippl::myNode() == Ippl::getNodes() - 1)
        lastParticle = numParticles - 1;
572

573
    numParticles = lastParticle - firstParticle + 1;
574
    PAssert_GE(numParticles, 0);
575

frey_m's avatar
frey_m committed
576
    beam->create(numParticles);
577

578 579
    dataSource->readHeader();
    dataSource->readStep(beam, firstParticle, lastParticle);
580

frey_m's avatar
frey_m committed
581
    beam->Q = beam->getChargePerParticle();
582

frey_m's avatar
frey_m committed
583
    beam->boundp();
584

585
    double meanE = static_cast<H5PartWrapperForPC*>(dataSource)->getMeanKineticEnergy();
586

frey_m's avatar
frey_m committed
587
    const int globalN = beam->getTotalNum();
588 589
    INFOMSG("Restart from hdf5 format file " << OpalData::getInstance()->getInputBasename() << ".h5" << endl);
    INFOMSG("total number of particles = " << globalN << endl);
frey_m's avatar
frey_m committed
590 591 592
    INFOMSG("* Restart Energy = " << meanE << " (MeV), Path lenght = " << beam->getLPath() << " (m)" <<  endl);
    INFOMSG("Tracking Step since last bunch injection is " << beam->getSteptoLastInj() << endl);
    INFOMSG(beam->getNumBunch() << " Bunches(bins) exist in this file" << endl);
593

frey_m's avatar
frey_m committed
594
    double gamma = 1 + meanE / beam->getM() * 1.0e6;
595
    double beta = sqrt(1.0 - (1.0 / std::pow(gamma, 2.0)));
596

597
    INFOMSG("* Gamma = " << gamma << ", Beta = " << beta << endl);
598

599
    if (dataSource->predecessorIsSameFlavour()) {
600
        INFOMSG("Restart from hdf5 file generated by OPAL-cycl" << endl);
601
        if (specifiedNumBunch > 1) {
602
            // the allowed maximal bin number is set to 1000
frey_m's avatar
frey_m committed
603 604
            energyBins_m = new PartBinsCyc(1000, beam->getNumBunch());
            beam->setPBins(energyBins_m);
605 606
        }

607 608
    } else {
        INFOMSG("Restart from hdf5 file generated by OPAL-t" << endl);
609 610 611

        Vector_t meanR(0.0, 0.0, 0.0);
        Vector_t meanP(0.0, 0.0, 0.0);
frey_m's avatar
frey_m committed
612
        unsigned long int newLocalN = beam->getLocalNum();
613 614
        for (unsigned int i = 0; i < newLocalN; ++i) {
            for (int d = 0; d < 3; ++d) {
frey_m's avatar
frey_m committed
615 616
                meanR(d) += beam->R[i](d);
                meanP(d) += beam->P[i](d);
617 618 619 620 621 622
            }
        }
        reduce(meanR, meanR, OpAddAssign());
        meanR /= Vector_t(globalN);
        reduce(meanP, meanP, OpAddAssign());
        meanP /= Vector_t(globalN);
623
        INFOMSG("Rmean = " << meanR << "[m], Pmean=" << meanP << endl);
624

625
        for (unsigned int i = 0; i < newLocalN; ++i) {
frey_m's avatar
frey_m committed
626 627
            beam->R[i] -= meanR;
            beam->P[i] -= meanP;
628 629 630
        }
    }

631
    INFOMSG("---------------Finished reading hdf5 file---------------" << endl);
frey_m's avatar
frey_m committed
632
    IpplTimings::stopTimer(beam->distrReload_m);
633 634
}

frey_m's avatar
frey_m committed
635
void Distribution::doRestartOpalE(EnvelopeBunch *beam, size_t Np, int restartStep,
636
                                  H5PartWrapper *dataSource) {
frey_m's avatar
frey_m committed
637
    IpplTimings::startTimer(beam->distrReload_m);
638 639
    int N = dataSource->getNumParticles();
    *gmsg << "total number of slices = " << N << endl;
640

frey_m's avatar
frey_m committed
641 642 643 644
    beam->distributeSlices(N);
    beam->createBunch();
    long long starti = beam->mySliceStartOffset();
    long long endi = beam->mySliceEndOffset();
645

646 647
    dataSource->readHeader();
    dataSource->readStep(beam, starti, endi);
648

frey_m's avatar
frey_m committed
649 650
    beam->setCharge(beam->getChargePerParticle());
    IpplTimings::stopTimer(beam->distrReload_m);
651 652 653 654 655
}

Distribution *Distribution::find(const std::string &name) {
    Distribution *dist = dynamic_cast<Distribution *>(OpalData::getInstance()->find(name));

656
    if (dist == 0) {
657 658 659 660 661 662
        throw OpalException("Distribution::find()", "Distribution \"" + name + "\" not found.");
    }

    return dist;
}

663
double Distribution::getTEmission() {
664
    if (tEmission_m > 0.0) {
665 666 667
        return tEmission_m;
    }

668
    setDistType();
669

670 671 672 673
    tPulseLengthFWHM_m = Attributes::getReal(itsAttr[Attrib::Distribution::TPULSEFWHM]);
    cutoff_m = Attributes::getReal(itsAttr[Attrib::Legacy::Distribution::CUTOFF]);
    tRise_m = Attributes::getReal(itsAttr[Attrib::Distribution::TRISE]);
    tFall_m = Attributes::getReal(itsAttr[Attrib::Distribution::TFALL]);
674 675 676 677 678
    double tratio = sqrt(2.0 * log(10.0)) - sqrt(2.0 * log(10.0 / 9.0));
    sigmaRise_m = tRise_m / tratio;
    sigmaFall_m = tFall_m / tratio;

    switch(distrTypeT_m) {
679 680 681 682 683 684 685 686
    case DistrTypeT::ASTRAFLATTOPTH: {
        double a = tPulseLengthFWHM_m / 2;
        double sig = tRise_m / 2;
        double inv_erf08 = 0.906193802436823; // erfinv(0.8)
        double sqr2 = sqrt(2.);
        double t = a - sqr2 * sig * inv_erf08;
        double tmps = sig;
        double tmpt = t;
687
        for (int i = 0; i < 10; ++ i) {
688 689 690 691 692
            sig = (t + tRise_m - a) / (sqr2 * inv_erf08);
            t = a - 0.5 * sqr2 * (sig + tmps) * inv_erf08;
            sig = (0.5 * (t + tmpt) + tRise_m - a) / (sqr2 * inv_erf08);
            tmps = sig;
            tmpt = t;
693
        }
694 695 696 697 698 699 700 701 702
        tEmission_m = tPulseLengthFWHM_m + 10 * sig;
        break;
    }
    case DistrTypeT::GUNGAUSSFLATTOPTH: {
        tEmission_m = tPulseLengthFWHM_m + (cutoff_m - sqrt(2.0 * log(2.0))) * (sigmaRise_m + sigmaFall_m);
        break;
    }
    default:
        tEmission_m = 0.0;
703 704 705 706 707 708
    }
    return tEmission_m;
}

Inform &Distribution::printInfo(Inform &os) const {

709 710
    os << "* ************* D I S T R I B U T I O N ********************************************" << endl;
    os << "* " << endl;
711
    if (OpalData::getInstance()->inRestartRun()) {
adelmann's avatar
adelmann committed
712
        os << "* In restart. Distribution read in from .h5 file." << endl;
713 714
    } else {
        if (addedDistributions_m.size() > 0)
adelmann's avatar
adelmann committed
715
            os << "* Main Distribution" << endl
716
               << "-----------------" << endl;
717 718

        if (particlesPerDist_m.empty())
719
            printDist(os, 0);
720
        else
721
            printDist(os, particlesPerDist_m.at(0));
722 723 724

        size_t distCount = 1;
        for (unsigned distIndex = 0; distIndex < addedDistributions_m.size(); distIndex++) {
725
            os << "* " << endl;
adelmann's avatar
adelmann committed
726 727
            os << "* Added Distribution #" << distCount << endl;
            os << "* ----------------------" << endl;
728
            addedDistributions_m.at(distIndex)->printDist(os, particlesPerDist_m.at(distCount));
729 730 731
            distCount++;
        }

732
        os << "* " << endl;
733
        if (numberOfEnergyBins_m > 0) {
adelmann's avatar
adelmann committed
734
            os << "* Number of energy bins    = " << numberOfEnergyBins_m << endl;
735

736
            //            if (numberOfEnergyBins_m > 1)
737
            //    printEnergyBins(os);
738 739 740
        }

        if (emitting_m) {
adelmann's avatar
adelmann committed
741 742
            os << "* Distribution is emitted. " << endl;
            os << "* Emission time            = " << tEmission_m << " [sec]" << endl;
743 744
            os << "* Time per bin             = " << tEmission_m / numberOfEnergyBins_m << " [sec]" << endl;
            os << "* Delta t during emission  = " << tBin_m / numberOfSampleBins_m << " [sec]" << endl;
745
            os << "* " << endl;
746
            printEmissionModel(os);
747
            os << "* " << endl;
748
        } else
adelmann's avatar
adelmann committed
749
            os << "* Distribution is injected." << endl;
750
    }
751 752
    os << "* " << endl;
    os << "* **********************************************************************************" << endl;
753 754 755 756

    return os;
}

757
const PartData &Distribution::getReference() const {
758 759 760 761 762
    // Cast away const, to allow logically constant Distribution to update.
    const_cast<Distribution *>(this)->update();
    return particleRefData_m;
}

763
void Distribution::addDistributions() {
764 765 766
    /*
     * Move particle coordinates from added distributions to main distribution.
     */
adelmann's avatar
doc  
adelmann committed
767

kraus's avatar
kraus committed
768
    size_t idx = 1;
769 770
    std::vector<Distribution *>::iterator addedDistIt;
    for (addedDistIt = addedDistributions_m.begin();
kraus's avatar
kraus committed
771
         addedDistIt != addedDistributions_m.end(); ++ addedDistIt, ++ idx) {
772

kraus's avatar
kraus committed
773
        particlesPerDist_m[idx] = (*addedDistIt)->tOrZDist_m.size();
774

775 776
        for (double dist : (*addedDistIt)->getXDist()) {
            xDist_m.push_back(dist);
777
        }
778
        (*addedDistIt)->eraseXDist();
779

780 781
        for (double dist : (*addedDistIt)->getBGxDist()) {
            pxDist_m.push_back(dist);
782
        }
783
        (*addedDistIt)->eraseBGxDist();
784

785 786
        for (double dist : (*addedDistIt)->getYDist()) {
            yDist_m.push_back(dist);
787
        }
788
        (*addedDistIt)->eraseYDist();
789

790 791
        for (double dist : (*addedDistIt)->getBGyDist()) {
            pyDist_m.push_back(dist);
792
        }
793
        (*addedDistIt)->eraseBGyDist();
794

795 796
        for (double dist : (*addedDistIt)->getTOrZDist()) {
            tOrZDist_m.push_back(dist);
797
        }
798
        (*addedDistIt)->eraseTOrZDist();
799

800 801
        for (double dist : (*addedDistIt)->getBGzDist()) {
            pzDist_m.push_back(dist);
802
        }
803
        (*addedDistIt)->eraseBGzDist();
804 805 806
    }
}

807
void Distribution::applyEmissionModel(double lowEnergyLimit, double &px, double &py, double &pz, std::vector<double> &additionalRNs) {
808 809 810 811

    switch (emissionModel_m) {

    case EmissionModelT::NONE:
812
        applyEmissModelNone(pz);