• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmc-dev / openmc / 15371300071

01 Jun 2025 05:04AM UTC coverage: 85.143% (+0.3%) from 84.827%
15371300071

Pull #3176

github

web-flow
Merge 4f739184a into cb95c784b
Pull Request #3176: MeshFilter rotation - solution to issue #3166

86 of 99 new or added lines in 4 files covered. (86.87%)

3707 existing lines in 117 files now uncovered.

52212 of 61323 relevant lines covered (85.14%)

42831974.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.6
/src/mcpl_interface.cpp
1
#include "openmc/mcpl_interface.h"
2

3
#include "openmc/bank.h"
4
#include "openmc/error.h"
5
#include "openmc/file_utils.h"
6
#include "openmc/message_passing.h"
7
#include "openmc/settings.h"
8
#include "openmc/simulation.h"
9
#include "openmc/state_point.h"
10
#include "openmc/vector.h"
11

12
#include <fmt/core.h>
13

14
#ifdef OPENMC_MCPL
15
#include <mcpl.h>
16
#endif
17

18
namespace openmc {
19

20
//==============================================================================
21
// Constants
22
//==============================================================================
23

24
#ifdef OPENMC_MCPL
25
const bool MCPL_ENABLED = true;
26
#else
27
const bool MCPL_ENABLED = false;
28
#endif
29

30
//==============================================================================
31
// Functions
32
//==============================================================================
33

34
#ifdef OPENMC_MCPL
35
SourceSite mcpl_particle_to_site(const mcpl_particle_t* particle)
22,000✔
36
{
37
  SourceSite site;
22,000✔
38

39
  switch (particle->pdgcode) {
22,000✔
40
  case 2112:
22,000✔
41
    site.particle = ParticleType::neutron;
22,000✔
42
    break;
22,000✔
43
  case 22:
×
44
    site.particle = ParticleType::photon;
×
45
    break;
×
46
  case 11:
×
47
    site.particle = ParticleType::electron;
×
48
    break;
×
49
  case -11:
×
50
    site.particle = ParticleType::positron;
×
51
    break;
×
52
  }
53

54
  // Copy position and direction
55
  site.r.x = particle->position[0];
22,000✔
56
  site.r.y = particle->position[1];
22,000✔
57
  site.r.z = particle->position[2];
22,000✔
58
  site.u.x = particle->direction[0];
22,000✔
59
  site.u.y = particle->direction[1];
22,000✔
60
  site.u.z = particle->direction[2];
22,000✔
61

62
  // MCPL stores kinetic energy in [MeV], time in [ms]
63
  site.E = particle->ekin * 1e6;
22,000✔
64
  site.time = particle->time * 1e-3;
22,000✔
65
  site.wgt = particle->weight;
22,000✔
66

67
  return site;
22,000✔
68
}
69
#endif
70

71
//==============================================================================
72

73
vector<SourceSite> mcpl_source_sites(std::string path)
22✔
74
{
75
  vector<SourceSite> sites;
22✔
76

77
#ifdef OPENMC_MCPL
78
  // Open MCPL file and determine number of particles
79
  auto mcpl_file = mcpl_open_file(path.c_str());
22✔
80
  size_t n_sites = mcpl_hdr_nparticles(mcpl_file);
22✔
81

82
  for (int i = 0; i < n_sites; i++) {
22,022✔
83
    // Extract particle from mcpl-file, checking if it is a neutron, photon,
84
    // electron, or positron. Otherwise skip.
85
    const mcpl_particle_t* particle;
86
    int pdg = 0;
22,000✔
87
    while (pdg != 2112 && pdg != 22 && pdg != 11 && pdg != -11) {
44,000✔
88
      particle = mcpl_read(mcpl_file);
22,000✔
89
      pdg = particle->pdgcode;
22,000✔
90
    }
91

92
    // Convert to source site and add to vector
93
    sites.push_back(mcpl_particle_to_site(particle));
22,000✔
94
  }
95

96
  // Check that some sites were read
97
  if (sites.empty()) {
22✔
98
    fatal_error("MCPL file contained no neutron, photon, electron, or positron "
×
99
                "source particles.");
100
  }
101

102
  mcpl_close_file(mcpl_file);
22✔
103
#else
104
  fatal_error(
105
    "Your build of OpenMC does not support reading MCPL source files.");
106
#endif
107

108
  return sites;
44✔
109
}
×
110

111
//==============================================================================
112

113
#ifdef OPENMC_MCPL
114
void write_mcpl_source_bank(mcpl_outfile_t file_id,
22✔
115
  span<SourceSite> source_bank, const vector<int64_t>& bank_index)
116
{
117
  int64_t dims_size = settings::n_particles;
22✔
118
  int64_t count_size = simulation::work_per_rank;
22✔
119

120
  if (mpi::master) {
22✔
121
    // Particles are writeen to disk from the master node only
122

123
    // Save source bank sites since the array is overwritten below
124
#ifdef OPENMC_MPI
125
    vector<SourceSite> temp_source {source_bank.begin(), source_bank.end()};
7✔
126
#endif
127

128
    // loop over the other nodes and receive data - then write those.
129
    for (int i = 0; i < mpi::n_procs; ++i) {
37✔
130
      // number of particles for node node i
131
      size_t count[] {static_cast<size_t>(bank_index[i + 1] - bank_index[i])};
22✔
132

133
#ifdef OPENMC_MPI
134
      if (i > 0)
14✔
135
        MPI_Recv(source_bank.data(), count[0], mpi::source_site, i, i,
7✔
136
          mpi::intracomm, MPI_STATUS_IGNORE);
137
#endif
138
      // now write the source_bank data again.
139
      for (const auto& site : source_bank) {
15,022✔
140
        // particle is now at the iterator
141
        // write it to the mcpl-file
142
        mcpl_particle_t p;
143
        p.position[0] = site.r.x;
15,000✔
144
        p.position[1] = site.r.y;
15,000✔
145
        p.position[2] = site.r.z;
15,000✔
146

147
        // mcpl requires that the direction vector is unit length
148
        // which is also the case in openmc
149
        p.direction[0] = site.u.x;
15,000✔
150
        p.direction[1] = site.u.y;
15,000✔
151
        p.direction[2] = site.u.z;
15,000✔
152

153
        // MCPL stores kinetic energy in [MeV], time in [ms]
154
        p.ekin = site.E * 1e-6;
15,000✔
155
        p.time = site.time * 1e3;
15,000✔
156
        p.weight = site.wgt;
15,000✔
157

158
        switch (site.particle) {
15,000✔
159
        case ParticleType::neutron:
15,000✔
160
          p.pdgcode = 2112;
15,000✔
161
          break;
15,000✔
162
        case ParticleType::photon:
×
163
          p.pdgcode = 22;
×
164
          break;
×
165
        case ParticleType::electron:
×
166
          p.pdgcode = 11;
×
167
          break;
×
168
        case ParticleType::positron:
×
169
          p.pdgcode = -11;
×
170
          break;
×
171
        }
172

173
        mcpl_add_particle(file_id, &p);
15,000✔
174
      }
175
    }
176
#ifdef OPENMC_MPI
177
    // Restore state of source bank
178
    std::copy(temp_source.begin(), temp_source.end(), source_bank.begin());
7✔
179
#endif
180
  } else {
7✔
181
#ifdef OPENMC_MPI
182
    MPI_Send(source_bank.data(), count_size, mpi::source_site, 0, mpi::rank,
7✔
183
      mpi::intracomm);
184
#endif
185
  }
186
}
22✔
187
#endif
188

189
//==============================================================================
190

191
void write_mcpl_source_point(const char* filename, span<SourceSite> source_bank,
22✔
192
  const vector<int64_t>& bank_index)
193
{
194
  std::string filename_(filename);
22✔
195
  const auto extension = get_file_extension(filename_);
22✔
196
  if (extension == "") {
22✔
UNCOV
197
    filename_.append(".mcpl");
×
198
  } else if (extension != "mcpl") {
22✔
199
    warning("write_mcpl_source_point was passed a file extension differing "
×
200
            "from .mcpl, but an mcpl file will be written.");
201
  }
202

203
#ifdef OPENMC_MCPL
204
  mcpl_outfile_t file_id;
205

206
  std::string line;
22✔
207
  if (mpi::master) {
22✔
208
    file_id = mcpl_create_outfile(filename_.c_str());
15✔
209
    if (VERSION_DEV) {
210
      line = fmt::format("OpenMC {0}.{1}.{2}-dev{3}", VERSION_MAJOR,
28✔
211
        VERSION_MINOR, VERSION_RELEASE, VERSION_COMMIT_COUNT);
15✔
212
    } else {
213
      line = fmt::format(
214
        "OpenMC {0}.{1}.{2}", VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE);
215
    }
216
    mcpl_hdr_set_srcname(file_id, line.c_str());
15✔
217
  }
218

219
  write_mcpl_source_bank(file_id, source_bank, bank_index);
22✔
220

221
  if (mpi::master) {
22✔
222
    mcpl_close_outfile(file_id);
15✔
223
  }
224
#endif
225
}
22✔
226

227
} // namespace openmc
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc