From e9eadd936d2ad1b75beaf31c8dc378e31b69c086 Mon Sep 17 00:00:00 2001 From: amandalund Date: Thu, 28 Feb 2019 11:55:11 -0500 Subject: [PATCH 001/165] Add function to calculate the density effect correction --- include/openmc/material.h | 3 + include/openmc/photon.h | 3 + openmc/data/photon.py | 48 ++++++++---- src/material.cpp | 155 ++++++++++++++++++++++++++++++++++++++ src/photon.cpp | 7 +- 5 files changed, 199 insertions(+), 17 deletions(-) diff --git a/include/openmc/material.h b/include/openmc/material.h index f43db5928..316186b5d 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -95,6 +95,9 @@ public: std::unique_ptr ttb_; private: + //! Calculate density effect correction + double density_effect_correction(double E); + //! Initialize bremsstrahlung data void init_bremsstrahlung(); diff --git a/include/openmc/photon.h b/include/openmc/photon.h index a2279f502..ad621c59e 100644 --- a/include/openmc/photon.h +++ b/include/openmc/photon.h @@ -87,6 +87,9 @@ public: // Stopping power data double I_; // mean excitation energy + xt::xtensor n_electrons_; + xt::xtensor ionization_energy_; + // TODO: Calculate stopping powers instead of reading in xt::xtensor stopping_power_collision_; xt::xtensor stopping_power_radiative_; diff --git a/openmc/data/photon.py b/openmc/data/photon.py index c73216b84..5e9f518bb 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -104,6 +104,10 @@ _STOPPING_POWERS = {} # incident electron kinetic energies with key 'electron_energies', an array of # k reduced photon energies with key 'photon_energies', and the cross sections # for each element are in a 2D array with shape (n, k) stored on the key 'Z'. +# It also stores data used for calculating the density effect correction, +# namely, the mean excitation energy with the key 'I', number of electrons per +# subshell with the key 'num_electrons', and binding energies with the key +# 'ionization_energy'. _BREMSSTRAHLUNG = {} @@ -352,12 +356,16 @@ class IncidentPhoton(EqualityMixin): atomic_relaxation : openmc.data.AtomicRelaxation or None Atomic relaxation data bremsstrahlung : dict - Dictionary of bremsstrahlung DCS data with keys 'electron_energy' - (incident electron kinetic energy values in [eV]), 'photon_energy' - (ratio of the energy of the emitted photon to the incident electron - kinetic energy), and 'dcs' (cross section values in [b]). The cross - sections are in scaled form: :math:`(\beta^2/Z^2) E_k (d\sigma/dE_k)`, - where :math:`E_k` is the energy of the emitted photon. + Dictionary of bremsstrahlung data with keys 'I' (mean excitation energy + in [eV]), 'num_electrons' (number of electrons in each subshell), + 'ionization_energy' (ionization potential of each subshell), + 'electron_energy' (incident electron kinetic energy values in [eV]), + 'photon_energy' (ratio of the energy of the emitted photon to the + incident electron kinetic energy), and 'dcs' (cross section values in + [b]). The cross sections are in scaled form: :math:`(\beta^2/Z^2) E_k + (d\sigma/dE_k)`, where :math:`E_k` is the energy of the emitted photon. + A negative number of electrons in a subshell indicates conduction + electrons. compton_profiles : dict Dictionary of Compton profile data with keys 'num_electrons' (number of electrons in each subshell), 'binding_energy' (ionization potential of @@ -600,6 +608,17 @@ class IncidentPhoton(EqualityMixin): # Load bremsstrahlung data if it has not yet been loaded if not _BREMSSTRAHLUNG: + # Add data used for density effect correction + filename = os.path.join(os.path.dirname(__file__), 'density_effect.h5') + with h5py.File(filename, 'r') as f: + for i in range(1, 101): + group = f['{:03}'.format(i)] + _BREMSSTRAHLUNG[i] = { + 'I': group.attrs['I'], + 'num_electrons': group['num_electrons'].value, + 'ionization_energy': group['ionization_energy'].value + } + filename = os.path.join(os.path.dirname(__file__), 'BREMX.DAT') brem = open(filename, 'r').read().split() @@ -640,12 +659,12 @@ class IncidentPhoton(EqualityMixin): # Get scaled DCS values (millibarns) on new energy grid dcs[:,j] = cs(log_energy) - _BREMSSTRAHLUNG[i] = {'dcs': dcs} + _BREMSSTRAHLUNG[i]['dcs'] = dcs # Add bremsstrahlung DCS data data.bremsstrahlung['electron_energy'] = _BREMSSTRAHLUNG['electron_energy'] data.bremsstrahlung['photon_energy'] = _BREMSSTRAHLUNG['photon_energy'] - data.bremsstrahlung['dcs'] = _BREMSSTRAHLUNG[Z]['dcs'] + data.bremsstrahlung.update(_BREMSSTRAHLUNG[Z]) return data @@ -770,7 +789,6 @@ class IncidentPhoton(EqualityMixin): # Write stopping powers if self.stopping_powers: s_group = group.create_group('stopping_powers') - for key, value in self.stopping_powers.items(): if key == 'I': s_group.attrs[key] = value @@ -780,13 +798,11 @@ class IncidentPhoton(EqualityMixin): # Write bremsstrahlung if self.bremsstrahlung: brem_group = group.create_group('bremsstrahlung') - - brem = self.bremsstrahlung - brem_group.create_dataset('electron_energy', - data=brem['electron_energy']) - brem_group.create_dataset('photon_energy', - data=brem['photon_energy']) - brem_group.create_dataset('dcs', data=brem['dcs']) + for key, value in self.bremsstrahlung.items(): + if key == 'I': + brem_group.attrs[key] = value + else: + brem_group.create_dataset(key, data=value) class PhotonReaction(EqualityMixin): diff --git a/src/material.cpp b/src/material.cpp index 8236a4ef0..97266f102 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -451,6 +451,161 @@ void Material::init_thermal() thermal_tables_ = tables; } +double Material::density_effect_correction(double E) +{ + // Maximum number of iterations and convergence criterion for the + // Newton-Raphson method + constexpr int max_iter = 100; + constexpr double tol = 1.0e-6; + + // Effective number of conduction electrons in the material + double n_conduction = 0.0; + + // Log of the mean excitation energy of the material + double log_I = 0.0; + + // Average electron number and average atomic weight + double electron_density = 0.0; + double mass_density = 0.0; + + // Oscillator strength and square of the binding energy for each oscillator + // in material + std::vector f; + std::vector e_b_sq; + + for (int i = 0; i < element_.size(); ++i) { + const auto& elm = data::elements[element_[i]]; + double awr = data::nuclides[nuclide_[i]]->awr_; + + // Get atomic density of nuclide given atom/weight percent + double atom_density = (atom_density_[0] > 0.0) ? + atom_density_[i] : -atom_density_[i] / awr; + + electron_density += atom_density * elm.Z_; + mass_density += atom_density * awr * MASS_NEUTRON; + log_I += atom_density * elm.Z_ * std::log(elm.I_); + + for (int j = 0; j < elm.n_electrons_.size(); ++j) { + if (elm.n_electrons_[j] < 0) { + n_conduction -= elm.n_electrons_[j] * atom_density; + continue; + } + e_b_sq.push_back(elm.ionization_energy_[j] * elm.ionization_energy_[j]); + f.push_back(elm.n_electrons_[j] * atom_density); + } + } + log_I /= electron_density; + n_conduction /= electron_density; + for (auto& f_i : f) f_i /= electron_density; + + // Get density in g/cm^3 if it is given in atom/b-cm + double density = (density_ < 0.0) ? -density_ : mass_density / N_AVOGADRO; + + // Calculate the square of the plasma energy + double e_p_sq = PLANCK_C * PLANCK_C * PLANCK_C * N_AVOGADRO * + electron_density * density / (2.0 * PI * PI * FINE_STRUCTURE * + MASS_ELECTRON_EV * mass_density); + + // Get the total number of oscillators + int n = f.size(); + + // Calculate the Sternheimer adjustment factor using Newton's method + double rho = 2.0; + int iter; + for (iter = 0; iter < max_iter; ++iter) { + double rho_0 = rho; + + // Function to find the root of and its derivative + double g = 0.0; + double gp = 0.0; + + for (int i = 0; i < n; ++i) { + // Square of resonance energy of a bound-shell oscillator + double e_r_sq = e_b_sq[i] * rho * rho + 2.0 / 3.0 * f[i] * e_p_sq; + g += f[i] * std::log(e_r_sq); + gp += e_b_sq[i] * f[i] * rho / e_r_sq; + } + // Include conduction electrons + g += n_conduction * std::log(n_conduction * e_p_sq); + + // Set the next guess: rho_n+1 = rho_n - g(rho_n)/g'(rho_n) + rho -= (g - 2.0 * log_I) / (2.0 * gp); + + // If the initial guess is too large, rho can be negative + if (rho < 0.0) rho = rho_0 / 2.0; + + // Check for convergence + if (std::abs(rho - rho_0) / rho_0 < tol) break; + } + // Did not converge + if (iter >= max_iter) { + warning("Maximum Newton-Raphson iterations exceeded."); + rho = 1.0e-6; + } + + // Square of the ratio of the speed of light to the velocity of the charged + // particle + double beta_sq = E * (E + 2.0 * MASS_ELECTRON_EV) / ((E + MASS_ELECTRON_EV) * + (E + MASS_ELECTRON_EV)); + + // For nonmetals, delta = 0 for beta < beta_0, where beta_0 is obtained by + // setting the frequency w = 0. + double beta_0_sq = 0.0; + if (n_conduction == 0.0) { + for (int i = 0; i < n; ++i) { + beta_0_sq += f[i] * e_p_sq / (e_b_sq[i] * rho * rho); + } + beta_0_sq = 1.0 / (1.0 + beta_0_sq); + } + double delta = 0.0; + if (beta_sq < beta_0_sq) return delta; + + // Compute the square of the frequency w^2 using Newton's method, with the + // initial guess of w^2 equal to beta^2 * gamma^2 + double w_sq = E / MASS_ELECTRON_EV * (E / MASS_ELECTRON_EV + 2); + for (iter = 0; iter < max_iter; ++iter) { + double w_sq_0 = w_sq; + + // Function to find the root of and its derivative + double g = 0.0; + double gp = 0.0; + + for (int i = 0; i < n; ++i) { + double c = e_b_sq[i] * rho * rho / e_p_sq + w_sq; + g += f[i] / c; + gp -= f[i] / (c * c); + } + // Include conduction electrons + g += n_conduction / w_sq; + gp -= n_conduction / (w_sq * w_sq); + + // Set the next guess: w_n+1 = w_n - g(w_n)/g'(w_n) + w_sq -= (g + 1.0 - 1.0 / beta_sq) / gp; + + // If the initial guess is too large, w can be negative + if (w_sq < 0.0) w_sq = w_sq_0 / 2.0; + + // Check for convergence + if (std::abs(w_sq - w_sq_0) / w_sq_0 < tol) break; + } + // Did not converge + if (iter >= max_iter) { + warning("Maximum Newton-Raphson iterations exceeded: setting density " + "effect correction to zero."); + return delta; + } + + // Solve for the density effect correction + for (int i = 0; i < n; ++i) { + double l_sq = e_b_sq[i] * rho * rho / e_p_sq + 2.0 / 3.0 * f[i]; + delta += f[i] * std::log((l_sq + w_sq)/l_sq); + } + // Include conduction electrons + delta += n_conduction * std::log((n_conduction + w_sq) / n_conduction); + + return delta - w_sq * (1.0 - beta_sq); +} + void Material::init_bremsstrahlung() { // Create new object diff --git a/src/photon.cpp b/src/photon.cpp index 89fef6c43..49b050c61 100644 --- a/src/photon.cpp +++ b/src/photon.cpp @@ -212,6 +212,11 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) if (data::ttb_k_grid.size() == 1) { read_dataset(rgroup, "photon_energy", data::ttb_k_grid); } + + // Get data used for density effect correction + read_dataset(rgroup, "num_electrons", n_electrons_); + read_dataset(rgroup, "ionization_energy", ionization_energy_); + read_attribute(rgroup, "I", I_); close_group(rgroup); // Read stopping power data @@ -219,7 +224,7 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) rgroup = open_group(group, "stopping_powers"); read_dataset(rgroup, "s_collision", stopping_power_collision_); read_dataset(rgroup, "s_radiative", stopping_power_radiative_); - read_attribute(rgroup, "I", I_); + //read_attribute(rgroup, "I", I_); close_group(rgroup); } From fac544b35fd17f48a30346326edfd57c80ca9bed Mon Sep 17 00:00:00 2001 From: amandalund Date: Thu, 28 Feb 2019 13:26:01 -0500 Subject: [PATCH 002/165] Only create Compton electrons if energy is above cutoff energy --- src/physics.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/physics.cpp b/src/physics.cpp index 5d6ca2dee..6e7620020 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -265,15 +265,17 @@ void sample_photon_reaction(Particle* p) } // Create Compton electron - double E_electron = (alpha - alpha_out)*MASS_ELECTRON_EV - e_b; - double mu_electron = (alpha - alpha_out*mu) - / std::sqrt(alpha*alpha + alpha_out*alpha_out - 2.0*alpha*alpha_out*mu); double phi = 2.0*PI*prn(); - double uvw[3]; - std::copy(p->coord[0].uvw, p->coord[0].uvw + 3, uvw); - rotate_angle_c(uvw, mu_electron, &phi); + double E_electron = (alpha - alpha_out)*MASS_ELECTRON_EV - e_b; int electron = static_cast(ParticleType::electron); - p->create_secondary(uvw, E_electron, electron, true); + if (E_electron >= settings::energy_cutoff[electron]) { + double mu_electron = (alpha - alpha_out*mu) + / std::sqrt(alpha*alpha + alpha_out*alpha_out - 2.0*alpha*alpha_out*mu); + double uvw[3]; + std::copy(p->coord[0].uvw, p->coord[0].uvw + 3, uvw); + rotate_angle_c(uvw, mu_electron, &phi); + p->create_secondary(uvw, E_electron, electron, true); + } // TODO: Compton subshell data does not match atomic relaxation data // Allow electrons to fill orbital and produce auger electrons From f923fc65c4642b48058e899b2cf9be14fd963064 Mon Sep 17 00:00:00 2001 From: amandalund Date: Sat, 2 Mar 2019 11:09:44 -0600 Subject: [PATCH 003/165] Calculate the collision stopping power --- include/openmc/material.h | 12 +- src/material.cpp | 261 +++++++++++++++++++++++--------------- 2 files changed, 169 insertions(+), 104 deletions(-) diff --git a/include/openmc/material.h b/include/openmc/material.h index 316186b5d..3497d0f38 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -96,7 +96,7 @@ public: private: //! Calculate density effect correction - double density_effect_correction(double E); + void collision_stopping_power(double* s_col, bool positron); //! Initialize bremsstrahlung data void init_bremsstrahlung(); @@ -112,6 +112,16 @@ private: // Non-member functions //============================================================================== +//! Calculate Sternheimer adjustment factor +double sternheimer_adjustment(std::vector& f, std::vector& + e_b_sq, double e_p_sq, double n_conduction, double log_I, double tol, int + max_iter); + +//! Calculate density effect correction +double density_effect(std::vector& f, std::vector& e_b_sq, + double e_p_sq, double n_conduction, double rho, double E, double tol, int + max_iter); + //! Read material data from materials.xml void read_materials_xml(); diff --git a/src/material.cpp b/src/material.cpp index 97266f102..13b80ac97 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -451,22 +451,17 @@ void Material::init_thermal() thermal_tables_ = tables; } -double Material::density_effect_correction(double E) +void Material::collision_stopping_power(double* s_col, bool positron) { - // Maximum number of iterations and convergence criterion for the - // Newton-Raphson method - constexpr int max_iter = 100; - constexpr double tol = 1.0e-6; - - // Effective number of conduction electrons in the material - double n_conduction = 0.0; + // Average electron number and average atomic weight + double electron_density = 0.0; + double mass_density = 0.0; // Log of the mean excitation energy of the material double log_I = 0.0; - // Average electron number and average atomic weight - double electron_density = 0.0; - double mass_density = 0.0; + // Effective number of conduction electrons in the material + double n_conduction = 0.0; // Oscillator strength and square of the binding energy for each oscillator // in material @@ -506,104 +501,46 @@ double Material::density_effect_correction(double E) electron_density * density / (2.0 * PI * PI * FINE_STRUCTURE * MASS_ELECTRON_EV * mass_density); - // Get the total number of oscillators - int n = f.size(); + // Get the Sternheimer adjustment factor + double rho = sternheimer_adjustment(f, e_b_sq, e_p_sq, n_conduction, log_I, + 1.0e-6, 100); - // Calculate the Sternheimer adjustment factor using Newton's method - double rho = 2.0; - int iter; - for (iter = 0; iter < max_iter; ++iter) { - double rho_0 = rho; + // Classical elctron radius in cm + double r_e = PLANCK_C / (2.0e8 * PI * FINE_STRUCTURE * MASS_ELECTRON_EV); - // Function to find the root of and its derivative - double g = 0.0; - double gp = 0.0; + // Constant in expression for collision stopping power + double c = 2.0e24 * PI * r_e * r_e * MASS_ELECTRON_EV * N_AVOGADRO * + electron_density / mass_density; - for (int i = 0; i < n; ++i) { - // Square of resonance energy of a bound-shell oscillator - double e_r_sq = e_b_sq[i] * rho * rho + 2.0 / 3.0 * f[i] * e_p_sq; - g += f[i] * std::log(e_r_sq); - gp += e_b_sq[i] * f[i] * rho / e_r_sq; + // Loop over incident charged particle energies + for (int i = 0; i < data::ttb_e_grid.size(); ++i) { + double E = data::ttb_e_grid(i); + + // Get the density effect correction + double delta = density_effect(f, e_b_sq, e_p_sq, n_conduction, rho, E, + 1.0e-6, 100); + + // Square of the ratio of the speed of light to the velocity of the charged + // particle + double beta_sq = E * (E + 2.0 * MASS_ELECTRON_EV) / ((E + MASS_ELECTRON_EV) + * (E + MASS_ELECTRON_EV)); + + double tau = E / MASS_ELECTRON_EV; + + double F; + if (positron) { + double t = tau + 2.0; + F = 2.0 * std::log(2.0) - (beta_sq / 12.0) * (23.0 + 14.0 / t + 10.0 / + (t * t) + 4.0 / (t * t * t)); + } else { + F = (1.0 - beta_sq) * (1.0 + tau * tau / 8.0 - (2.0 * tau + 1.0) * + std::log(2.0)); } - // Include conduction electrons - g += n_conduction * std::log(n_conduction * e_p_sq); - // Set the next guess: rho_n+1 = rho_n - g(rho_n)/g'(rho_n) - rho -= (g - 2.0 * log_I) / (2.0 * gp); - - // If the initial guess is too large, rho can be negative - if (rho < 0.0) rho = rho_0 / 2.0; - - // Check for convergence - if (std::abs(rho - rho_0) / rho_0 < tol) break; + // Calculate the collision stopping power for this energy + s_col[i] = c / beta_sq * (2.0 * (std::log(E) - log_I) + std::log(1.0 + tau + / 2.0) + F - delta); } - // Did not converge - if (iter >= max_iter) { - warning("Maximum Newton-Raphson iterations exceeded."); - rho = 1.0e-6; - } - - // Square of the ratio of the speed of light to the velocity of the charged - // particle - double beta_sq = E * (E + 2.0 * MASS_ELECTRON_EV) / ((E + MASS_ELECTRON_EV) * - (E + MASS_ELECTRON_EV)); - - // For nonmetals, delta = 0 for beta < beta_0, where beta_0 is obtained by - // setting the frequency w = 0. - double beta_0_sq = 0.0; - if (n_conduction == 0.0) { - for (int i = 0; i < n; ++i) { - beta_0_sq += f[i] * e_p_sq / (e_b_sq[i] * rho * rho); - } - beta_0_sq = 1.0 / (1.0 + beta_0_sq); - } - double delta = 0.0; - if (beta_sq < beta_0_sq) return delta; - - // Compute the square of the frequency w^2 using Newton's method, with the - // initial guess of w^2 equal to beta^2 * gamma^2 - double w_sq = E / MASS_ELECTRON_EV * (E / MASS_ELECTRON_EV + 2); - for (iter = 0; iter < max_iter; ++iter) { - double w_sq_0 = w_sq; - - // Function to find the root of and its derivative - double g = 0.0; - double gp = 0.0; - - for (int i = 0; i < n; ++i) { - double c = e_b_sq[i] * rho * rho / e_p_sq + w_sq; - g += f[i] / c; - gp -= f[i] / (c * c); - } - // Include conduction electrons - g += n_conduction / w_sq; - gp -= n_conduction / (w_sq * w_sq); - - // Set the next guess: w_n+1 = w_n - g(w_n)/g'(w_n) - w_sq -= (g + 1.0 - 1.0 / beta_sq) / gp; - - // If the initial guess is too large, w can be negative - if (w_sq < 0.0) w_sq = w_sq_0 / 2.0; - - // Check for convergence - if (std::abs(w_sq - w_sq_0) / w_sq_0 < tol) break; - } - // Did not converge - if (iter >= max_iter) { - warning("Maximum Newton-Raphson iterations exceeded: setting density " - "effect correction to zero."); - return delta; - } - - // Solve for the density effect correction - for (int i = 0; i < n; ++i) { - double l_sq = e_b_sq[i] * rho * rho / e_p_sq + 2.0 / 3.0 * f[i]; - delta += f[i] * std::log((l_sq + w_sq)/l_sq); - } - // Include conduction electrons - delta += n_conduction * std::log((n_conduction + w_sq) / n_conduction); - - return delta - w_sq * (1.0 - beta_sq); } void Material::init_bremsstrahlung() @@ -1022,6 +959,124 @@ void Material::to_hdf5(hid_t group) const // Non-method functions //============================================================================== +double sternheimer_adjustment(std::vector& f, std::vector& + e_b_sq, double e_p_sq, double n_conduction, double log_I, double tol, int + max_iter) +{ + // Get the total number of oscillators + int n = f.size(); + + // Calculate the Sternheimer adjustment factor using Newton's method + double rho = 2.0; + int iter; + for (iter = 0; iter < max_iter; ++iter) { + double rho_0 = rho; + + // Function to find the root of and its derivative + double g = 0.0; + double gp = 0.0; + + for (int i = 0; i < n; ++i) { + // Square of resonance energy of a bound-shell oscillator + double e_r_sq = e_b_sq[i] * rho * rho + 2.0 / 3.0 * f[i] * e_p_sq; + g += f[i] * std::log(e_r_sq); + gp += e_b_sq[i] * f[i] * rho / e_r_sq; + } + // Include conduction electrons + if (n_conduction > 0.0) { + g += n_conduction * std::log(n_conduction * e_p_sq); + } + + // Set the next guess: rho_n+1 = rho_n - g(rho_n)/g'(rho_n) + rho -= (g - 2.0 * log_I) / (2.0 * gp); + + // If the initial guess is too large, rho can be negative + if (rho < 0.0) rho = rho_0 / 2.0; + + // Check for convergence + if (std::abs(rho - rho_0) / rho_0 < tol) break; + } + // Did not converge + if (iter >= max_iter) { + warning("Maximum Newton-Raphson iterations exceeded."); + rho = 1.0e-6; + } + return rho; +} + +double density_effect(std::vector& f, std::vector& e_b_sq, + double e_p_sq, double n_conduction, double rho, double E, double tol, int + max_iter) +{ + // Get the total number of oscillators + int n = f.size(); + + // Square of the ratio of the speed of light to the velocity of the charged + // particle + double beta_sq = E * (E + 2.0 * MASS_ELECTRON_EV) / ((E + MASS_ELECTRON_EV) * + (E + MASS_ELECTRON_EV)); + + // For nonmetals, delta = 0 for beta < beta_0, where beta_0 is obtained by + // setting the frequency w = 0. + double beta_0_sq = 0.0; + if (n_conduction == 0.0) { + for (int i = 0; i < n; ++i) { + beta_0_sq += f[i] * e_p_sq / (e_b_sq[i] * rho * rho); + } + beta_0_sq = 1.0 / (1.0 + beta_0_sq); + } + double delta = 0.0; + if (beta_sq < beta_0_sq) return delta; + + // Compute the square of the frequency w^2 using Newton's method, with the + // initial guess of w^2 equal to beta^2 * gamma^2 + double w_sq = E / MASS_ELECTRON_EV * (E / MASS_ELECTRON_EV + 2); + int iter; + for (iter = 0; iter < max_iter; ++iter) { + double w_sq_0 = w_sq; + + // Function to find the root of and its derivative + double g = 0.0; + double gp = 0.0; + + for (int i = 0; i < n; ++i) { + double c = e_b_sq[i] * rho * rho / e_p_sq + w_sq; + g += f[i] / c; + gp -= f[i] / (c * c); + } + // Include conduction electrons + g += n_conduction / w_sq; + gp -= n_conduction / (w_sq * w_sq); + + // Set the next guess: w_n+1 = w_n - g(w_n)/g'(w_n) + w_sq -= (g + 1.0 - 1.0 / beta_sq) / gp; + + // If the initial guess is too large, w can be negative + if (w_sq < 0.0) w_sq = w_sq_0 / 2.0; + + // Check for convergence + if (std::abs(w_sq - w_sq_0) / w_sq_0 < tol) break; + } + // Did not converge + if (iter >= max_iter) { + warning("Maximum Newton-Raphson iterations exceeded: setting density " + "effect correction to zero."); + return delta; + } + + // Solve for the density effect correction + for (int i = 0; i < n; ++i) { + double l_sq = e_b_sq[i] * rho * rho / e_p_sq + 2.0 / 3.0 * f[i]; + delta += f[i] * std::log((l_sq + w_sq)/l_sq); + } + // Include conduction electrons + if (n_conduction > 0.0) { + delta += n_conduction * std::log((n_conduction + w_sq) / n_conduction); + } + + return delta - w_sq * (1.0 - beta_sq); +} + void read_materials_xml() { write_message("Reading materials XML file...", 5); From 49832db80be7c5d738b2dbb6d5ce7b77f6f3650d Mon Sep 17 00:00:00 2001 From: amandalund Date: Sun, 3 Mar 2019 17:38:10 -0600 Subject: [PATCH 004/165] Calculate radiative and collision stopping power instead of using NIST ESTAR data --- include/openmc/photon.h | 2 -- openmc/data/density_effect.h5 | Bin 0 -> 206264 bytes openmc/data/photon.py | 51 +++------------------------------ openmc/data/stopping_powers.h5 | Bin 494368 -> 0 bytes src/material.cpp | 37 +++++++++--------------- src/photon.cpp | 48 ++++++++++++++----------------- 6 files changed, 38 insertions(+), 100 deletions(-) create mode 100644 openmc/data/density_effect.h5 delete mode 100644 openmc/data/stopping_powers.h5 diff --git a/include/openmc/photon.h b/include/openmc/photon.h index ad621c59e..7c20a716d 100644 --- a/include/openmc/photon.h +++ b/include/openmc/photon.h @@ -89,8 +89,6 @@ public: double I_; // mean excitation energy xt::xtensor n_electrons_; xt::xtensor ionization_energy_; - // TODO: Calculate stopping powers instead of reading in - xt::xtensor stopping_power_collision_; xt::xtensor stopping_power_radiative_; // Bremsstrahlung scaled DCS diff --git a/openmc/data/density_effect.h5 b/openmc/data/density_effect.h5 new file mode 100644 index 0000000000000000000000000000000000000000..77d973517c244f6083b558e9569a5082174169eb GIT binary patch literal 206264 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 literal 0 HcmV?d00001 diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 5e9f518bb..01184a744 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -92,22 +92,15 @@ _REACTION_NAME = { # is a 2D array with shape (n_shells, n_momentum_values) stored on the key Z _COMPTON_PROFILES = {} -# Stopping powers are read from a pre-generated HDF5 file when they are first -# needed. The dictionary stores an array of energy values at which the other -# quantities are tabulated with the key 'energy' and for each element has the -# mean excitation energy and arrays containing the collision stopping powers -# and radiative stopping powers stored on the key 'Z'. -_STOPPING_POWERS = {} - # Scaled bremsstrahlung DCSs are read from a data file provided by Selzter and # Berger when they are first needed. The dictionary stores an array of n # incident electron kinetic energies with key 'electron_energies', an array of # k reduced photon energies with key 'photon_energies', and the cross sections # for each element are in a 2D array with shape (n, k) stored on the key 'Z'. -# It also stores data used for calculating the density effect correction, -# namely, the mean excitation energy with the key 'I', number of electrons per -# subshell with the key 'num_electrons', and binding energies with the key -# 'ionization_energy'. +# It also stores data used for calculating the density effect correction and +# stopping power, namely, the mean excitation energy with the key 'I', number +# of electrons per subshell with the key 'num_electrons', and binding energies +# with the key 'ionization_energy'. _BREMSSTRAHLUNG = {} @@ -376,11 +369,6 @@ class IncidentPhoton(EqualityMixin): reactions : collections.OrderedDict Contains the cross sections for each photon reaction. The keys are MT values and the values are instances of :class:`PhotonReaction`. - stopping_powers : dict - Dictionary of stopping power data with keys 'energy' (in [eV]), 'I' (mean - excitation energy), 's_collision' (collision stopping power in - [eV cm\ :sup:`2`/g]), and 's_radiative' (radiative stopping power in - [eV cm\ :sup:`2`/g]) """ @@ -389,7 +377,6 @@ class IncidentPhoton(EqualityMixin): self._atomic_relaxation = None self.reactions = OrderedDict() self.compton_profiles = {} - self.stopping_powers = {} self.bremsstrahlung = {} def __contains__(self, mt): @@ -585,27 +572,6 @@ class IncidentPhoton(EqualityMixin): data.compton_profiles['binding_energy'] = profile['binding_energy'] data.compton_profiles['J'] = [Tabulated1D(pz, J_k) for J_k in profile['J']] - # Load stopping power data if it has not yet been loaded - if not _STOPPING_POWERS: - filename = os.path.join(os.path.dirname(__file__), 'stopping_powers.h5') - with h5py.File(filename, 'r') as f: - # Units are in MeV; convert to eV - _STOPPING_POWERS['energy'] = f['energy'].value*EV_PER_MEV - for i in range(1, 99): - group = f['{:03}'.format(i)] - - # Units are in MeV cm^2/g; convert to eV cm^2/g - _STOPPING_POWERS[i] = { - 'I': group.attrs['I'], - 's_collision': group['s_collision'].value*EV_PER_MEV, - 's_radiative': group['s_radiative'].value*EV_PER_MEV - } - - # Add stopping power data - if Z < 99: - data.stopping_powers['energy'] = _STOPPING_POWERS['energy'] - data.stopping_powers.update(_STOPPING_POWERS[Z]) - # Load bremsstrahlung data if it has not yet been loaded if not _BREMSSTRAHLUNG: # Add data used for density effect correction @@ -786,15 +752,6 @@ class IncidentPhoton(EqualityMixin): J = np.array([Jk.y for Jk in profile['J']]) compton_group.create_dataset('J', data=J) - # Write stopping powers - if self.stopping_powers: - s_group = group.create_group('stopping_powers') - for key, value in self.stopping_powers.items(): - if key == 'I': - s_group.attrs[key] = value - else: - s_group.create_dataset(key, data=value) - # Write bremsstrahlung if self.bremsstrahlung: brem_group = group.create_group('bremsstrahlung') diff --git a/openmc/data/stopping_powers.h5 b/openmc/data/stopping_powers.h5 deleted file mode 100644 index 4bc5b1388a6c448605de14f7c66270876c51640e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 494368 zcmeFa1z1&E*EYP_o09Gl6a)z|Pz=nm6i^I0q+3#2>_)^^un-IE?m`Suu>--t4zN)% zY53P(V{G>Sob#Ob{QvvD&-whWbMU&Hd+jy%TyxGfW6XQpV~qI@c0(2A^yGNLKUrCx zBu|C=DEhC3{tOq&a9@e8MfZd0g9N4XDBZ!w4-!1#KORqqzE`F4f1A(4&E8&^OH{rn zrJwPvB=M6ueerxXesG}clBf6~N_5{EYb1J(>=eA-A-aDHuP=*!uZ0zUE4m+x*Rq(6 zS8@oi&FT8NjDXAOK-W4hcpXL8-dpf`p6GrRUhfdyXRtw+Mfd07^;^;X$9OGE{itIi z#XZlQuDvJXwS(w>Aznv`?rTVM`R9r5`{VTvx?Z*quP@Vet^nWfThaXycr8o)@qapT zupjIqtiw!fCeIMNlV>;;+abY@Tw&LV#+eF@v+QeF^NE5~xg?Cg9frov^@OsMgdbUt~rPyzU_xXH2SAZ<#7f1wCS2Nfk zs(>1mBFx+_wVxl4Cu#|0_=^*FCucihABt898iu0o;pNi%Da7H^`aW!^bzGy_Ix`wr z@n9`X4Kd+O?1CRe`Eu#Hup54FPWcWn|C+Cyu4{)-hF?7Sqj4Ba9V>dvxGqZk;kx)% z6&s49lE?dJUHp5li{3QeMf2l1%|FpJNC^r{7&|sPB|0IV`zj?UIV3zfWL)(4G2FFi zzFCQW@F(dXjo)&b&!X|$xbsV?W2g&cM2=i=Z>cM2J=8y=Q04|7e;9_(=;8t2C2|ZO z=6XWpwXR-ox{ij^g(v;89(cpgz-tfRZSsZdna6!PEcS91at}%0@=!>cbz)#w>u`8}eRk%TZDXK#o?AtHuSoc^e2hlc^C+-6wjnfT zR}6&edVK4=axAF0zFE{~b3CjQ3@Mr)n+Q23B{8SgB*E6#i!bkZk__@5st2Fii~||< zP5E+rQ^C9~Gpx4%1PDEPsCfCCiI7y_C-d>(Wat=hx}@*=sleNGFROg_bT~Eo;ckn> znNS)XlYDT)EXa6~BVYG&Hr%+o;moo@b0A?}%9@Uc(}8I_b#~g24A2^CmALxTJczrL zb0sN%0qoeh>Z`-nMeshgT6*e{C9v4+RmIhD%Rs3q;o0`hnef`O_{NC0Szy2PPK2G^ z3aAmJbRUwx5;TS_T&XgAHK;8etFit^Hk1W?-&tFj14}2R`S|W#2b!{#?~G1wfSv(` z(Q%VFhkk*l0wNzkQrxMmv;ITbR4PGGVbOX zC^robJ~q1$OwN54RFbem_XKD_oEs5w*#qCGD_q~p6V z`Epl4w@tQG&i$*~{z3&wRRGeETk($cyzI9d;jvYkg0;r1}6}5BCVSc=izF3W|>$yYU!i8hyBb z``J?%rM){#a?x`r%Ujp7=+q0Cp{S`>&#!>N(wVoO23Nw;qk2*w?!SV(w-I|jM!$gt zr|etq>AZvcoy{vxzJ3q)SMQr%cDD*9ZH@Vy_VyDrdc@VxQN zL-rdKhxRpE7x5h$*96w8KK%iLmmUw&6KfzwfB*cq?dw3nW^cOFr+To-P0RfHq!9{y zDkj-{X@;`CD+Jyvd5po7X!S)GB^aHv*=7e71x!1;V=8`QC7F;ueYW?jlw!ua6})Ia zL54}lKC9Yj+J>prpEkVmha6*+_3oqkYXzp$9jS?*>y(&d>4`@KIVz0e_4@q9*HoEu z>B=uk>gr54o2eVxCTlRqry8k^d9TR~HZiuEGsc$v}N@nUdNa@^s(jYlL;n_)zqB6nbjSc z@W?h9K6A{N+cp{o7QHN(Xw@R9>GaQSY`%8{kAL7T0ZJ5BLJ zR^IK-Ts*Z``Idn-)4%7jRe95TGRCp(+nxQ{i&^j5WKy@F4`W+3A#cclzRVQ=gHeYR z`ZM1pznx2O9>7%Zb?IiT0Zeh0=3b>83?pzg=(zUbU}n`o>G1Bxw#?8*b$(=;9W!uK zm%>kt_RQo#vvYGYhcVg@i#i6{4re544-~j)jAXobDvvrK?Z~We5eO>votepIeK()o z{&w{Pvqv))-DdBaGQx+k zi*L66($h@(2iqfFjG|Gx+XA| z_3P($JeJ6m^)DQG^j#9;J*sI+h;<5+eqgV3(TZ_Q>C6fG^OVOkj?YgFU$AuolfHQS z@l)QDn42FzuClS5!W_3OIySKVG)AU!)5u! zu}Ncgk01DBQO+EuNOgJs8O^!Oq2LRQ^_~o-prFg(=RxzC^jF2RpY>SCD17)dKFMq` z!)-szQcVA3FZ$>9uiFEn^Zswo1qwVH_7ovJPw{yg>=|b`HQ|rWO(OZk8vhvaN$=mc z{VzPXk?8$@!?}%5r%4{KTy%i@_ubceZnIMVgA9Muum8GnmD>)x_}3m+e|A1Kw8U2Y zb3Vm>_`BkEzdfJMq;sNZ8TsEnpNjUK-{MUF-F+uQ`1jh5`E~Z4=O);9zxMjT)lqgF zle32XlSpCvkNuNP#%tXqhU?efiOh}b?BA()yl)tX_t(VYebX3*+xE{#VVV+&sdWUV zf-#s@gkf41ish7qU^x$h@%niXl^2NDGyO6DH($E;VNSG5|KO_Q&D`IdI8g4A7p57W zjD`Qwb3eR2m?;|jhP~+L&Im8fJG)WpiqGlm!pI4KxXTI4sU3yo29IP03U53a&LnXk z9I#yNVT_ybfw%3M_UvO%Y_P-frrKgTF+&)K7n3#iMGnS#rZ9M4AFw`A0~uj8{BQNg z{u|Yg5oRCu!UliOo_Dz459>|O>qYglW~y9;5AH!}cdTEN6_sy=K;+fDa3n^FInVtKJ0DK%kKy!#%xJl>dzd(*J?SF zW!T)yb>`?`eRgOw!s2>8)nYsy z)vD}*iTj(3^!~XH0V8RP(3tg zo@g-KFk7d=Tp536quzcEdLJ5$a8$f1q2E2%V1&(D{YitlmS@k71P!JmJ1T7DHL*W* zHJR`1uzzQ&iSyrD6U$*VX})VR!fB%Aqlx_;u1V{QCL^3CAE#>4IM&4ZwOo_d8BHAj zyEU;tj%hMGgu|zZ%Dt{h?bpO{`BD?--A7FvueF*u|0K2W{VQoveYF_2wd_FCqJGlC z@!n615e}m~do9L5IJ}&-m?3O0bnw%{^*BO{>aE4BvSkO-6fK6Eo*7z<QVcr7G=LrMfXLib;j_3`)vN^9x0FK+;f5oS=n`d_nlzhk?w8VJaB^L3obr<#-?@( z>AK;Mo#0_ux%Sy-PLNn&sijxp1Rvh2-x>MF2_m!_GpBuUf=jxSl;>7Efw{rYMN57- zfyecA^X(d)V2o?I{cV9W`0v?K)KkG3++`*W%+_#*ZZ=ORmKr$2mqFzz6=u#b{Y%5g zJZoo=+tNNN7@Q%L9~W|clrwDX?X0Kl=M3kVi&^F|&T!SR^s3HeXE=T@`P{Pw&fuw3 zTH9%ZGdyT}@zbb7&M>6KX^Z_OXIOS(tghx0XV__QL^12TGkA2q{5)CO1@cfB$$7&}_?P9-6-3op494ti~5EzxTQ|{IeezOc){ap~W9OHTEAmW)TR<=jPnrGd2i% zeY%m5&A!>k!{QxJb_s!`(fd1W7KB3Qkhn$bt3yF)%#H;+zlXu{We$&O)yF`7h2!*v zP7%`)v~~{6*>Gdmt-EvKUCxz0 zj~>s1{j$x+vkVqO!#?4M#en)uB`;LXqc(5LpUyL&Fbj$^*h3D4<-N=JJ&Z(DgByNW6Zrut8 z_1g+79X73Y?Ytdi%B-f^joQiTRfKPPH}Lj_Um9w-58mul%GZrQ04TQ{1iL3PhDYZg zhDrN<*Hn)@3N@7>dG~rA2b6d6Vbvjpq&*7@;C7~evu*up;N&dVLSQdGekd%0mP1p% z9&kAi?oykx`biX1`!9m-OKrF@c)LsRJ zZo}Z&FE3>mlv25OU`krIQQPG1!RZPOgDbD@!^Q!f@8rCG0P&k8PD!af21}ilciKcf z1@@t_ITN0PGov1IzU&3yzFq++w^agH?5fw`GuP%`aok%_WLxnl>OIH=WslNaR0Z66 z|KJlSbrJru8hG5_S3tS)8wi)xM|Ix;<+7i^?Jx1Qz{y8}^?>q1BcL4A3@A77m`%d% z=Z*x)NdnpzBvC$fm1cxe%Wwr*hTWam1-cET^7OqD!)=dURY>krrTtC~_rGo$w6AN@ zeyL6Snl8$j%58DK)Hk60p*`-$_Y9d^tTeW@Z3mK*jB%f+HffbN5e_uRYhEYZhksb& zJ}lQ2_a&cTlKV;i-xh%1_w~p0fiLc-i+oTX8A0;D_Go&ZC+&wM|6g^-@~^t#^X|H$ zJX7U@{h;K6^1?VLlD|e_8Zr{U|2`b$@N5Un?=+0$i=kNVdpnZrZJG0|c)#@A5K0GQ zeM%Ur51_nfJctnP)8Jr(#B>$_Dd`{z%QDJ6q2MA@RmK|Pe zFDR1ytbpf;KzWkClfs;2EHUf99o!r>EKH$0`zQ%K0Be-w{G}7}$ z>qsMDKQ_`j)=2ei0#4lR&_wHU6RlHCfbDDoZaiFV0+jQcfIDZKH`9964BYv4X)~4I z3@9fz1J3&v5Q@tS$F=~T%US@>Z!N%`OO$wY-r>>vG++7jd_Fy&PwOh5 z&R+sLZwsjY0;<1&#;btNT>_j}R|PmvKL}`DmZbJe;yiGar12|B=X*(9ANEP&{Jbnl z=U+*b!y6t+Nz?gGn$FeI42~0Nnn%*~ z{-miNq+91Rjw5M04@)!1cN6PPT(o)r<(~-Wj_UkhX8YUS{Oj~4hSu1*zcw!VNBk)p zB4ACV5%OpHmBQ|rQ8e!U;s5=^{}Yag=fsz#VZ{4S=~sTs&;9S}SFoPHl71z)FV^Xg z*OB(W3?Ey(KOOiJ0;g!5$fc8`Xng#W{`(#%bEvkQa@+~3_VzKXz3Bvo1K)dWc;y81 z4O8S+*E@k?*GOKzk~0)9?LMK4kuw~&FOC1+-5GKlk|PR+IKz3V_fPM*I>RgFkkOxl zouPxBtxEReRZgX&KRCmMVeOp?zB$8OC*9%K zo1Ebwz>qY73v`Y%;~kZ8fyIeirkz%Bffr9d_;y!wfu4@mHe0n>ywB7=b&i1x9EmYf zyJhSGANMuw)9vH}x`A7E-(vAZd&QAE()+kTnAs`G?Souk+@6|3>!B_XD|30kY9|*6 z4b47L?9`g&QzS|0>#(L@;9w;fj%CKzV*oyo;{tOW=IZ<1VsXuqL0;95T%dC9GsojqF5nmwB{(4A3jGY*G>lhsh0TJj0|{oX zpzua7B5HsuRM#wgkmczLcV(MKosM?}7Cb6^li>=w-j}}EZgqu;s|<~E&$&YRok<>z z&s?D!2h_Mhy3CDzQ!L%!ajp=kbOVc()pG)8xWV}O@AuBy>jo#wkGRQJxWdvg5Iibe&Yq(zK)+$HhVNg_uuyEYFBUAps*xs^c!y&P}Kb4 z@ev=e^{K7*UF{29`C-!p%l%;X60f6MHv28)Q zV>%Y1VM~+p0k4lS&{lO(+Q>^|VSTrsfm3hC!^+NPdEe6$p9en?|5l3bgFn3>2I?P4sJJS&e@X*=brc!d>kUiC9i#Z{%OyXRWQ-M`s~W8YzUit zPEFZ-E!=$*WBGISdcrkxA%0nWjz`=MUPD1Y+{he-So`TsaLs$HiJ`0Gy6$1Mu3s|0mi;s`anObrl zvaZc=I6JKv`b#*@QFOipXQvt1MA}_}om-q(1o0Zocrb91_l_ID;T|d_;Jkmun0aBh zp|ENLi$IpbIAQTYVtkU*Yu~>QBRPQa0hr`BW_*A22s)Y{zx1mC^`KvX)2pBO zO6U9Uz^Q|d{QwUB2(JN7Pu8stI6Zi~2D)wn)U&pL=v%RiE^l?eSc^ z%@Cje!idhJ#-wL6A-v6>^mTrC&aCsnG~XNXu{oo$egR&H^9}JtT*2A{@wx7VH}-SG za-Cc;e;nbBU7fL<6^__1%A*jUTQ`FE3d0Fk9ERzxq4@ks_L%zEVLgZ1;`0U%!F(eI zEmjCj8Kn za25;dA9KoYiuq3y&bY#a^q$73w@>ZB7(c3;9y8U5L0rs`@RRoR-VN~n0DZ()uILfY zsY~NVhwun3(rarHUqA!({)g02pM6FRamoi`oDum3q$mHPgnHeDiqt*@8b9)ggFb3Q z_>nB(yfTDyO1I)6h~r5SJ}!y+@YMq174V5Cz^8gi5MCqEif^IbpGW=E(u)6caO3AD zK%BA(I6eKwMnC|s5fE2y0FKup*8m(IzqTHbw^2{)UmYOcQ%5*o9U$MJ4p84+OXb!A z;)u0?{DWF5rOzmo>b~O|3-c0kU8L(YqoEznVX87xHv)o}gmwxT@?jPZ1iMCk#|F5`NtsUkU zornLy&Hlm7gd;+S#u1JV-hT`?`>nnDe-}67_#O|OnO}&P?1+8$Yp)}})$6?d&3hNU ze^Dx0Czzq4Z~jSzJ@D7KfJ>mKtlZm!^o-mBB*gLhICkzUB za`nC&*cPLa!5hyA0^&Nw|(@D^IUOyi-R3;|c56_O9q@=Lx!3+T}$!c!ChM z$R6bhDkh)xuex}G^o+CFU3@%Y_MYutK>?nvINJA~!OOl!dqP5}gOh2zCq$gqxjKKm zCj{ucv;R2V6FgG#i(E21VZ_b(1CK2AguxcR`P$i@U^AyvuPLnG0TEA7f92X8Tk}0( zse#AKeiuDKVw-|~NvS8KbS?HA^UM>1E5|r?uJ#0{9BKP+JTDmFvVFiwRj*clp`v#F z_TBxxV0``HfGsXw;3t2$M#KkxH}J)_~2tow?Q6{BHFx>Svz zoi`lomaF~A-y7calt0pci#M!@3{)!kEaowmJxT3dxzPunIdwR9R@N6HKOU36k?ISf z8j?#BKKsJW^KC|LPxS+HivzrE3jTCn@Q33;gM7OC2S8x{)86hzf$;5edxZftfiU*n zZ4c+yL9l)N+?`!ggF$YV|I5pQ5MargYL=Tr2rmtV5iE;SO(hJB_RB1PSrJC#DjaN= z>I^(yG6qI1F1dB*Lj)YT@?yD@NffYTzxgJUqv6Tms!@60Vqm2Zp3E8x?Rsafk@t^> zwKnwHfh9REZ!p*eG6${M8twrY?RW5O)jsHDA@wA%^Z=|f z-J1JomT8srwV) zc!T?%!Nkd1JKO5NAe`|fJWX1#r1EP8C~<)1E4Uso^0LgpH-LPUcW`rFDO;ltfOZ@o zp)NP_@cWd{z}buZsHSuBSK#b34t)bW|NVdo96|kOD;|M7^Lje}i}+E^glF)GuP;G( zqJVHl$yVM8@-}6NFVY6>95%`mPNax-5?_?jE~K+6;#R3@WZ$4p_8yw8I1|1<9kNT% zBVLU@@_81uLta~?A>xo5jS#Q=*n#+ICS*_45%IP}vdanfLHuz5;f*Gv5%1IT!u+bl zZ`Ag{`gL?iUeF*n#1n(azG=P-;fBtH=Q+~#C@NC_IBfeNe{6=jC@vzy0sDB1v8rvU#-_#fJ$~+sy2|fBC?y29K>erL_iq?oz zUhRSXaJ@U`du&Dd#JD5!W;-L^Xl#k^`LG4yp5}zFno+qO>Anf_lGYg`?`TyAMdCXt(D(Aluho(xo|i0*QyB*N!(zS_&KoJ_Hp?oW9wSNiO#;ft zr}4`tUY7*%vLtAp@QDA$Bi?UIEAD}OyQWs02JM*|i4WL7cv=JDaP@@W)dT7;>OfeV zQ{(DDXjZgQudWrR!}(kboE_P4F`kILyc)uDYKSLa1865x)2fF+-ee6R->-)1QA6uT z4e<`e*NFRx^CO?ThH$eQ(qGgN4p>8c>l)%e*3kM?1K1xm#N(_1#ARz*aZTjk*Afm` z3!Gh>V=Z96iE&Kih1L>3yq5T$wWMFF1xds(*Q$TPcGpq;>j?L&Biyf! z`mK)E?K(hya$W0tL4JN6u?y-6kF6)YPd(vc^;G|Qs((GS=wh2ei+t2jmCW z)B0Uc?Wm`AG*CMlXg_EmJiCGL*amvP4fGxwXnk*>{j!1HLj%2s26_(-^d1_hJ&n|! zMrw~3zr^>^NbUJOeu=nwBjJ31j$h(F*F^Yo6OF$n+IO2suhvBKpowt$CVD?j^nRM? z{WJk*e_7f@`ne{;)td-!Zzi0%nZ{Q$&7Wpa^;jIJ=;8~bIEA+_Wb8P%@x={aC~^xZ zyr$p>Qk%@ixY_!_h%aB-JecGMYU+2YyX^4;PW*c42iA~;h4^Mg4 z&x)M=p;wOoqFJf_B=7mdcP-`5eGmA9hi8=GsvG`b6Y*eq;cI`$8y-45zri2mx_oFp zs1g7vD&vmq>KFha7d7@I^$q~1sYf^43=4n(J-pVoj1GW(CzbB52oHd*n$KKn#|D7* zhSduePYM8~x=86SvjRZU!)CU}f&j8>34pI`t=p~*fOp|Le@x#T0O47ghYxHI0KbnR z-82paz&*VYAMK9>fSW^)-4jj(fWv0K*`vY$xKQ%GQlU5ipt*F@peq5;+h=pTO}7K! z;M|3e%kBoiju(F3eVzu89Y_GITHWZ}{3!rbiz^kaz6C&<_%RtZxc&fkeF6%FCZ67DOZ-H?C!Lk_mb^FRs z$$?da#toi!Z5=$_?Pc2Nwvp`h@}Nq)YHr-ZP4L#yzSE*ETi~&(lYHR!tq`lEa{YG2 zb`S&)NSoWd6WGH{X^g`j5RPVp3;ST@apQGbrw+iDXJ?ewSswz{2u}a?wZrfu65QQS^~i&G(t;S8&az)om>)%QHK7&ZM& zeSU%Vsf%P!a2eP`3u{OvK4&2B;TD{HxS(lFO$m4jj~79uWM@@I`{`ZcN8G1%@&T~M zV4rR59|3y^eAssC6Vlr}qvyXMy~|6mM`@r>w!-Z|IguRW!{Jn7L7)p+Ho($8IO7*9(T%va5;CB zZz|o0cj-p<%dW&jbV0n%%9-R4N6cqG3e#63u-uiy2@iB&xSALaLmp(kJ;^I}nD4GF zr9x_!Tfp*$uWZnZzTKbnf*x)>qoek4c05M4_@2!Ci$utmj6TSZ;8XZKZ*S< zad?)t71ncRSHxvscgFgJu>Nj^f>yN!K5vCN_R}acdOrDE`e1_oZ|)kCy>kb=f5(XM zLPO*?wlO3;xgE7vpK!glWN)fR{)u$Rj#HcLD78rb)FgjM8pNAaNBd1Tkslsa;v1?E zzf$C9NQwO0C{TaNlUyrDe9SgvPcBP1p$vogo;2|srCRM%kyj}4OCTUSZ$8<(^2xqa zg5+5qy%!$YleQ3E*wV_&67ju6_R)wNHn#HFM0_|Aj}CF3dcsk}yhr3u){*|9mT;?D zKzmp*UMIrwM7&1ikBjj?)K}EdIZBLEVm)h!cUMC^HSvA4r>+6?!&F23YH_)Uo7Pah zYg&1g$Q!REJWI@zM1El{*@M>-F86y}5%nozUL@jHVmuN3aftblh_{MyL~L&z;l6dP z{fa9{J@M-5$|k66zJ!q>!jGvdDugxfX{KK$o= zN5q#K2sdbG<72DT~?E6s zd`+=EKfaF^dLJ!>yR-9@vl9vi4-Po_J8)2h?XFnAI)@RQ%(Fz{a7anIs|VQ}Z9V$9j2 zVUT%SVtD!SFi>oHCoOj>46bTEebwPi7!0+&xY^^J7*`v(VO9GRSHs}MwdpK^6-NG) z!eHz`TNZK+gSSGnm?vWWy^dVD($K0faCJJed)e18kSd%gt=JR>C%X>}nJ*JgJQOzW zg5}8{IqkxUj}i{E-P=1n?Hdk>Z3~6xzUMd{sf6y82uRjL-4s|-`ICKnrSZbxC&u^7E{AhS(c6X4$(r7q&GVGvZrx;+3tlHY&iy?cf zSQu7Wu;OI+Sn>-L2Px5w=PZZE1Fzrp)!M-caCiT>K?6o6Lf?-Tea(I*!ut<(Ij;^S zf&KBovb5RBAQv&JNG~!4JoLIBz7;kO(w@!L**_^2+^-KVxxH&VyyTad2h>l1QCl}A zj*p!L&R4h0?aiA4#k&S)KRP`X#s7Yt-j3Jn#)NIr8cV+!@pTVBLvhw6C6klEXef@*kcgz13;5 zLplqloI|G~_&!!hv^WP#q^q?YTrPm*n?>dy6)zI6;1cbBSD>GeCeiIWc#Jby-LmW^ z;gBUTysHqQyba+2kB15-mXUtxF8PVN2RRegZ8FX;2e;wtXPTaS2yw;DtVgNGA7CQmoOoNp@Q@_uc*8?@Ji^m>hoLTb-ahR8v-q^seA;(!NOmBCOua* z=|9DM2Gl$LAU^+3T4!rp`TywuM&ysBne<#dvKNs+d2qOZa6(D)LnG4r%90@zcz02TRe`Jgth*o|3&l0JLQjZ{5`+_>&BJgH0ar zPudRU7lAE4Uug*O4+mpvOMc%U4x?EGvepKFzpoG0KczS2?}fZc%bvuK zBs=VOe{V(NN(FEMT>@|TJB)?&O4?Zq4ETqefpkf+*2{82HF5Bp7w&x!D8tXC89 zO@428EW+imer()7E{?+Q?TrzCZf^A#D)Rd)!sF0>x|zHoD_Q^JEE`O7OEeTN*Xp|aKs2OE zJ(_1$5Dl@xyCoN%j|M}|fFl~TyD*Pp?nQ%3lK#Y_kE3D!(OL~&MKrKZ$xFMxiH3n@ zrxT`rjE3>CYZNYhi-xb+v#!?GL_^%g=y{zQqv72**P;Hr7zj7&C%Hs2hU}AKKxcV# zpqz3HtSEe~KR`VOZV0QV8v_@DmiKyZ6w`{w9n|dEqs(Jp%sRzFufcbw@!VpexZT4`a?@j>#NzU;q5EP%V^Y?*82BWd9cp&mu$HK$KgI){xab!mo2MZS|Ih;Ea2kMraGjCbOgAj%DVdKs=mk9}* z3GhVzx}5#V1kjGiTVK{W5qcZ#?f!O7BJ3U_I5_roBHX!aurSUo2@XAMJp2A~5(K9x zZD`||On#h_p_H}CYCkQ7aKCZjqq}%&;FobQs;5Jd`{h)K7(O${_tz=YVf{nbHi$xlrDz=w;&T3>ruCA@M`}hWE=B!XVB8(_+ZqRaMZTb}97H zEA%rQ%=&3!t$$e8>u`VWf~02C6;PQbbU?onyg0{CtBJ?F2IkAGaLhlq7C2h2!3LNv zbOYs+3l)uy=5~d7z>*W+S~_e7Evs366TWSMvtyiA7hl*0{5y9J9X+!HP8}ZqDE;*= z7;Pj(cK5;o&)LN4JvL#4 zfOY1?B8jh{f1=P*>NVk^Z(+fK7w=XcdQUiJ6>NX&z#^TW$$p|5a6kDlIh*y<#O=40Mrgm%*O=l5nUEZ4O7gE6%Ij+^ z815V~ll;jq=tA;cH{6$Gy3_vD1NV(QYqEptg>vHtR{pjh>>@0~n=6RN6Y)@H5+8%U z{$KYq@YmrF!3(hszc&8xTU@LBH~lYq5293rLs-ofee+K$?18^-T;*nBkN?`^>d$a3 zn;dL~XgvLcYyG`&tv_7<=i|5#{r|tsL;NG0%w;M@QWoK9e^ft1!rlH;^%IpVN=1A{ zCIi0-rvCXK@f8b4Gk?yT{P(zHdHa9ur$6jZ(|^q;YL6)8@JDrDlqc%E5%+sF8u6uv zUMN4@_r&w=6A#4as@xGL;}ia9%g_Z^0k{6hX8>ugc3sUN2q-R+fZ8pf^-a(kX9?evfSxBH9AA>=lO(lAlH%7$ z()!v7YFusQOB(fDB3=9316t^Ra;_gL5 zw)G>;`rv3d{^>OvF)teYrpnFyq7VaVkL|NJ`NzPgjzXeVOsl^gSF13&dp5BkBm4U8 zmnpF@U8G#f5e*>!z9z2W(JGHsW9$+1JOx#3B1({;fFBi_yrs{yq*`CJP-J z#gqT(cv#}S&{@JN9{P4PG<`879#~^*gB|YipqUw>nGhaNcF*xpmsdJ(&9r#ftG>EI zb6z}zruz-b%8CcAn)Yjy){Akrp{uSRJheL>&YeG!@M(WMG{^{%yLjk1DsE@msd$K6 zHhk#KbMdh4PR9zJEAjA5hd(pyRy_C)eLrwzSvpVg;M9AGZ_6waAoBRCD~SUVpd_dLjA+*cs9CX2eM(dU zJld+5v2|7g2)()MoWrR^=r~YeuhY#$NbW9uFR3vRasq{KAPENMZ(}23CXwI!B*B=-g!RyV0+r;bk&>RB1V|by!NPf2Bn%IySlcIO1oHgM&J$drv#3 zLVttHlVg6Q!lC;GtgZ2Qu#P!1V$k>r(C+zg`PH5iVTs@MTZ)d8;N_dMGW!E2L-|^r ztmX5kK-HEroj=~03XgQR9lJAlIuz*-oSslN1G>KK-~B`JOt@g;f7$rNELfUswU&2& zHhjF-LwCuWG*}-cMDWr9dD3&C z&y95*wG&j(eat|I5kgMf;#&dQp7&u>&xKoz2>ohd^RW@1*3jhsjUUQQ+W9kK?d%+GxoZ zzkJv}>5@gitOC-DohH1n5Io$>a_1i?f>T0w?7hWy)T@P;yDtJ4u5$fl!uzgLe9Iez zN8SRV)%7~n+t7mpDocT*6|3JNKTvl8yW>9a5`-R{9suXweg7khqxppPx92c`GfaO$ z@z_{9>b=pd%ce@=xxa=B2fMNn72W~|_kMW?s+UflSS(#dewjWIZ@il99KMhr;%|hr zekVV=KWU$?X|)d!$r++}ak$@$^g$A&*Wr`gBuV>(C_b4Ct^aLkKaeMUQjzvGWt4-e zRLIUntu-z*?#r6^yB%7jhti?v=#hUYeUc~J;rc(+5ZC!>M!26`>p=MlZ#>+Q_GdHN zA1!eGe=X9pcSiYMsvAAm3gzXB?ozs~n}yZhITE5mKrx4-td`ZGK=aWA$)G@ky!Q~$wJ zg(IS51C9&P|Nq-~stBK4who_gfS&h1!zcZj|1Lfmdud58x*QT{0MK>6dLJK>aWgx8V(M`u@*L(*L+bw+$n$qBEwj>6xM7>V*u6XA|$ z91ss!Gz{gU$f1bOIoo4>hS*VROFTfrA47@vm`1!ue;{0NAmtxGI9orIgHrmU++=El za?;!0h##Eng}BAKo>;#H)>uwP5Bz;*_g1-ziyN|{8}UH9VEaQl6Rz2b+HFC&q&eji z$DiTiXKXN`_|wLSCobtg_<<4OrG}(GZjX3|K|Ad4HTvWqv@Nwum+%K2!u<$;?4?C` zsV3qsMjC{ps8hTmHNtsBb~!49kC0qDR*CQzMZz`Z3Ad3W9H$M{SC;I0WU#-_iQ~{9 zKS1mc678Y|gtG|9&!h5c?Sv@d-ut+@iQD7$-)|J4D=6%%enqi{f%bJWJ%&)f0Xy z#wA5|#%Ql4_Ctv6ZU7D+J|p%sD6$vE_&DPDC!+QTa{y&yD~}L)n&NmRXiwfmxMnl; zmze*D{Lp6dyV*iGX$$#L6Z7^k{*KsxC;Elt5pR}9^MQxsaWjwX$i(rp(N13+KO6g3 zg77T~vj3N$aVA0j0wgH@v;?~@3jg>tUiow$<5L`KK9$2K-X9NiPRPb8`TBuTF!Nza!=KVIJ?NgpBA8qXWYnH2J-yGYSF zSc-5_DOz`=n33?J>Ryj%ia!_)37yRquJ(+9S2F_~HymR5d)s%FFr8x|Fi&~a!Ms=q ziCeV3T5T-6lQ(+PG-GV5-#x*nNzF%GS%!SL6;Kih!<=OX>AYgmus;iHZC~hUo3sihO ztKX|6!by@KEl$sMyBbFz_*JGuzhYu#hjSd>D%lBls zaNvCQ_nKr_HQ}z{wNVOG#NO)M#w7*h*I1^-q@|D@I_p1i=Nz-|^(j!Wx}nmX83&i{ zUfy?P(Kv_=tD3X=`8bds_59wG0jc1*EjulDb1LC!<3UB}UUJ!Zs9j_iCE0cYD7Sgm z(Duj#@_RoKcCuFT%e5!LuY@KW0M_!l$7oQmVT0Wc#KkjQ4)d0pMi<%4Db2fxM4gv|UNJ9^v9g0~|RSkwR6a9r3twKOOQ*EfD(JO>iGMK8MN znhqR&chy{IJ8Vz!cHTU)51$XSZYdkj8MY8Kr0VT9m@Ebl)?51f=x4KFVyUn4I8q5gqoY>kl)31z`^iqH^8$# zXMSGK%B6DhUbm1H!o&?T4{Pa`6xjp=L1~|8k zx5aTO(XZ=y!vBh4x-cAN^d&Ii0Msj_XS)W%ZxgC-fMM7t-ywraU{|mZxx5VnJKxE9 zZBPb5td;YnlXu8J{yoA2%i$?sXgK{4&RDJKq_grd)#EAoF@6rcIpFan@y#p9-{ULt zL;o5+q#V_3xb~Lz;rGyk>+mWNdXQZ@aN&jm=>vnrAzr+ybNYxIAOU4?b9Q@dX^xLMSmog_kodwC)mb8C#!D|_c z%h;Z_@7dOy;0Q1-38^K37k%3iZV~YQ)@npFVLfr9J z#La^D{J(4a`_Cer_YPzxKHLGu+JZ61GA#p8mnj{=vny2gqsYHC(0cK z9(Z1TOYyAr+!04}aYOlJ5yiE>LHtH_7nDzm2xlBaJV%XDcn-fM_V>v7nTvEFxnmf~ zNka+8v}d^X8QLM35x}TuageTM*tL_WQ{34RuYi+}OIGr&<)>1?yc$IHA~X8{-_;k)KF$+!n<9#BruEKDOA-8q2RIzDGTsyToy!u^+^7 zQ!oy9Bl*8-B;JlFzLw}5)z})>1o^PyxFu+Z-9+|i%@kKf94}d9w~YP|TZot0LUwB{ z6t7uqZ;ZG#kNAc>inGL{I80(YVZ>v3aEpy^4VPLCn`gyj+s}j7c(AY=#~hwj;XL-j{!GSAcqH3~Vq7u&#@U1v?#BJmp&~ z#6PvMxISep1OgmBkl5wwx;;l1On*5~18dZH{GbB1D?%-0XE-?AOmp7{0|I2{;;;t(a$rekhZ` zZQbT2OLiwg!k6j|f@?`|tJ{c@ptnhoG$K5P0DOj+bg-%uGc(N z^}JFT8{e>>VVj2W$?!z_=(C6OlcAH){CI6LXiraMT^J_AFav|p#s$fsbI_Srd^s5w z^p)-Bdp8-HiV9Oczepy(mB}EJb1VPRk7V%Y>1`d^k__&C?+y3Mq)?p36!K@80;dM0 z+}p070zYOur+n>@0=Ehd=31GjfGp?GG6e?P#XKzTnF9LLuFFXFO94+|SPv$J{9dNO zrQsn@D@LV2(3<1#`+1~**Y}Kw4gM*x+qcwJDIx{V-dE9Ios`mQuPj8dj?PbkGGW+| zH7U@3_;6+0-6>#Ue#+Op5-5&t=cf4^ElY) zxbE?1mvIz-V;q=iba<|^YaHwyB_!sJgSacZSkH*5Fox@xRPq;@3hf$vI@^Cug>^;G zxm97_UY`sn}c%FwpkvTYii`?7Q+NFWenm>E^9JsIcb?~i-bZ8z^QyG#s7X~Yh zU_-uSP@K&9aQD{Q1s*yJDSpZ#xR+AeaPj^U*zkV!pxuR=8vXWX0>cG>$$}Y< z_jY7Nt$<@A4%n=#TM4i3_LUCbznXB&HIOx_QdxS#THxF{K3-4pHgh5Qf-lP)&ZD?9 zY<$X^-c1jdZXtW`Z4mp#f_Kq+2c!qRf8%Js3r5~(7bP`!53EkH*w?9HAH*IHh}u_n z0PYLJunao{Tv(aMhoOhiZRm=l@I1dJ@k-Kh2x;2LBBlB8e&r$7qPl?MYn=f$XbbD| zv=GL#Y(>^In&PpYCqESz$iMGJI4U%Y-gOzY8m@i1a{ek*bt^DamcK#qFK>~b#oM(1 zltKZ^Laf%h10#Lr+T1G^^Bs}T_<-v1i2Of30p)eptm*Z05Jt_MzUT!Ay+lrLcuD0| z!t*Z6a%;Q424B`2<$|U+aC6tKyIxiA;H9_r@!PyA;GdFG(|}K;hpQ$(j9ET5C3!n5jlC+$%$zkObRd!N1e!zHX)Q|pBb_<4|E!Tsm_=rbo3g$}zoc#hWSKbJ)P zh&;n4wtPSLw*zj8dbE5Q^w}L5S8P^}>ups9ey-e?bv>0)*H+~^JPGyj{Tis}YoY#j z;=0_b4*FkpxxemPpX>IH@MrJX2k@Z$ZAZ_Dd* zYQxXz*Wfvfd?V$tK3r?x$$`@=gRAC*#!IVg8e7V zZr#eP#|F|Hi3o-$mImvBHo)t<*eT|3O5Y@sW$!91%J*9}G`dHJQ*T&J|R;^Vh0 z4&VBsm=_g6Ki3j{W(yvVH{m;pbYe36h9`eSC#pI#8)Yu0iUD{@UN9u zdH%rlbq4M`%ID?v$-YnWyh5H2$+?j7Jc)H?O8z6yYn1tgobSl|hD`YSDtrmn*=3=w zSNxfHK9-F-AX|I>exI|Y_@K+a=d#Z^*S)z~-z}b3uSDP2W{#SYMCCNkHWgdLq zRk;7ESZ~-$*3+rL<53|uRfX}a_zSV&k`6wvgL+#ByaOHZWn|wl9n{fszJa3GlIIQV zU$2XCtBcR;V*9$_2`Kt3KHmx-g8g>&F#piQc+~?RK@a0w;X$z9zU=Rzhnxmkhp5!~ ztdG;feLx@AolxJ4@vYVLu|0j@1^Vcx>BA3BAN&h_T*vy*gXsfjke_?{IKTS1?)5Rx z(8u+tkL%O`d?f?;P8pydXMp*k0p?u>;Lqy<6I7{ge}k9ub*KC*M|*-fqC}H~-yl_Fg$r z&0|L(Z+ay4>R`KV+sl!(;7r|n_venH$4|rJmb#3lO;;cI)_FRb)Dm$|$o-f;cGAG9 zV@NQgd;a9^7<%@0(Us1QV`=yEDYZsMa{@s&nw({;}go z2(d0TW#c%SXbOTtF39xCHYl(65s zyqhmAzF1^MbYEX`NefCp73@onMsJ6Gp6N?#3p^QRw!xRiWj&iw$TciZ;xBlT6UWeEfQ=w`hIQ&gk;=)#QQCIkKa==l2vv8TfPNC-O_TQ^?e z2O8xsH#B#yAMi3itsYtSJuI=$T}X`fqseYLRYzR#qXU9lr1gD2dKb~T@9EcmRNrmv zsRh}7B%)x!h5RYMNmR|rW&P=c_16`<$e%v8zV@3@Pk$=7%r+n-*q;VAZ0XoA$)D=z z^-QR8&Yz;vJMHnx@TZ{-R=z)5H2{8{LOyhKzr)kl1<>fk!woXN22iJBA8Q`-2&4~r zPoncJ3xw}w5IwP8awa!0h%yIsUvM%lh{V+A>Jh;t*;-nM(2^(1PFNiap-(q6cAX0g zrPfP(e;nE-jLh443Q_9ev@x>y%e%$YB&Jw-CnM)(Dkat}vZngZ1d19Z5+$brN1j1Whvw_)d(WiNsSCdz{4|S__Ox-R zGHVX4bT52hQvZ1rI{U?u2i+EsK$h&&TfK;k$9Wy~ytjn*)af|sOWh>ul;zWKaN<%D zRosgzET{gznJl_>dj)uUtLVId^0{tUgM9gQ@N3)%9`I)BB7CczFKr>wb#->eJ0FZR-FeJ68)QwSdZA=j{UUX8)_YG+IG{-chHT0AkL-xgudrz>}Oph1^96 z59wW<@u!(J7-vgC-@d66`f1=h_N)t>sy^nI&cNLo^7>T7%P(~S{sq3nTJRjQ+wpQ< zz#Uh5;d5TR{GK-a8rYimqlqUUk9jL>uLb70%^A)gRVa08C# z%CDcA@ZYVQ@N%u-?_>hpacU#pu3ba$7M!*C>h974v$I}3@I&k3xE0=m#QQt}oz*Fs zFIofq0{F`dd6%3MUKPh(1-~n}BlnvX+>!B@vW(l-a|AwFhR0E92jHOg%*SnD$K$P+ zE%zmh*svZywiM$brX``Dum&D%h1~Pv(1|FxqjdcovShsPhy~7LVc>w~zzxCM^)dsV zPzdA26#R(-(3j)~{$axBGu0UDF#KwqmfQAs~~z&T}|i_({7KX(;y z6&3VX3h#ma*5y7z4)Q6p(Rauq)}Le%_t!Jgch5v#mg3_s=Q^^UMnlYx)*$~+gMNnw zIHrb}SD}Ibd^+)d$i5D8zat&@Vda%^#B|_(%I6qYOea1c8uX2n?Xhl4;Z=A^jc5(- zgBtM3HQfXZ74ok-}=_`_nZa1H%t5dF^?k~`=R6ou%0QK_&%8p{5TuAVcFoReD7P& zII+T$k#i+w-5LA)=b*2ZgYPc~_-GEk?;PNyxmrF4^9vMxS_7%^ujEI{I4t}7=W2b) zn7^N^<>50<{e5mE?`IyKZ+XbS%mXf-2mVVQ_BW5%2P+Rcnml};D)dEExZkUQTdL3p zQvo+r0l!p%hcDy&|9iiB&T&=Y{-kpGb+}pL6TX)I-1G6D;bw^`d=&CL{2$!x?}eK& zUZby)Ot*!hu=yL`nQ!&`U3s{u5|{9QByz9t-*5TKeX-nW-QO?wEj~8{%YFQ2xy|?a zjUnIQ9a#KN_aftu-|qJx!XMQGT>d=xWAZCL=|8^T+5HK9b`p~R{ZNtbd$u3{{c?Y| zcYlOG8sn)apO0UKKdw&aE&dFDl=+N>`jnlJuy-VdNx{3LsH*qg%4O?}rWI8-ewz1o zG_`xsGkav)F|;+pXUotPV`ztU;qQAaVx}ZOm zulz~9wSqqlZ!RVjD|j9IW%`qyZ68;IIDe|785#d+zCQ)*iT`kXy}vdO<*Sv~Xpam2 zRAx_h+}C^lG`q=;BjaEClkwS+S*26`DX4wf+S_#kX!50jc@0eiD9Ll#nG?kWX#1Iz z8Ewi0XmP)g-A{LSa1J0Lq}$@MdjKun+OPGXb^+w$F*D7uPXIN&dveL@5dm~9`dzsJ zApvy6d5TTN$pJLN$RRCXVgTKEy>6ZEjsRM8XX9m~a{-i`I&WL!X92XBMs{4K7f3I>iQ_`|KM?!>gQkZLlhkHid}5S|C+6YgA!|br2=yZhL;JPY|td z7_qs-`XDk*nLDVhZZI8xlWDN8Uocf4VyCn0Trh3yCnk}HQ11IuwaXq4p|BGD_do9x zN>yL9@7XCWl;Xp0UtP8)40`-<8f#$r`jvy43W)Olg#zBVM{{qnZ3NBxBnreMsLREN zRwFw_f@c~Jg1gFj!WBk&yiiTTQN>99x}y*?j#(hErtXJ1)UX$g6a z*|OB|S|XiY*)yeA)uqU3Sw?#gEU(eM*$VJtR$>2E)8wFd4}Y_Dbmd(6**&^%Ac-D& zdlOZjf3b~Wvn{mdp|uc&vy}pclyr-p+u>`v6Z-Mpbb9VS!MSlSa;f)|03I%XbnqZa z@zI+P(>UR1KHD6H@8U6P{PNEF%$_GmvSX}qiVRLnt>Itg4EXNnkRNk_(hd8}^(=Ck zYD)m+6$)BWSx|Ie#eDoaiRj{m1~-BK-Nt_1MW5h4=EV;&FHDASV+!=$PiU&>l9~6E z1Ty2v`#YYKsNUW^`6cy}3@Kkz4_9$d-;(r_`5yDzkHoy6&zL`d!TC%DPbUrdgN9^2 zknF!K;Y_=8kvF4)&+hkmGR$`|1h2ywxLrQ*Kk_4=&lGqOaL3-}@DVP|I*}5V%#Tbg z0{%xa#=Q)zz>lQ@#^tPR7|+>d%dhEn%*$!xz`U~qWf-6HEDM~c9R6N`_hT9S z%(ua3D5Vh1_{Pj&6J$uC9#d4ru~DCw!h367w2MHU{3?5PZ=FIFI#tzc<%|-U2vm zNAN)FDLI$SW2%MoQIqHKEx{ulRUPLQ=Y4S%od3%F_iYuyuY~@pP z9=_*E4$NDcYR|l-L_6k5?YCt<*f|^E1f{Y5lFY;MD1mWhh53GQ_G|Gj#(EL2qWnEH zDgrzZ{6}{S;G2b^12Kng%M9bS5YA6Q@G%v?rza~G9Jk$U0w3^v7$3&)mob8F$`HAf z2EZrvwfthnkMw{)>jG!g#piT@U&=Zd74T6N&SxI3=Ugp5)LRlX<-qqf8#rSYdF=d> zb3GtSt2dJUn>bfK6Zl~U`YRdWM`oZ;kpWyy1Alo9)~|tYy@F4&FOdd*5E}SmXo$C? z{LXll2L83m=UFGE=(%Kl7wdmC@VVE3PpAQIr2#KJ1Nx^7+|M(R=c({F*?&I+_*8~A zzf`qItxA=|I?^gwWsFEx2>+nZg4L>{n-1G6D;g7e!@=?h1@PF{fzZd=}<7U-A@i=(-m|y=8 zZgzN}%by1~>zm6*^yj`#zvb(w^x`}h9NfBALy|3rPp-v8X=>PI-D z7w|lJto)~OMESmwY{F-$I=1(R?kkCdTz+<6>0S7@rq|sCowT4W3{SWR}Wxe#F=C$9ZA9wbpF|*2<`AtxGhA)J4==o(7 zexPwPc($;FNQsp5$#CzHYyoKNQIx%n8E%;yw9&xKT*g~J1= zV(DTx?3V^myH?(nqHhEsM<nA2P2U2?DPBDi41F4*ON+12nfi(YoK#x~D0_l?| z`@I*4JnJBG7;d^E%|3`+4tL)%+%<^u@>T78y>AfpZXOp`JuC?M(?JyL`{cp2EdnkF zze1nh1LmxL7=%2YAmmU7L+2ZeJnCTD+~7grRw5 z2UDz0tBw6X1=EJCQ?5S7A@s4>Hpg}LA>`G$Ko=vI5UO;vwa2V}Ata_NcZ>_64))`F zdu$1T{y2o54r*QbW06qmpYdhnk@lhFfB)mYSF=N@OdFB+OyRpgr^7sZ#6~T zyLUfDhFa0GDcNV?La;rW`(;FtjzoZqrojh_pB?WP zLlV2MeJt?dIC{2VmJX2#)IcKf#z=+;@rS$5>4nTY?w~f4mWo8eKv#URulg>izbHCphDbfrM+7bK#&^_sq- zl>B1S%^Q+zCS%^w5)s{f{sHr{PvF@od`F&#eb0Afexy9_mHkKZz$emy?oAi?j~;Ys z2FUj^0uExV_0eX&QUUN23o=h+of-IV=Fs<9Kp$-hJ!(sxtJ_;N7XK<9Fm(8`T27=!E?R zuWwRaY_~pe)CPEM#Q0HDV!ZCO3*&pbu8a$Ibi;nN$N2-^SQj~#^SyYUn%S0*^JE)d zepYM7DTjOV-#uFK`pdUu{LBJ+YrW=-D`k5yPL|UYIAl}aUNLvZAFH|X@p!pnUJTyj zIyu*pfNM79_1$mC>kDlFywsVu|FRzNySlvmq&mFbG0K4ua4<5r;=YFRJM%KrfzPEA^Y7Ae|4auCnhqXbI`BGW`!ZjW`GFen12rV$ zn#>Q>;J&UQ#>EtWDfW%m5bLTnTAY>f+YI=~XW)1;Na6vN(MW&%%Dc$0kovaml{*qje;H){|mF8%D`*|GY5bNi2FdlL+K4jj#!lz_@qJnes z{U8_PGZ#GDTw*=E!mIod-pP3dx!}R(0x!>nze+A}$vm9bJZ)|%oc6*qZjTlFjt4=xF`uaEu7TdKAylMEY=ABt-qY(Dao z4?Su(!1cVNFWqi>Mb9S6mn^)LOJ_HBd8E6vvZ%(%Yz}>yv9!P%^p8{ z6#{>)5HhLqCU=WjDDB7yzcI}rlyvvaZ#bxSD76XMv8-ORP+HLFvPpq%p|qlixZzOR z^zPm4r|M8De#Ou8!K_e<*q*0zb8RTC+9(niLg7CYN|QdHKi4lkl-3F=t(!%|$n9*~ zwV}>o)J6CfI`- zd}{8#SUT2B3GLmhpyQ_nWS>J(^R@RMz1kV zN}xx{Vxc+)f`HBzy5(=(mdq3 zE}#+mk9~6@7a*2_G5wBtJ3f39grxxpKt*V+W%vn}M|+T-Gi-CL=lklyLlW;=9GJE_nft5Jtv z>>?l0j{W@};(qLY>L}6(5)P7ddS)Lc!Ia(6SNABDE-F_3$Ed$l;Ge*A_!M{tr{ONkKBX=_M8~n`crL!g=U(Ia_?D_l_D}E8 zXZ#4A!)M&jzu^9#iucptQzF+3nOgk?KRU~h~g{H^@jua7G+TH zL1$%E9(8I3)cvxbDg1>BRd*;PTsK?=>bi);We|MLk^=r%uGM*;mzyI`W{$Bl>Ux#le7yc{Y+u!z0RHnSwTyK8= zuYBEfE%fh~`~H*v-GBLYh0B#pQ^7DAv`uEGpcNYmy*wUWyDU0^NBinKPaNCRPjfU`>cWcW$Nb@$RUp%?~ zIMNDrNK3{6<6CfD8qhI9hh4oo>cOgf z9_m%${Wwqw^%wFk4Ju%{a`0U%i{o>|a%F(?Ixw%OhdtM!qwU}$Y73ue8}JfK;XIWD zK34*Gq!sGa;?VyW10S;}cu__0YRTIvVF5jLVc_xRIL~IlI}1UNS&+B)rT}~h@&g|< zL5^WQ@TZKi9wYb&7=kBdz;)$$efGmIpbxxW5BsePzN0R1QrXvAh2vImNcOqQ)B2b* zK9U1|V>bSt4ZJW5_+J(=o|LKON3)JP6aEbuz>hMtx@FG2RCtfF?wNJS8sI}3%*Pbn zw5-pT@jJ4$41W`OUP0e*QV_?k*iC*yRAPbTY#Gl_A`OyHQA@W0H``c2BXA1zJg?^NZ?}P3B_d4tP+fNJ5lPcUVROm;j;4`b@Jl(S@m-oHj z&se4!OXGu%tg0WV_%%JacB9n9k>luArhQVC7vsnxe@N3^y}fC=eu_!?>)y2W^SQp0 zn)}ezG~T#Dq3W$^O?^6 z1H!zp9BtLgNWlHD=}scB-z;ysMVsj2lX zi(bXT)X=FY`~ul8$ya~Owty{aTCuF;`Lc)A^hAsky{x8cMM`{eeypbY?<&+Um!_sI zDX#>F@(B2NMNnPq!#!-9M9_+%UQUJjM$nY!r_WZ4il8qE6>K8cM!**-g2a@|>qe23 ze5dq*l*W-%z&o-|{g6nq>nu7%MWXK=MfN4Py=~Dqib|N-ZCrRDiq80UI6K@inj|^Y z{AemD1tP|f=%Tb|MGUPNTxh$lTP%qx9K(;X(6zcpEk4vCA6E$tl2Th}*#kcOg z;XR#(Eno53FM0-z8d|%|`zAmCRE6!`@gD0|(jwIaJ zuz1E|(Do*Rq$-L0BtUX0-5M&ccscSuS5gc0{O&t%uAAPkY0TjM@!c zZ7)go>nHb<=%#lygLp98LWk(zuO zaK2Zo%VaDC16)C0xSDC>EuqM!dg-+`Z3PTD$J8fVkc-}i*SQ>6yrA2i}RxGiyAebI&gZVX;QcQ>9l zoOI{9vz3R-kNARW8=kLl{qUd9-IDo&L(F(PeX+g&Yrf#G!#(hMv>(Xok8+s53-BH!C=3mmTw=HIn3A9uoQE#QJRv0M%G zXOSoFTMd0<=->NQ2L37YR4ZV;sOPN8@p|4k^53tNVgBt&2j(T7vS**i8+Ke5ezb+3 zqb=&x((rvO#kj)45~wS!*&p$1anzs1P&XDu&P5UUCt9+vWUvKr&BEXU; zJQYMCP`1T0SXn_s4i8>+}`8 zlFxUhmY@0~-8SbBWg({~OPe3W{6RTKOv%sTT+HuzjxQ%8Z=4Mte>U{&*_bzG z0~gHE&MW!*$|2^p%Ja+|;Hls98<`)d@EaM2R&?Bq|K$?tskX+S!rM7q#y0PSuEek`u=3Kv7mbQ zI)5q|G%+r{q=GxXzOXu@VnzU2^gDK~(x5;JfAH#}#ic-+*k*S34|Rj6)b#G<=PeAP zwr7{e)=?=wL&0f1SC%~zOp1J;8LHvSucpo|2HFhlrlt#x%7lCvt)@D58*03aR+CG{KL6`;1s1wTsAW7a- zB$8f*wP_MoCz4WxRLL4WBB|r)SwTgkBk8kf$FwC9{z#EjqUF1$+e<|umotiPf2nYM$$8BBxx*6R2ew(J4v69gT(5&ly>YkGw`mfn4R20RH7PYChrg<_UGD zgSR__qGEFeCEZNoe8yR1(L!=|C&P+Q9{tvHF7??_Gi6TZJlb@zhHdbH1=RT5m*n^B z7lHq|gd|saGa<)P%G+E@GX+<(Yx|c`QHuprhr6wyX_fox?s~tHMD(uXk<}!uB#3r%m?XQ2&RVCMO@6-_{#0A3bVgLfi-+4N^xVR#6UXl$5#6lOeHTe` z$M$<@V6XcgdI9^Wr)?7fF+4!;Oho|qF!TpUNMt?EH$FzZ+2iyh`q=VJrCUQ5^WPwGAG`y#{~&8zh*i2~5gcz^Ct!wE155NKD1t zvGM^u7wx7BCgc8=0vz%&@X)7t|2Y{-Mo%wDRE@2@^om5+`$DhYAb<5e^b{Y_-}!{+ z(iixSd__Ml4L%{VZ*vCl$t?I#KIa9>CleO7(wMhvw1;C#Q&hkUgB@U1Zg zKd}(wkv8V&Ll@@t+_qp{Nsl6^tBSg?-$ilYh1SRugD=m?(#SuzMIXqH>o+?G)W2o; zb3zU~>%GcBFH-@yWF_c~sxUsdx*9L13%+Ahrbk~b+TtYtlt^>oQ7PN z3iY|v4|SAtBAa0U!FNn`Gzk6Zt>#a^K>O@mQ|>H_LrHKa^MZXMO#3_)~HNK9@hnHSPa|zNF=A%Ol`l ze}gg(rLOz$m;2YB{_p+kuNzmku78Db^)p;^Obb2=c|84tYyQ1(O}Vd?P>;vKY2bT* z2wyz>b03T!;fu|2x0dfv|7kq+hkVDjeEjnBTHgM*uTp)|9=?zJ+Cit=j`@3&ynqw7 zWqk1<@W(l=d4B5c$+%pnR^Z*VWE`$i3m0iSw$NXfY=+-G@ILB~M()fn?CQpKN}wxm zf0?Y)aN&BYkPGUc##}#DZv>pL0s6MiTu(XIM?Hl4=uRDe|3GcVMK?O}_SeBTa~tw| zPQX|5Np-G|3P67%=!){eSJD{28=>wt#Ci;XbLvB9q=)_2V|;avE^=#R zp9CG?oGRd-D(JaopSwKp9TXf=*2}WLUAC5ICxosD5M-9tzmWNbnOglYOOC;{0X;kIjVtZzk|N#Rrmg+=^~` z@rP9>Th&$ae;7~w-v5zt)GVz}C+oMfvE6Ls{(PS^!+2&ka$K^JW3K3<`TNd6?#}nP zA>(hdKSvI7Z*q`(lY{-q(atMnypVkobBTRAbHNMBg?>-*ePld57rAUd=R3-I;P*1Z z1gJ6(^ZGpK%N2Z($59^Uy$U|aycH!^hR2PPE5qN13fH9yz9A}HpUU;cJX;0#XTGco z^Hde)hbousJr-d*oGs=5zpR&^Y| zb(aqf?9$!ibt7N8V%S&D{_=U5LwaoP=ubv-rqsW5+n>6W z5gmd8sQF5_RWBX{(A|ZJ4zq=NBgf|Yn6Mcr>YcWKWcnlIAX?gY_H&o=K0bWr@u zO-HKg*t&+$q``x-5_W~q`$j#--LDWzGje;I6q+AOcecH#Svy}CNpXTcVYGR@laO#2 zMu}PD2JdqXr)#wi9Phd^oW3si95zHxO^M47>&~sIrp7aJzBu(&Lx-!Twv9w4r-EbaQpw5Feums^Yq(h*Oma@;$q(M89?dKG&?IV8I_j61{VF1Q`|_^2%gq1fA&8 zV1oB`VY!4`Q7t}2P%+7%K9ag$FSqAd*+`oD=-$`gD3W&G={i2Jb0o2jJ(6Cmdpf{B zB9cBueOWVLRwOO-idVa>j-;37%U%@S8%edV9cc6VTqIqcQX;JGgGd_PGH^rm`$+1k zvR=_DFOueO&KWqVP!z=vUfi>TZ4~*Hq>k1#qNwogg;Bq`Mp3~fKK4gCM$uj|cJQ|- z@@{d%&mts>8q~YJp!oDCI^5{ek~(XnNWc5u$dSjRXuw(iM+N$Gd(-AS0B+893`GyetO2_%p`g&;{Gr;>^X zyl*s#Y6`AU7VeXQt4*N~oy0_fsr0pOl9^6i0({G+!Eb#!c$hOtC(cWtR?Z}o7-NB| zJByC(>nTuUXVbi9xqXxO%%REUB_xjmB%dz!i%)_ddm23Ov+(yi4?X%N z@V_sEXLywYB;%)R;6dIXN!A^9iz4(zgZewP+eK7(-=hKVy9<`^4@i<{*G#7E-BS15 zosdEsGJB3Zk^7j&N`aYAp-XrUf2o(GFWO0&z9v6ufwv^GSm*n{hYtHAbO4`#AAUh! z>MQmy4bLMDd^}`-k!-x53q6I*`_@69R*(D0v-F{#HiW;85$dRXc+HRdqbdBY&2V2f z2S2hf@H zE!7?7(D}GR|1$yo_&2q<4j)jP>vK&V)Xnv@^)~Y&;lCc&7|Xlx@^hOop8437>+z=U zT=yMmih92p*W(3SxcoYNqp#Or0pIwR57@Uk@3ra&KQhj-yXC)M?gt) z{|e*kXSkW|06q$NJpF^4{XKEB)2(B6yD#Q2+fncZPXc4&XQ1Gaqodor}azJ8H|vam$AFj4q|&uUHc6FTs35 zjTP{{;=ucgan4e=qFm>?7XeSw61lb(&`B5Ox-Z5YIw3O`=2sO0UlKX*)~3+&2%FcgeUI^9(Y<vY9854%{mpxR-)E%6^W_rCWB#L(-^_ee6~?8?#Ze-5s?fJkfxoN5xK{DJ>5Z)O z*TH;H2mJvZTsJznZgjxo)xq_zgZ1iwkD>#AQyt7Nb--8AVcxNsF8ow=U5upz(dFE! zwz|OEb>Uy23to(z%cP6@p_~`5%l^SvbzS&-(dB-{7x}u{+Zpoinu!~9s!B_(jp?YXzcQbOT^UFE#xxHo7xF%y@b!+bl0Z*u6Mycr2pKmLt}kkdV93c#Z^;$$#-Vd z9sS~d;H~*-^CG`IAG0BCvp<#EFswzh`T;b)=NQBALjg2LmEB>jdmyb?9+!0EOdxe= zG%x&X>mXWow)%U+D?wDd$@NfG`(QE=?e8xO{_L+C3s&VJbf=uU|G+aLbgj*WXNGQ} z#Ce^eG^OjrwmQ|rNOY6$wk(V!`+JLUy0^kKZbd{m@;k$6ZHtewP89`S;n=Aw3iT57 z%L4nd>l8IfFvvkQ#RLy}xb}^jj`uF#w?Xj;`0quKUrywM%>s{5#v7@(A}98WEZ zq)J&EjdOQJQeVRX?n^I6QXRuZX3j4aJh9A&l4re&MA77{E5ch;jG{Sfx1XrpIEp@p z7+zn{E{Z(cc73cfD2g;C-tA8DkD@P+j|<3W6mmqPXn|ji3qG5o$iwaAvW`ci$g9MS zS1vcBXisjhCH3D#(Ulj=Chb;5lP1O1?rgDWnk34RYedrn$FZH=TSrqXU!7{TMnu!o zbkWE#n(oCscb>dGnk4w`VKjB~9MO2AX$%>9Cf|I}Fos;xg3?a~$53!$5kb)$LkUr0 z0A&nyzkRJ>ct27;9$1tO&s*Z3hpSTmKIq)o+Mgh zj|uQ4oJd_}g?7=;n@Cg6JA_yNIEfy2Ew<~5Y6>kmJ!ARsvQtT-E7nV(8Iu;qGV=^Y64a99CXkZ;6HzfMAh?e?pNT~f0YcDO?TF5eI5RhH<90Z z3%PK2sI^4Ey-)cj*a#5hLsCr(6O`G>WGe})Q)qDf0D+ha|NV^kjzt8p|7fgzN{YS z`aRIcebf;5d1Lf@O*p60wgCD;1>xgu#ys=s=6D_zMn0e=elNoP;Mv9SoUr2hs7(pR z?fR8MpU4I}5?l7CZ)(qV-3kZPv*>$ogAe)O@?00!tH{rns+G~lt_obRI@iBJ@RvUY z{IQY~>Rseoy4L08GU01<#hLr`=Nn@G8v}Ply?(g~_Qwr%s5|%P4LvYlz`USW3qCGk zp22#iw!GcuZFo7?);!N>=*jhR-B$eEsofI4w?MzUIgYCt@J$ab&r;&^$3t(m)(yM` zS3a*g&|B4Q0zQQcAJ1^&_2x9<<5=8~*XP-QkHs`#L4TueHW;S^)Un%C;4|B{* z%mn;F{3!%Jf+_eG1$Z8$n;&&rK0cn^#=z%|P=^=-&zJoT^l@DJE|N^BgC6!S`Y=i^rL14#dRWm# zaowGU{zn@6+G*%-q(Lu}rsZREzdjB3uQcpe8s-tH+TU4!qb&ETtayZJ@EK1-zb1{i zj!#2hCJp()Y1({W=69r_f0TyjrK02Fc~?4gH46WNzgNXiKYPumtF8NMuzn448Z}t2 z2EOWw|2*r>6#bQ~W0QF#?5CEAd0-~^2$|TwEa;Z9NX`Y|KE9%x;`Lte4SnAm=Qr;3uriYk1t~AO}|VCDw7__3OB>&%B(!Am_j8V7{({ z>rV%KdL2CHbg&&AT(7#AcPRQs*2(GOd8CW&>EiyU3%o%W&jC3PLKirKuGXiGedKlV zT+v0Iv@Yfw^7XCj!sAX4_a{B@=XF)a{D!J;8^+J@>vu0QzCL8&zhCaV5B`_`;n(57 zw!{AlIPlNeu|b>!oiQJ?Y-_W4%d*KY`xlM?C1c4!rjPxPSg= zx#T+EE@vqD&GJ7g;f1d>9UZ>zPGf!YtDf+__>Q?P;aT9Ka>}oA%H!3l41~Xm@9XO7 zN-HqN@_IUb$MPC~e1887dY)f5-V($A3g-h~zsjaY(5R$JO1@$H{<}*lc`z?M z?{<9P5KJX@>j~7uU~O)rk!Y{DB!v3TsQuc`I+P?hZ+a-zJJfG!6O%CT)WT?QwA<)U zAHzuHe11-`zTp&qyKhRF3*lP7McG$z@0a7=JJo8EeG)nMQ%$2Z4}8uQjG){bPY&L2 zj-c?RTl=*h6hWVRwd_@MN(8OaeIJ;+J%TnQUGMFFFM`r4oEkVbFM_HkMIOsD86&#ZDLnCRKeVcN3UJJ|H$A1~48$}Mus-Ldq-*ili`bH=DvPa~sfut-0h9Yr=RS`>0y7e#l< z7MZ-`P!zeEEOy;^J&L-2c~Y&)>nMtN*Y|j1ooL#ru@tC$(Uc*+I7O2bN9h$!#THfG z@o;oB@FHP3F`jWxG{uXu;wOr3T9N}di-F%o42kKM9}mS4&#Pj!xs+RP?W2e56#Vg% zdTWI)0dX{0gb6>!(ftag*5`T0BbRhMm3KdE*Kv)4KW-Ax+UcbxB4=_UZJ%+Z-RIYn zsOpRMJv*gMrZ=5Mpl~WZ5zxW#>IvXCC!qf{jq0u}SNW5AI_VrK*(hxE3`)A!%6gga zOo|p^(pj^>+no*l@?7YM=aJ>M-UXhy3wmpV!vTh-i)gj;)4{uSmQazCMI%ejOr$5- zt%Y4pqPdxY9j2KqBPYoyayfMu>3=yZkcYMk`HgF+!t5RblDUqAFrWwB_HDp?W;1dh zw~%YTS|jt$Zl%4JBGRhl%t$oP2fKj#?Loh8KRwhHk-vkqtAF^NMuCTsUwMSqESD}+ zx<5oUTHq?u8*ee7<|Os0aL(-1-qX-SpM~G%1w08f+g4t@A* z8v>t{b1w5?{+1u}HdB1gjQck|%v~g(>rI6jHz{R_`Ck$CZ){bJ^)cpF=s#QYd{nO# z<36=*7-u_W%YC=}_T29p{J-ZvN_d};Gb8Dr{y+Ysgx9^S1)Qrk`b>3zN7e&g>CAZM zDEP0(G{*AqX`j`^MS4CY1Ltev&UoGd_%C&A#_KaiPGyI7j6LYd#VnTp)r-E1dq$bbzH8n7wuK^sj zI&i$I*dF|!Qe?e+Mc@||__&{!172B{*E7=*-%lCzIURtL+ryX14)c9m;D&L_R zqr!h+9ZMGQt4!dSnRs4hf~SxHf2Is=4kWKfgT9HvKallMGEaeh5)_<|akX^#gey6g zG9D6Y%s6*-Sd4|13i$U6Z?@K>rq<~k;?$DAp_?x z1JCsg;FcNCiDkggJOlptnYa%t{{5U+nhBj+Cb18`;_JjY0a?fa&4TVr$*p7_L>Bz- zv+$hE2EO~f{z~pU?Jh0e2(pp$n2p@bY~(xU;P`T|-5l^Y6u%}puR!KuFmE6ScyX>) zcg1*}f@^-8KgoV!ia!(kohiAKiPqxC$U~k%9`-8_xOpD(Je9mju8)80FVFfs#gB<` zSH+Ks@l_R`KZ@Rp^ErR6x8i(-@AX!kcc23ALhz9nq85AaRd80ulVyFR3j8SrcV&K& z>O1^VGlXYP((~tE{3GK<#>4*oa{uC^|J8r`8Qyj~l+TxZ{{F$+{$6++>oW9J3AhU4 zk=7<(Mc?`j%*Aq>zgg~Eesv<2O9bCqUf;Jo+|^j__IUn}yxhwG{BHsl_>;fLJmYWo z`w#JqlYh=L{&o0OatwbXKgRPM{segGw>qQKA@Yd&*8@nt@7YfJ_sjk3PyhG+^+$N} z>8X640&wU*T28g*f3{rL4ZmMbKBJZUjhwXT<2ZWncfhHs+M6zH46anz!iR?DRMF9_ z@}Xn>ukT1}>`NinzTVNfJge%x_*zoJ3(Ox>&X;;lgxP%(M&i?+eE{`5QHJg z0g<7!e#7lPer>~Om65@UApqtj5e8}!!n8ZxYpo`qD+!;<&r(yf za}lM7-BVLfA)R}=O#~H=)oHb{e*|(tBB;N`ygi4XMbM%HweGGh6G>+}&*`8m;DRzQ zQPXLUSH`VKl585yqDb7DO*2KWEb|KWC(m;~kQ_yQr=PX-HjAcQwUMD&<7k@P+tkZ? zn1b6Sq_3To?~sDqgu@Q1z1l8`k#&HzCsDe-L0dc^k;;3?^)-9Xt zQuvDX7iQcjX&bNAOK<#Gwb-Xc@w8YV8FqOQPfg};8RFbvJRRy=cSMhwS=0tqXhv-;r#T3n`At&G76uE_a7lb}zYj9iu}6e+Od(hR54j3;eg_05?I z9dQD!Uwy=>fXy`eDzH$moK$c|_9vVHAHkW>h0mfjOX?O`Q++lyXv z=dW+KiS~359Y;4)tqIR&cXr!K&wEZ-clO{mGVUH>x30$yk~Uvz7x36UB*k}^+((UH z-dUg7^8ox955a%&2#pYB_1lh8su(xzaUA&P2@*iSbsKJ<0xo$5zKiG4AGk;&`d2>e zGW;#BkOZ3!x<&(q^qJE}H-KB-B*~_6$8B2NTLdug0@r*%Q=fjexjOn0a${0RWKRwq z{TP0oPk>WCqmfb&{R{X;zM^O1$NId%`|mKn`v~9VPvE(HCZ6YgMP6Mhcq!?~lgU8- zbr$BwvOh;2a7Z03uZri_`oJ{|z^^i5yrxV(=(6(ze=-H%qY&^XGvG3Xf$vx_-so5a ze3qinn-phX$v)QL;g^ITPHFJ*Y=QsT@%nP@@%J*o2OWXmlmiY}0erwp(4|yyk?z;( zYT(mV2OqK~FBew}xSA95*Cx~f&k%a+ocg@|mkofML5Eb#g>f(s*{|J|*Z0DW@w8q| zc{}et7=K&XoYym?C9kKeC%=EN9q)IIc8o7B_2Tns;l;}vw`H8_EqtG@Df%l(C$Y9A zZ*LKDFXuGp{h!s0k83{s=T`xL+=JZ9>uxxIuD}~zd4Jk8;p2*R!TC`9=OtWvb3@>4 z4S2r_ID=QI@F68#StxMZA;`b%?Zn&ZT?^kI{GVcK@b*?#$M;+fxMWp)uh3tWuLQiV z0{BGb`FGE9*#ENNXF4+enC5_2d+;9ZIZwT`9e9Yg@DC`BaZ?I@rX`qPG{qWv3M(Fu zM#aI4QuvUPFVY@MKK}n3`IgM1O9!s@{j2=G z>>DNHo6L**pXXr8I3w$(H0Z}^aGzFu?ot!hk{`J|= zStvg7+`r0!A90R0pFrkIGH#ZG=S&VUuA2k?YA%jD7tfXNec@RrnF}AWT<~Obwd0Y; z&5v^}zx8?QE}c-t2cCI_dFaRGVgK@wYpMc|Pz7C>3ePna{6$pY_bYjp%sW={EEzvl z;kl+U*Z1nE$-%$zwTf4^+OJ^AAR07?aj)W{uHwN z>Fy5B0VJlySUnD)VVQ5$ZzcrN=*r~_oOKEU&J;v}35)IH;)5yt=$#FNYKG90yeX@_ z9)!@#8fR-&iwmW90}KwC)(E2+6HeZJbSF%!n||E=UB7CUf)C?kF|b)p`@2P@ciN+- zFK1JC&NC76QYzKB)Uta7&5YT!$#+czZM?qCc4m46e1x4dS#h6V}9&!=pdwl zx9=GP{#*>1NI}aAKGEyZN#SYq8zEKM>K0j*f-eXH7S(|Zd3*ZRwp4nAe# zsA)vwY2{kPQKLfdFWw!g;C}&P{PFrYnpN;-Uj6e54tRO@7~3-WKpUOu+@^ zoapPj&cE6^H=aHhu+A*EJDv*l|IK94t$3=uYrA#f^mr=MbYRyLCB{?9YZkKuT*hm2 zrMd4uo;>E63L|7Zoxk!#P-KrMqmZ!Tb`2+xYgw!M`GY4=4cCC}V~56}&%wzOAH9&}d znMzY9y9i2VA+P$x@#jzOCXnbVIjiq9suJ_bvNc0 z`zY(&dm%aI014o57eRYX2BQ69l_Ru8v`bug6gcZ~n&K-ODV`uH#%0$j65S_@?K(pl zqAlgqa}?Nhb?plcE>g6qDA2x4Vp>e#sVmS)Un8?uyEf^)xDFrTo6wWrhR*vgNi@aV z_kmMCLQYdM2_ZIX`*wT`yz>e8EYHZw`&Qx4O65>v*H1{VUJ zV+MX0c#exKkULX^@xy~f!SgB(KOJlEBTE90Db4wRLv39a9=F{*ZnYhB*Wcrg5`S;8 zf;&p{Y0pYp{v7-LRs$YX9r#a8_>0uy`JZlW=z`&w-l!hqh(_=?N|klTje&EyXmL7; zFEi7XKmW-M_+nGwnI3$e);8z)WXB@Aa8{>WxT`}(kPg4cnqpJ%qXGNGFHv%r# z5Pxp~9wTzU*VO|KsN`KT9#9+GbHeB0H}5T<_Zp0Q?ttI?`D%>cHL8mJs*LZik_%UJ z6|q0%F>cE7@wY3>f3N4r=e>Lx&WkMP0A8X!AHOGZFUQ!z@5zSW-(HISY8sXVKk<9N zdB(4b;rlEC{95)6umDfDF!0jCz$@f@CFH#KE(D&iDW8{l1>lF8AAU6^z!~!aXE1`V zjUn(6L*R}E@IjETOW6-WmwCn2l)Ovkb*aF&RDqYA2Yy>Fcz8MBk>$V-JsbUqEZje{ zzyr+G;%SV7WoU6Z)(LC0{z@{Bk@=G8#C*MU@FCN*{tt{hrD6RtA6wB+^LbALUtQ5( zGtQWb{a0T3cols%A3z%RD~&i;FpVT!yipo_f0gaC4~3!+XCI3+@W#`?`%HuXQabL- zicXtx$aLIS)4|_Y^x85$D*IlspT7qBa1D6p8m+Ef#%b9%?0fuE_Sur|k3%xxudeVd zW&eA=zh`K9s!HGli%5ZQds9rxpB^`Gnbc-YL3r-p_3CMU~u5#_4jPTUU6ToMWlrs?4WV z_?+yAm4oMK4*08zpFWQ_1!tB0(`0_9oWsew{9K%0C5KbydGa{Rgst8kL}h!85*wp;647NK;(*Lvuh{h?H3TE8Nr z2Zm8jV%7HL^M{jQ;$(AUb2xQtyW!wo!M`ctuuWKQu$q1=Tl`|}^TO}39iBfg5kcMV zSx%ieOvr__S(315R|JjivdMm#UL+j~i#ILWCXzPJe-R%tNAQ6c+@HK2Mbfr;Zte3s zMv;GH&aFK|qo_)E_0Ai@eB_4h`FFkFN0HgN!3A4XiKa#a&&DMRyoT0Nfvfl+6%^wJ zi^q`6V<;gFRK<6l^=JxTK`=evuImEp?^AdQ)fYE$%hQj8kJkTuUUIwQ zk;h}6$5C3i*opssUeYE!&7tYQc#_KAsCXLC|I65stK+Hr$ECuIAfALG_}#Tn%6#Oq z`|XckTaG8@v5Y6ZP|-nYJT)qJV06g4@f2{SOTysF6SV&D@;pS=OBoqIfB7kRBE8@8 zH7Wn=i6pub4d^uqzUPxj->%zX{ZW%?tX^YbZZ?HRCbaOlcytO0W>PoKMo)z=c>;X( z5~!bb?9})Q)97mL8KZaZ5ni)S-dfyE@s&S$Uo@NR4ZLL$`?T$n~JOTvA8DRgVgDZbT| z1}mag(9=SOi-QZTqWb--2vV)p)F*gw3-$c9H04!3VP?9XhDwBrjr1%mZmG+X&2(~t zwdb*qTWE5xr9s2{ZX;2Bbo=9W5?%AXR_vrx6~sWy-IO**6x!`2VUn@bVb6YCzlSgn zI7}x;I;nTL93@d*CCpGrWI??4K7qRb6zcjjWG2#Dx}2kQ-{ghnD=yHeWjgx}3STCH z{2)lGuE785Dz4w_lw3t*blfC+X+m?Gq?lFnyTraz_u+r?km_7$(B{gtWU@ZoLx{jk zA&H(b@(K78&&Wv%*nAFOxR=mjy(Vc|bmc9DNC6igP)~dW-{CW!dtY#WN=5EW8gflE z=r75AwruVFjCt;I|3{Z~P}B6#7czh!o+0W@Sr;PfMG8RIQV_faGw!!ufZu#&3-BK- zk>^vC^(=3Tu}{t+E9hZLpf6ks^BY^{M>MfxKd348%!5yL;QH0q5p`cV^pDD;e-53_ z>dN?gReqgRo$LQoHBe92!tprq`vu@%w6QMFFGkgeFH-~FPRB-ECx;Sv4lew8M_1Iv zn18%<=lXc82iMWXn)Ca2p^rKU-PFm}EDT~3PUiW+a`$xavf8F=r_t;h0pvXC$4+u)IvR` z{tiA z-i*kMFSp<2OmhdOFU|r;(!l-){ zzj@Zp7J_cOAoz@?sH5{^c@yw`^MU_p3|^)Y_=<)&4+bvG>(bZyQcFJix_VenSLp{d|y zroy)-74xN3;9{x3#ZrNbr6Q+H@uy_|VjA@1vX5>W_wCOX#$o>-dtV(N#nraG zF%mq101289BzUmk+)HrxQnW~+P>K^0JOU)dh~XC8X>cg+Qi{61$54PEzogFzdbD!(JgmJGV=$DgBymUv6P?$Yl$+%WB@++mEKkK!V z!F!kf`HWx5yiV2;r@)UR1;*$N}{4S?JWK6%8M;0lA5x3)i9C1xZ!^C$x7)f zUug3f_Y!7P&<~$NHABl48PtC&6-YjQaeDq~^kLwDz$J&K(dC~q^!r9krxe?6inPgx zdhZ(U(QA+o_3e-|u=QRa>i=TxPj&P9lBE_*=}WDX#^w6BL-A=E`uuEdD?d`gH62HE z_oL}mi`FQ)#*cpX8ZdnKM?Y#AJ0^X<;^+SCa%k-OKz}OxvYH|AvOo2ByD0pI!wj1A z=)%m1eluvC>QcU3>Ze4$qhiW#A2DDiDdCB=C&$dBg$V;)%iobWqtHX;P{cS}r%2v| z&^<9;6+o&gXGFd1^-g8>r3D!729Oe_cygUi;)%HjP|6a36lf_JzeoLCY)K$rI=#ooycnUJz9Xzz4#$eLqSB@d{lft^VH6_I4*QD8^4+ z^JweWr&~Dnn@=j5+H=+d@HrMz;~i!6?W-)NBaQ2OKHIT`G}!U0WzRcj96yGV;g=(LCSxpxbRud|Qdy*^UUrOkfiNgf0b z{s;{l^?v5rZbzYqI)?tw3HUIbqUIU_;xu?0XVE`9kN(94_$ytabAHGkv=x0ma6+d4JF^}S8VelLrP~R10znwwFp(iN`{LhK& zx6RI|e_fczFuDxt=d#d+iTw2nsLLyH{n@7q*V94pH;;E?+_JXtK?nY5Rh#STXm`C< zhU$fnQGKr4lN*2!A^8vN7vBWm`|bP(<}pbA!{_ivpMyM$5@^vs_~YLTf6R<~UCM+@ zXyf%?{t@Hk%po2(|MJn_`hWj8+#}}fUjg^X&W~WhG2VJ_jF!*cpXy%u=l-M~Dpzwp zU|)Lwz3xxh;ir0xBMc+me+xg=9pUlkgx~vJ_^It^{payhOU=hw+-Gfdw%RVb-u(4- zlil^z|L0#X$Go7nsAu5gsBgo#;WXsa>}v)7W=pO^%8UG(7N|eKb3ES+bxJeti#8Ye zHy(@wo@v7Mksb1J`sq=B5&Ex(B#ZS(_H=S8`-OLF(#*&=p@J$Km&Wmv!JFh76*Bu$>%Zs}7QDM}pg}867=&V_9 zT9EO=vjwofc8tH~w*!7?3qE6h_!#8n^U^X8bl|y>ua^@%OdH^b*392rmjlPeit*8# zmhf}51i#V(z6Bzu&kS|A8TiUNJ^SS8@IB#gmto?8F+VE}dfHU*uZ$*NLiSZm0q;-h zq#3`IevCXnmU!b3?Y~5JD0elGq=8Fd4YX;174B(l| zSLW-<;@;EdSAE&H5 zO!i4MVjLL3W0HA1f{)4PF%`U2iDR-}Iu*Wzl4QcfBwmn>TJB~ zyLsINYIrYS-r&w&)X#12^RNsrQeCGvZSkf%#b3BT>Nk;YZ1~v7#cmRXxBuue?c^kC z^Wj6z+Y=|#z?k8R#r+hT-0|7Ybx)^IR7SsC`4>&4T>H9Q^y@T@T!x-6^Rv}-YFMPj zq|W=NBiGP}G&*CX4_)_E1yVkg;I^}Vy{5kO^>g$2rx*EB*?H0XFMjZ)o3(za+q|V8 zO*&Q}zw2U!|Jdw+XU1DUTC@N4cW20-raC`8@M(@eB~Bi=wBkd5=vQXY_iy};*7lk~ z!naBIH3@zr`<2h6LkD!JFRw|wv6h{C!-HKUpHT@b?9}zgStNLj0%sJus^cwBM7LTQ zK%-jLt>S%I;)`$ds)Wiw(&SD(v+@)Lu4t_p(+5(<)KfDpoM%&F?g__tH>k#im$_YJSy-+Vr4v6c=CaGVyBL%FU> zwBsWB+55bHaN1&Wp0M`P#L%U5u*9RCam|<0!#al&&qv14uDIr3HCeQRF09$R@y-5~ zG*DsXmP}bi_f-4(Zi?GlvP_Pu!WaxgRZfp z!Nv==QJMLl!l$Kfr&5Rayt+7TC$0K&mz8Ou8Z(m=6AN&;>eIfA5 zgSe}}Ij_?-RZjWkP4Iee(=^T4=`MBCHtat7X>oY}5xwi>p;%Krrb-U#7CxohifdcR z!q4g86Z;ZppS?hz@D;VL`pG#x@ijRqX_+34-vKv$kLTeB@H^wdcQu%DS9;aqZRNu z{K}10P=~sK#|YlzLgc<1Yl259^5K!=c&sk^_sDq+X^1|4V=RxH$W2XvPkL}Y-M1Of zBkmyQ-m@jw)sh0mujbGna{#$rt_%;5W zSp44a!XtHK^#5Bta)AW{(%zrBH){Cf$hKS`oNNOfb{noEdLiF>X)CT{?zIFTuqESq z-CA(n6E5*b=D# ItItuGhjmc=>B0m%9nqCEw|l{Zsz)A@C0y15Xq6P6OVaarL>6 z+Xgj`~K_QSf;z317|nHMs8SR~`LeH(q{bHU52FRq!V(V>{44zE=VL za98jE%cFiQhvm?Jb}0kjHW$6df2vuU`{x~;8Q&Z4#QNhlrNAF70sq6|tnYtWl=7tH~jG6x^Gl2+hHTB0tu;Nx)29KMj|;8~iX9+&yTjGxKeYtE-m2acBp z|60jEV?LPCgdYjqiSfK-`1mD5kD3HrNAezpZkc`Yr0$t<%LJ1z1oJs1KaqbY0r*h@ za!(SVKTSX$iUIRi18`CK%6vbAX*uSHCV=Oe0G)XPcxn>=6g)|RGcpe}0XU!BUgi}` zy*JNyq+VR`BE^0)&iDIyks?2b`G`rF=O&r_G1c_wd{vUcLreyrB^mga#2JO3CG&D+ zE;r-HDW-gG=9$QxZq}uynDT}EkDOc4e7DTgVZNU9xn$kEDYJTf#w&>Fea?`j`% zjEtJy+sc<7Y^i*?=MZ1`jr&rsYvuPHFXu;g4`=tRHp`EGxV5v3%~L@BHs8Bh>NZZ_=VHn3@q}dZW z&!Nrr^lmNZ%%RmAbFO@65l;I;b12AZIPxQ9PGucUz#D;_fCy4TKNaVoNb1Q0jS4?_ zR{BuEDAMG*8=~l!p`Sb%naDyFy15cI9OM ztH5oqqpx-Y`h{CmRWsJVL#oTvN|*aovhcUc(0_>M>Lc2yuFmH%{7s%h2k?wk*ZZ#~ zyddVgzQW(Hfrr1vbLTzoTOZI*`G_1f1NicyPbd6HQlM`Te09O=*1;Fs3_jH6sJkrT z(`1D@${PMpInlSy4Ii4kz%BCwPqah*Rsi);LFiQqq0TD|9M1tf$D+t3EY3bW2TJmK zW;>z3?5x-B|D|2H-iy?H|CVdXxa2M2&m{ce+wu19 z?7+vtyVD=&AKd@VUjg69%=hd6^w;xNb-MJg{|TI9@AH4Z+`oS3@9_VB9Bvl#@vkth zK8Kq*ed4_k>u1ry-(PHuO{vp|1I3?%nKfWFJJNN@50UEehY4vL*w!BKRV@w zN4}XE|Gwx;iB}8dbM+HDC(_wy2Scx`m0MTqlLa3cE9G7Fb8~ZZZ3Q-1-oh*{nb-K| z#?`aqaoXUi$$P2$kMlS+-KcdNu2aUe=KADnEA%Z}>9ybWL5}r>7Qi1{aNl(haL3Kf zfLk@?<@M6%QPWl4Zo)WMMc|LqME{h)e?)$_b0e-xM9$7$*pGNPJT<;l+qwXxmbz0q`=z}{jzi@vM z@CXY7?<)j7vpsUH3&NkM0OwR}vqLV8Eq||&t;vswb4v2U*D*Kh++3(rb0W9G20o3} z$h*z~eUKF&pH-IV|64$pWP!Tfocr<{%z%fQppwE*w|Z|6bsb|it1`Tx&@WSw*}@HDC0W`3T`{}K7*tdCB{ z_{big6uCRqZPes)so!Q@aSGZ#3|Y5@%Qr|`8cQHdi>w> zA9+90aXqEexyKnUS64{q$Ds|TKpr>dKaDU?S~>ZCh)CbHfH_;^nstLm3_Rg3YW z`sRCk9{AFmLK5<}8)-k07JuqdqTZE>bh?slqY6=zXqyUKeleN$T)h$4zxWg?-fVdD z#ZRVC;~(SW-ff;r1G-F^;xSr}e#!O;UuXDI(av{@O&Q=vOZ~s`h&tg%M>kGNSz68?I&yz{d!vS9*b9GZexqoc zx6P%0BlBHn08g4pr>k~8SUYwmcyqJprJqr8QkS}EkrQeBX#QqZ*8mdyMb$0*`_~e0 z+@rXcH<}noYo|Tvw)$8gJ#tl*#*&}N`rO$ha7K{}nVru0*^Y*a6TRdiGM*buCte$^ z_74a~USlw6a^WM=XHn>%TWq^`<=a*vfI`jf;L zg+4k~wTE9CNEp;Xq>e34DDFcW{#QV~U8-x5YYnfcY5lokeE?Hrn>>$14+ zzBzQVuF4z@r*a$jD9-bWZ=*(>3#TV)jKHOEVk7P1i?Kfi(w@7AY4+8v=%ox84>-0~NRV0$B}+bi@~03ZE@^s(Qr8jt2LqIG>#A@^dM_8%doyWggh5N^9(ta*M`pu8Jx;(v=-3I8O;hRmLsIWvLBCdDXph<=pt@y)<~i5xC7Q*Ivn*jvJxA6!gU`$Ls;e#Ii$m?;=ZLzj zy2u3t{y4M<_>GRh5sPu1=2imVFU5WAr_fzjF3tVt5Es;uqV5F#*v=L8tMCb`%=LTC zs;DcGb2+j)aK;*3Z#$zuzpOTvtHX8Md+4su)#u+k*^t-&1iZ(&z#lI(0e?~Gn}qJE z1%Gc%OP&YxZw=hCEzcY3wMU)ak=J{*6CdAQtxY^ht=?MzzC#*t%r7zj*xG`(-weEm zPR;puVw!Q?|E?*1PtHFyKlpo1xZbTMb1k(x=?Hx0y&LoKsox048Tpns>jST?2R>+B z#+Ci*@Nx5Y$7^lg4xd^)kBX?t+p`sZ^B1f0@k)2&a{-c#RAZE+37W3q#|~F9^2XCddd%6KQHHQ_R9l5 z)!dj@qyB;e%FQTd{afrePkGhIw$Bi8sW2jWqBz z(y-lW(9xyix{*1e>{pgfe0GBmd{dV?W!kvEscDAFKa7 z-}sN}oAl57SGZ0y-~Vkbd8@O#n~Uo;rr^I{F1zplUwuD2zYGTlK2F})@$C9ku{nNy zJpa>u%IuE&;|TAG^?Qs*JvpALJv7EXSno;a`-il$?=^v%7W2s)XzNAp7Jb62{OCm% zWftk}g1zbOkQP+5!$gYzQC(2xT^1;K?R}Nali~k2g__@-S!zkgsWka+yP4i)rjhOI zP=(<*jaC~kRBLl-I!(4U|5&!05B&aosEWt7Lba;+lGWY7^7|JmyvK3<>v`nxqdj@* zwmm!6kK&ehDSPgLA8jljKj%g2 zNm~_mR>zXFNFhNg3^tkj5|LjG>Ik6xYRu$($!C1Fc*Mwd9Rq20g@|U=Rt1vKKZ|^p z@mdgy%w=I5DTs<|hKWIxd$O8n7zF;Eb5oK*x8c0+pds1@>?BpKKhJqLsp&C( zkM}@Ny$?F*{rLP4HTf_|k-i@xjs6&Ol!hwlGP?>L$9A0{E&ip?DV&!x=);^tKIeJh zk{8HKGi1C3-SidG;#TKhrGYDMC{6{}iG4J0(1Lb_l&G0o^s1FAl)ginOuhbnTIy3y zafEyb9^@nBVm=1n@+o{Lo>3(&Fy{sO8n5VzPDLDFleQaY-eSJ=9`lwD@WJ?qzLCM? zmn`~|nw{~|6yOM{&~c}OZ>rPt{LRdy4h;T?Dn)-`#*E5ZM%TXpaur0$CGpsLva%Dg=um4J6w z!1;8=_6dK_a*R86E(@Hm40Kj57;mK+H=pRN*YLyT7*ESfftOGczgHaNs~C8>j+{fe z)`5TDvk2pr-3nv73c59pj=Mb$I_1e1|g74@n1~ zI}Q4(RFnTV<1R+<6(sH`a4g0Vld+y86K=-3tVBH564BpIH2Jv;JrnDCB>pG#Qmk8% zzE0dPGGMz6@aHhV-`oH^E9)!kWDL+B8Q|9|`4M8h>?dS^-az_Hv2I4{w*)_fedDFC zJ?BkIAA8|z#lA<92f_ND1d|U|W_(iQZE_CcZ^tJ&zxeZhP<)*yKO@Ji<27_ptH!2MFu zmrI4uiuAK*ol{mndx67qZm4)(rh>Y+*!8B7Y1oJp#UMKTTvid*$akyDbF`i-lwQ;i;N8SrD5B~=@`+MPLjMrG|E@47% ziS;YD><8v>u+)&^ZV!2p*9+%;na11Q|r+X3j zW9IGtUHIeZar!?G{ut-{SGeD0#vj9hmt{9##C^|67#3%@;NR^1?C{4ox@(Ia9ueN}NAFZt$8TlZMhx1=Kj~nbm{d`}xUU*H>T{o<{v3WCJ;5WYXcF%;BWy<)`jRfq*B$ebM0r)ZdGo(Zw86H7>+TSNxR#`)?JdK zL~rl!qfh~7Q9}IM(uGdVGUZG&Um$=4uTkW@h@5D_XB7D@!e7z1>H01^tb?e`!=#7FL9}k(mW1XW!8C7so-vz)gGqJUEO1@sv?wNvy~}vvT@oqJ1R94xkzF3%h}@|TZV;^ znljUKRT$k+V^MB~QJ>B0kJidF2Rzd`)btB=%M@Mo>0d?|cg(?gkUoqRpFI4gPu+0Z zrJ#$Wdxg{H$Ds=H8BTVg@0=#A4W~|{x2?=^HJs*j)tGR!e$>LNgR4gXSCTqv#Y|FB zNJmh)v@SHNVkEuqWdE|@#7K&MpcyREoBO4H>0T*{f@>7}Ix-@P9wy(Z+15PTlq19b zn{$!#GZ*7=9x)$v9=U!jqa3OEbZOe^z&x84(4%*o?@w5is?F*J7F_}Gk#D`@qaj}vBGU5PyBRdh8`HL_eo;|$3M z+fQFhO9!bz+3RSw;+B{@Y6IPVt?s}ks?n=u_kzu~ko%c3F5e9J9{JRW(@#s zbrX8&+f+|m;a%XO_i1cUn6gA1siG_oIwNQzX&ylC|f^up>+^@iI zc|&2U?7q`G%$!Rd*CgF@OcsV-8jNevKZ?| zDwM$IrTF!+6W%Y)`s>-*^B$SEQxV&rmG{W=%zq7A>*1C8vrMU?^BS}UopS74))U>I9qK#j^k?KxYXqL*Ve#s#d$DF{v+c( zRk0n&3Ce}@xT7L)W8jc=U3t6mm*@B2mj!NJ2CpuxU;0`4&uh3&DQDLCw?&S+St&j* zJ|*BwS{%9SMX?=@;O9EPPoM~V?F(@}(i3~$ujd6B7fdX`*G<6!tgC8h$2zVt;=0HW zUnk*HkO%zN+_+Ap{}c1{tfAA&fpL|CanW*Cz+EljPhf%LY7SncIdDod;Ga79MM)fz z{fIK)v*KjNZ@YTb))bF*~duw zE3wag0{kSTK1<+!yxs)hq>>*g_>7*K0h0V&_}L3SCHw8j^$Ncy&Q(l+ue;2{8qDv{gC_fyI5WZW|mJh?x`*sp^Zz2~=_+%tOzm#P1*Wx_K zB=o<@Ju6)gTx8>JZ1HB61+yt;)O?Vjlhv{`mL89|dmaR)NQXEpUV1g_}8zSLzBe zqWDRd`QJb8I_>ZNx$Cs-pU|KB3~-*z$4&e#j;>Qx-aGOB-~IKE8&@$6{|e(OI~-Bh zoVWgSIHGs8UyrZ(|v_I=s<*V~ufa-;kGdbywKKS_Pu#gopSerI0RY6A6L-Kp@Q zLlbDk)*dJPSN-U8>j4j*wDYF|!&St_pZbRQ zdKM>%GioyI8q&W}@Ee71BiCO6q`LRbohtFg@h#M3nLyHLXr}{B`Ot#TC~!rM<~LgU zEo!h=onUIC0gl1IU4qG30}y2ni_kX<{4hvysT{jf@)Ju~Y`?jmBrlQiq%g88IimQs z!gEMh|NQ(S{j>5Bg}(WT3Jbc0lTH&dhm#f)GD`9iU!UyMVdtiB%2{k#zY0GpdT1tG zQd4aO5j3FatT}-dB1mOdE@>M<6VmxBzm6V%>c_XRx z@rn=5G>inE6-m`<-5j=hO(dlsJu>c>N0FqWf!;1r$ct9;VKl#26N zvw#jSvalRySU^r!Mkx^ELh6yTa6rw&i|BHnbrJKLunbuVA%O`D)M+Cr)d{lVJr!M}_pRka;edpmH|9n{$Bh>yGT9T z4>s+ldK$307d#k=JDz<;N}|po_%t4&nM!(4&jhKrW*qS(@p7lASl+lQ;W20Ess@Li zL;lx!a#Y+iKQ_5Y&jzRjN0~G8@>`Xmc$HLDcKaFEsewj}ya|7f+hnWKe|y}e(&>qw zaZBz4Ka9h?`Vq#_W8kGv!KZkRysa11w&$$6H%`6+kMlKrE8oFa_&w$`AHa`@H~FH7 z`905%lTGtQ<}0PaFFFH!6&>>UWX=rx3k!W`4)$-nZH-*MoWN&t!`~(^bf&i8Z`m=f zxTOHEw}d_XXbOS9RRr%l0#7Lh{b>o{DW%v)@{W^U;}JQR)@wRAUl;iFlmXAL9C&E1 z;9FJ%9tFLwYgNY8YP$hPst)|K2ID=&Yw_!n+E`BNtu_7U>Fo8^8vo{^@NJj4qn2ZB z^LgCyc!DBq9oP|k!A`v23ht=kB7?f}Yr&R`tHlCe^uT&gH)kGO^X9-Ifp=Df-_u<1 z9y2_6xxpTMoX<(UwWgPi2JVPp?j0^bAJG%1rC6wdycTeiB zHQ(qSjq4zno_Sj~rt6LIo*ejH zD?QiMRyfX<;CEWUZ`B;SZ!`F^n&G67f5d_sI7ZnJ3A4oC)y9m3&9x+r+#v1MngP_~-^=yvu;T ziUEAStgnna$>lkp&|vb#WgJTKC|MsM{i1|V6zgiG&YN}V29u9H=Mp3UKTJU1Q1T&J zmo9ywGUsFdr}0bXV`i_{7C5osuk!E990A6+lEK%LIHvIZVxD2LDF>D7!4!YV zo|!opGqY}+`N0y`Wa6R`=hq0I03*hM5xAlBgVKBs=KuHnp!ocyA}1lMZ@s|lf2(i3 z@Ht@oKMlBH8m_xEYdez|uN zh338gCV%u~^70?LW$3smG_Bac1JAoprIpvuItDeEM*eHde$m2ZIvqLh^}e9B54FEp zuy2uRJ{0ugJF^uDKB#|v;g{nJJ&YeEci-13<)$BfoRZ_(;?DjQy5RPU>gW8a!p_a9 zr#*iAJVfMCay=VBYWI8e^8i!cJH^qJOP)gluld&fEn`ZrJwuJ;*F+_x;lqme=7d`$K2s$)BW2-eI@C))bx{OkxJi6-=%3A zme(n?A)FRxylEM9M)85~TK~&WFTzdp5TTbkb>jJxJDnoX=Z-)f8Uerm2&%d6$AJUm zBj};3qADF}%A*uM@#PhjPLFeuB=l6BRU4-+QKZ>LEt9$`h2(MXmrl{tT9r@jk-3$1 zXH={`Ic6>;R2la}<#O}r+TiNjQuaz;C%#@5;QqgWMys@oZ3}TdETR^#*MIA`ele*> z^TC-VRAFmHYHtn}Q+ zvNq{MIM*dNd@=K4K9V1Go*nw%1-Nd!T#)OvFAHJ*P?+nkgAP2uSWy&pQgPH>C6PPi z#PgCn!mq~#b!r)&N7OBczH@o#u_{1EQwe`p!ROWZwOn<6f28QY*F+s(o9pP??py~3 z)#duNPko-xbOi5VNMoKCbk+0vW;NmY!6grVzh*OD{`=aySN-SuHGwS{?-Ka$KmD4&XTK)SgU7*_z-NC~zb59-)USza!+Vy! zuH(aoU4+$!j>f*Hy@H6PI zi_`{A3EpE%_&zFi7xSsAgQw?)@44aqs?d2?LETu1*FUo&@Vg4AFGa3-IqWBN*XPS{ ze&vrYjECPWt=IT+zc_=}=*<2Ajh%S=UYA5ZWC_M4&5A>BT@>|j_V^?F3fcqbEQs|L z06($-_>!UywneUHe#SK)=7o&$1t^ zEf^rS<;lK?)b^obOHmV!4qLOUTc zCzJg$6Txds#C9cOzM6~Tfr`KCiBo{sUA4qbaX__^uefo9Fa6uPT^ZO>RY zTI@-kYpxD@+mQ=`#i#iQMFk9KMP4%?~$QPwhF0m=7?S zQVu-c(6ZA3sQcV$(Fd0(nA z{!L7Qo4(ZJ!UM+<-6j8laV&o=?QhB@e|qh{KK(|A8B}WJC-(ils2oefE~lA;`n}p z=C7Cj?E+uq97d^!nzXU$$XUh0Np-WouF9gU!Awbi6d z$!};CbS5^aP9$(GnL}x%pkxgXMgrfK{_qcLsK8_t6}{i&O}iCQRP9LP`kv3CC`A3a z>d|y;*wNrae$k|+VLrSo`3{^nI+rvXcgK0O+xBV9jD_=Pe}4V91SS5WIkeR3&Gpu0P&bM2e}`^>J4glj;&x=*bd#pvt-mE~BUt#eBW{E~l7o z8WV!7v|!E^bj4xIDkYMWt{yciiIpp9gMwNrM~Xrecc&iCYe=)n>ZkA?T4wZ*+qVw9 zm<^I%2fx$jf}c{`=ptIU+0)W7F2 zC1PL~tyW_+zgBWCHDT92+N8M5D<1NsqJQ6gagfSA^3QGmEDy%ihj;9_{1Lv z9(R%w_T33eAAFh~DIzex&S!yh{zx{B7I$C1=_lxxE|CKMU9B|uGR;uddhz-dnvqvc z7`R5aRr|BTH=vWcNy{5nzP9N3ZR)EDsqVp7>H+vPaiq~c&ORc}DSd+VJq3^YIeg_` zV!ZrJN?4|1S^oylp?A0szsK|BBXWl0iSNG&;M)t|XYpJyn))pKJk7v*bjS}kL%nN( zI>-`vJ~@Cp+Hej~gIwsZ=7GK=AJ<32Y`HG_-VXWX1<~iV2S1`P@+*tLC)?4KH>A}? zn@Vs!_@)$eS@3(BRGM>);#|0%9#B@#^RM#YGq`eH8V%i5bY;9>6}luh;GNaEuC=Sl ze^0H&pPRe0ZfI2r?`LG>TI=LbREaP?~NVKju*dR`EOg!Vdt-xW8PbHldf9B zBb}Rb-LRt><6aG$F)nzhDdTtbnxg;d!QU&5zGxJD9?gM2j@B#tt^B9t%xF5+WsUi7 zpGK&EpttTQd5^4Dtp{AOE^xv+z$e|gu4#@wZqHh%i)sSbtig5EIhi-3@u=#$p&wn9 zKM$&c^;SlIwj#CRM=G3Ei@nj3zRx%7-<v&Pvs|* zj#K1bh+GZ!=}X1D!H9W<(WJ9xe>$0KB64OJ&rCAmWXvZ_1m9ZfsRiEnu%pT(lzd0w zyC`r##!V$(k@+#g$2J~0EAjBHjR#LW9=has@Jr<1d>zFD|BNTrO~*s$8V^3Y9od1C+jz!Y`6@3k~3@8K5JUd6@!N)y7lP1Y&$p>biwLB;$k9A5yz66+OC^+v=1E zd{z2rcG8HLQqRr2%tYiGU=nyKlIJRP-Ji?J z1Xawa{6HYI3GTC1_dtM};m^7T%G+c*iz|qr8_JRM6bRHH`@PkPenaPHnaJSpu{-2umjPN1_+UUq9; zz3BD2Pn%Odcp=}>8|Psnol16_e0#zq`gyx*cr%%1FM1i@xy2M3aLRu38272v-TwRS zyDLm14gPVSPG1(kkoIjp#bq{T|w&`0V%$GF#AzMGvWHE~0 zQw?3WF;5En(^Z9pHfo_ixfD88*su5u8mG9-M=zH?PmE{Hq(Hl4t3q97QHCb7nMEp_ z&b?Fsy~;Q6n_No+NJal16b%GU9SB|7Y~ZT1$)SI#r9XU}ZQ?r~d9zGGXrzx5>u<8+ zkBVuxB3ucf|1JL5f0JeK@r84!qG}8Dat;anaZKI#P4)EQH0;#MS8u)!CqtbTwq^n0 zB=l7xS28pH`2NJ^B2DWlzVE86rgsF5Rc()aq(75-7HrQ;UgH9VjkvRDBz^19xb)g) zk+eaDFULeucMZOaq>)7yy{>g7k_LR|e5OgxDC(}HGj`BNQR$A6TNh4=qH~2FJS%-j z`ZzVLu5Mv8&Qmn`x2vH$&G zj265&pN3y+TI&b@1yo$Mi`Ort-pXEl$g_w>mu=u~{$UaIzOZKR#y5*8C@Qr?koi)R z?kZ^0xkHuwq|f|_^$ssad8~k+(MtGntfDuwMktE2)zt7#-GNmauOU^nl`(ZKy{)J@ zSmC+0f!^7yv#Ms?NF87GPhWm~GoE8x>BWY8`y5Bc(zGsbuYOptjpnS$-?!7l?cl-g zq@`7ZXa9717mZumLXnW|A#c}QhS?3X;*W(&sLHCt@Si;jf2CvaqdE?~*GW3AT&>-@ zoQ99?SsD^JNP!N2gs$o*dN4*cY`RE!RCu!WWm3S+satnn!Smr7#ag@waeaH8q65^R z+nexfz72f;F7i$vkOJx}hV*g3Js-h$>Io@eu#%AQ6gi#GDfh0m6Hixo37+N8q{V7B zeM8+ed$4!7zrM$F;{)#N@#qJMT=ye}6+)z3@YQujBt-7UlVg@FmUcQ;>}1+`xkq%Vp-rX_F~s*-M$0%glGN!3vTy zEth%zhoAk^zWj0cQXFQae=WYA>j)lK*_}W!@Aet>@0ZK&`~O$p|KrA$(yn^pIvksPX$MxVp1uM;FOTgm$MxCPvZ$xZaNl~f3-mjsv7gSUL!E%bIq`Z=mqeXcg7Lbi z#gM076gZ(HZ%2LykxWfjc_eph+1KZ+cB3qJ0X%&}c&z$?v|&*`hfargw@RR-pV>86|u z!S7-}#Z=4}jL>zZ0MAOnydfF9uq604Bw@ZG_164_M9hB@;43ThWken|=c^c?)0TK2 z<8B7%z6~b4k@+L4k>`tVd?q>HSn?w|ms#l35`d#hek9|ri6r==0@r1HEfF|NB6xL)IG>5& zF(m>|OG4gC66S|leI=Rqmo-OQ=(72EBt!R}Y?@E9emEK1k&Nw-IW+=@tgQjmDd3Ar zz9jPzv&SKsH<|)GIV%py$HxdBuMyj41dsId`fTRe8o}q0{7Lo$NX7Qbyc*79PlXRb zDssTH&#PfvS@I|u_m(-^%zsV8_NQU{)8MNje3{e0hfM=7DXUJK_akfGcHhJO>wMRH zJPrD=_*fe&Pg?Pf8now0H|j19(~X=!14jQ;BE6ay#W_VJ~XNJP4UYqxR0Zw`lxidU>l!*{y@7P{SHuEdJDEDxJC5V(a2A)2P6VN->=} zPNz3D($*Do^`ZMa9oIQ;lzErIanmc^-sVfpzw@K+Rl8;EI^ajg?)TjP*2ABwhJNK; z_N+e{TRvPptkVqA;HcX($Yn(pg<&|8+J95tf7R2OwA66u!>(^;(Ocgy`k(oE7B$NM z?!uiB0TjAqW}~<71IYZt57Um03?%R7?+?#?69}HzY?{3*Sz)ZrrZ$=&J&2y|XsCQs z;*LWnmb|xgS1@&SsWNwuO9=F?A>`5cR^RcXEQdOR5$fr3uVrv&`)oB^lI+*JP{`UcfoVCTEAiN@Tn1` zy3m(gsrWp_?MoVcHiAwC6>WF?eFRlfRL+GQB1w}alY%F%efw3W9{x9 zj--;E)TDq&QU*u#Z6`%Py}G*Mv>ru@DB8VSNEA&ESgBurCW?Nj-e|yV>u4I79JruB z>uBn%*~~|i8X7t6f%5mAVp9gxm`hshW7u38m9RuPLv!h+pK)HjzVpDRQ}ouARL80L zq`IT$e>IY3g_>e=gbO!1o^ zQhCvZ4!h~uURC(6@E;debeMZ>A9Yma$yfK2>aulNcL?|IBXq%0Jz_`E_c%ta4o_9A zy-v_%|7wcm`zb1@m^%%*ej5JpXW_T>Behg*;9W03*L;c8t^acUWzynQi(f?!<~8sY zZ;(dgY

5g=+uQ;0_(>?bPJMpnEh`wVm4c0RB>O;9owXuQh_?6VmL&Y@d-PyFU9I zc;rjua{f$=*S{fc_bUB@`{sM}Q9hcUzkHueF!A(-PY3(57>RvL(!lHfgub8-{a15S zo*qAct$<7B&~yLA2E4^w&~@Yi4ww)6X-}M6!_!T2B@nWalQKv{6`n$M}7l+(^2G0)^5)H$m1>02XDpSuMgdIxpv?S zbiivT<_!$)%>Dn3UHEuechmoI_(uOgo)P`I@r}%Uzy3bF)!EJ81kSP7@82(%-S_{m zzW>LKtC+CA!npbzZsxR@_d<-Pe{i#Za5MGZU;`XU+$a89xY-$h9)B-q^6T%y&5ryQ z+$;yTsL+2hgMYS}8NYD`J1kx;l+V>q?3_qvqkX2=)yl1_^~r)4v{K$xKQ}iw*H&PI z!W1k$pk}ZU8E^^ zh8|pR6!qZxVr~IWa?VR*)Ip7ado=`}2fg*O`dp99ugCahbY1*i2e_j< z@XOk$n`%KHf;{nDHBpDb_i;#de9sNIS~cFk&Q*Cm?<<2BSPAb}a^br2L}}JfKXB&XF?U9Ok`w!nUM-3Gv;^?KVw{6Lwys0}d&!DFG9H{@$_p3xBjcbF=jHt8MCjKNp_flI>EBrgmqdb}%Jae`;K9-t zlKFd*2g&&@+4CS72TcZUoD3dJGW7CNugy4fGVsu3;GtRlA(a7gwQ_&g5Dd{&v8&3Q$s z;BjWvbMtr=erKt`(^J9cOvQOlgU@9ed;}y8$=74{y6)_Fk@YIAEN7fDo_bAhtIMe1 zNxO<%p3v^TCk-jQ;#RIj6X?fTwdXb;;6*e0+BbS%-J9I!9PgizYa%@?)>Jq8%|t4d z?6A4+^+{AOZ)YW3ax%Rh^YGiHd#8|B{!3Hq?U+g`E3V*y^d;7b+ezMs)=x*vFU{=kX+iR#oEysp#?DsNvp z&UWJrs#H*QHk?V_Z+j_7qSRe)RMEFfvw&v>P{xOTyJ|cNAlJQLcJ?18amO>NtKTTe zcN9MJ7CD1T4SE+u%gXevnKC4p>TAN`U=lf%^BRwDGWAEvb8P%$eB8Uuq2P^$!JjXT zSg0FDV>CjX%$uC{WcbC(Im1chObTA3M(d0YCzYL+_mK397kcWxid*611`$+E3!IFg zs4kb@mJN+C`NW@7<1Zg5pO0K+cEBo<%xdrYZc8=k(^zM1`N|)BA}QyHdh;J|jHJ6t z+T^usiq5)->iix>DyuZwEs7M9qUxY-%B5uA|0vRI)YGGAh-%B|9!)Fmwk^8KQ~Ega zb1j<6-|5~erS)9;P_@X1r3)n9cv?YYOLm$^Lt6VR>a|wK_wZ1w(Q zxBcbw=iYUS26XFEK4$hAnyv*FoWpv~L(hB>KJk}G0V!X6Tj>f7sG&MXUL_5_Y;hg< z>`maZw`fVtl{@Ps-y!xry$_#;hg4Y$Ab3O?tU2v5o!C}Y8Cg#$NpYvQTl0)KU-Jd{ zn6GGrO0yjJ8or@#ao>H9e%1%@%0B{!G@w5zd{#sbT?z?(1wW5PzLpMko*DbqY&S>0 z*3#5>WxlyJmdgoW8R`4T>&p+lh#l&y0`PGx$aT|zLX0EkD1yGR1J{GwigF#bzc_T) zC82|M((`i$^`nOi>di9fi}-Xb@}_cx>&9b<^}HHiPq-#+kj6xvL@y! zH83v`yi@3}8VNkO8jgDv{#}pCIIk6PzAIqfcIOGR0O^Pn1A#r#5~+C@O|o25V$(> zE~D(&&*`Ww_9H*$2l;S){fox#T{u zIdojYzg34ETJib`K06uUfv21LuAJAG3SSB%_ysB8v8R~oOy=Vx5ig%)s&`qJlL%c? z0_w*E5`BN3=gRqp&@%~Nc=oB4x+&Im#bZ73s7vFaUy3*Jyt$r^M;}GLiuZXt08fygA`K^C+iTUPK$LqD0?D)=uS{jLA^kL%Yst@C%d36 zF~eqi(y_p)=B_O!Q27+Q!vphrkrre5(2G9iQ4IyXsX4jqiIWFTrQI`MtQk0H8g-8;>>n^}I?aC9^XAZcKD1_4@$==5 z_|U~+g@<~z@}(~u1dY3P*_VDPQM=rUK7Qn$W2tTZmww2(@+aT7{ZBMDn?X+%cgEXu zW>7xW#?e9MUKTmv#5#R_vT4s+wj`q4Sa{r|e5_vN54fi$}z9*Cf-|=Yp^)1Vyq`%{xu~koY zA3TR%DCsWMFU+C5VUayvI4C(VN=iuKR^c=_bW&gouW+&pedjb`Z8&ury=`TVtKl@K zt0rJ2kq;A--pbDL3nl+0PBs3Epl$0)WGvboLH;AF4GXyuLCQK0K1h$Ca%o*?RK-Zr zWcA%5>D=rIg}O|Oq$QoyK$zc-J92(V6fIbF`j-*LDEJvhlO_Wn9SuHRG;Jt&soAaf z(WH*l(&BI2<`L(S&Z8-nr>fLP@KWc~_CYST-@l$u z_bQZ7DT~m79cg*JCyF+715%=Gm6|{}~i%hi|c4|8*;h*tmO6?>S z{Y#v`i!?jU8hfaY1_19Rjb3=?2eN&&=X;A62k3_C0$KhrMJQW6`oa<@H9M$yL? z`l9;SkA~>`H)dRKxE^>Pcm?k~fXhNBbqT)k!&@@m<^;t=DW+t~f&%1>dJ~PV9qpxFq{LH7x;tKrtSF zGm2vTJHju(fpNXK!WdtLprf(}&R7uRAHGlT?SRYLfk$Dhe^pLJQ1XK>oEN-{Jbd2m zbK^YZ#CmPOGqwhwI0tZ8EBuZn^kf#`b6CJ1!5rT=L(Zic#;*>%ici3QGQb;1$9*Hs z)Q=T73gd}J_(P z_&;gavCd$^0~u$E2Tmh#LcyD0o`?bWSBV?4UyuQQI|kr(22*aZ&{J_gT;hge`-P4w zcC5+}PXG>RpM3X*>aW;_?mIVJJ=@);sz4}ebJK$VS z=?l;2F9rCp=r>9J0OPzVCZBiSE+g}M+Y@~Lpq_pAOfh4ml3OA5HY*#B))H>q}?i6S4o74*d)r@}PBk=27VI+|(hjR);(Y z9eDm`@M)7gCH9#&!+pmLITdE;OPKL2RHkB;by|`##UqL>U1yRXNo^{nf3b)_#g(ZD`L6K zd}SwmV2jivv0P?+&J`cj&9q!>ERV~fneYyN9{&0M75HQ3?fzZ(qi%vyUy3X9f8OUm zu1^qm@UL*c%ZxvU!(aA)K6>)#I-TIX%Wk>9+xyw!k2ZMfiR1A{;g9Qo&(eQM6)d zH;FpC4a#++?qq6s`=^j;wWROkS8om`uWU4pZc|5#9IdC*sp0*u_pIVWeLLg~Y`xcq zwzpjG*rmBIDd3pmoaajcstw=QezZQUdz*^}Ke~D3i=2f6{AqB;P1JS!?>G~Way{@m{H&jNIs)RvkQ|xjb7S;kD~PU zuFZ}(N0Z9J3+oz9xei~uxHu@9(hK(4y#8o3^;29nyQM~hZ>r?Q+*S#Iihf$z>dpt} zqJKY+1ix{(7Uv>yMxm?Dp#?_IC&dI&L4+4jq9%7zvT*QrnpDmTBzh) zD{0ehCa=i2Gv(#!)mv{kGzB5 zzlZI80K74d#%sYdkLYFrRq*|UtQEApQ`%GTEuWJHpN707Yt1N9@qN@LtZ%4ASx@st zHow5fgfEBD+Iz`r{e z{>}p(ND93(e{-F zj#tLy_oMj-w<`~Pt^#yB6~Q;FjOD8_{_=zHH?PikPdDUUpRC2-@8}LZt`5)t4%TCQ zPr=_b{??90yuK%-*Pb&@O&C`j=z-;%^6$Gf=g*I{08ZJ8x2JX+#+RJiF>Y7A1Nd#7 zu%6D0Ypv_T+h^I0@xV#l8DFf^jNdmj<$33tro4Ph@E#w*Uw$06Cmq|T_&#a4oJAA< zeP2CrQ21BIH|G6(-UxUtaMo)L__$oGkMj%M@nT)xj%(0eJ#y#$hzIX6S8ez_)#C59 ztI5aJy9V&d>Nt*WI6rQ{jiI|5T?M#ZWj;=qMUD_~#{sUGpJ(qoZ%Du9{i>V`^9>u8 zW}ahTXVxVJIsuO>1w66@_=m;WZ=ifJp6}mrguj3Td`F7_M=Z?vUgJX0J=w!2sv!F^ z^)0~X-^UL5OSUFlUgO*L$p?OA9^i_(!4uAf{L7rc?`?4XSwlya1LMVtbz@yEfrD6> za_ZS%#~h!_yi3NTbhy4g;dzol%r{FX#zln>Ln?e`j3&JcUzaH)_-vW^kL>3l{AH!z zyvTiIyh-L-K3TK)gj1{m`G5xa-55-~LgqXFKla`_Fsf^N1Dzy<06`KY!AT&v1rI^i z;O;KPinc{sECdT7xWt`=1a|_#Dems>?iQOUynW94_MF$`m&<*(y}b6e{e$Ub&K%jZ z=givQ`b6VFN<9_lrN*NEhy{;37C4jk$oy_?JNZ7zYm_=H=_4h5=p{}m@lJ_PO1%~9 zoHV>t;*va$@xTw`;R~ekKlym^z<1+;gC?L)lmNb|=HDc7T>jiNo+*~8e)h#Q$)Zuqfhu=XRawc@p59s*5 zeprX^zlK8!(OAmbPZ|!%ISd(bNdDev`L%riFwygTG|@AU(ggP}6X-@w_`bSae*eEE z{%Cjhudp8f8vc0mBwvL@IsU;P|6cf`#LXO!@jQ6BgCBnvZWi@t!p#O;{wsV>)8l3* z!S_<@@BiZ;`F*uJ%~$t-Z1T7K)3?K8BX0f`=2d1mVn^V4a+3VfIHJ6-JiO1NE!F~7g~LoOl_ao_G=Y01vuSQ3isdkxJZua zl&$1~nx91OO#2+M#fOEsk!hZsc2mj;{ISGRudtmn=vlKe4{x+|r~EEumlnU{PRq70 zJNNUbndJF7@W)H09;DhbhIr7#$ldKrRh~tTc@@NO7UfnA8#TYjRWTDhuDH)3j|z&> z;avKDQ0&hm*UY6xAzOw!*PBPpgL73sbuuIV$a>cWG_`M$3dfTc(CU&3Vz`hDo0S0X zMbx4}Qvo?H0^d&ab#x!wTtskt!Vl1sb}R5yq9^TB;JI2}$Pw1~jhy@KMGF)=Mr&`f z?ov`fU0ObM@uTPSJ8$-;IuB!yWP9X|JRToPO<8DZ(Kur+jEO*D{V(_cxAMuLqn5a% zQ+3bOLkE57X*DzdPak~ghaYbB?(ZOSVP=2MUZuMqO}sPfx$`1F`oS@mB8dj?LE|+_ z+);6l+`7k~L?jb?{JHW!`=nZ&A|$>Gmsnyk6-^{MIbe}W-k!e zAo31_5UqjYX7Y-UCvp%IoWYPvIq{e1%B4u`jc8nsospDRs z9=3(btAXlUX{ZWhN7H{;#)#Ue%s?A{R>ncY^Nv1afD7EDPOldB(-^R|I}l8TedP;AoDF zXITRW`w@AJcWW|UHoP|8?*tqUxz{J^0dH%-xSzSyEjI$L))=oh;r+CP?)p}9KK`7R z{Cd~cydG`b7SG!=?$^8{<8Ko?0mnq{b&;+-9=_f9dTzmAJ{&$zJ%Br!Xu50GAvfmZ zo&evm6VCG{aL3;8ecDdomo~)b)&RW0`bON9`GnA)uR`ACdMCzHx7XqEI940uRSUQ; zd^Bxq;`6Ej92UICaPS^)IpTA2#QDN^eqd$Hi%R%=1?Zp4WBp%_$K9zc@XL(3my92k z0zOz0xS)nVs=T<#B`{BmA^)f-{054^-@Op#c|q`=Y=P_9fG=49I`918DdhuyI4|-t zt>Hsu1>e*>;4kF{zc&}YKbH7jovahO<2|H!;VO~1`}Xe{`gns1am z4*MNxKJ?7rjDub`4!D=*lb;@slzvu>_r>9U9uHl3JaQg2zbDq)#zSWt4_r6_zdH#y zUIK7hO;0UzF4@;T0X#m<---R)4bUM--n)idvYuS?bz=Nk^Oa}*X(I5wMDQXL;ct~_ z{5_GlrsP|)&R)|?Grutjc(JCF=G=xP@F%rAOR0}$zu{zDe@6d!>Dwf6QR!#QeA>Fb=S;!)d_BLC@o)`SWgf2P)5JX8RP-5Bjk#`<)d`eJJWo>LiG@O4L@a;7C5u^c!PlLW84fv{t-x|h^KQSnD9F10FJe|hV zy{47VZM2#|5eMrf#oe4h*N>X^zqD~8*)`ARS$nbIKUD6y&eCNPMNd{309yzbC8~H9&jNskq(uJ#U zY-Y@$k;Ug6N-f|{!(F1Yepv5LBJ47DY?GNZum6_W3+~ROj*qf+E*0#d5-8dVn3kciX=VvUVJliiKb@$g7Q33CP1x62EOoNLnmFr^i z6l{dcqdk!~C~_;+;7(0X6;Y?aTE`t;By%aHj!ODBsrKbdHT~3tBRiS}=hD_0Gi!c- zY1{;j-@v(wK4haBYWY&t#y^F+;4l0!X#Jx)(tH!n~ZD)=SPxrLE#)8G@$ z?ZQcMx5}G;DIIf~o-c=W1l|6uet=lV3BJRq*+o7kMN+-PBMvRtzYOz!Irs!CXl|Ru z^;XVYNxfA9&nlenYPz|jTy&!{Yq6eKN9VEz4}Mx{16@1q(f{>}jTF_*{n(?ko9WrW z$m=yfMA7FmiV@jXQf=njM#G1F8%=C&@#ag>9aKq)@!YwSZYlAe6Lyp0?tb>Wz4%`4 zBQ=(E%K@sZ8txy$`s6V9@kihvb&MKRx*GDl*a>|9Pr|S1G_8KwvdS0xbLg*KK)>)3 zRa6NUm(kC&}_-j>rRYaT3<`k4Qc2>c_O@fD!=v zloXfx_LrVPSM~z>t5;;L5;WeRU-J(A%8$f;cc0MriGj~vobmUcbq@w(ehue{NZ-3O z_}s~UjtTS`rl_Z~z<0?Ub(jVE#@X>`iGEKm_;TjqdaAZH@`Lh1ACixKGUpb6PQ(^< zUqR#z6~_9dD6f0Umq1->r!TEspk+z^`-oD|r#Nt(J05wL<;tO-FZmA@p~tFX?60eJ zORs9EtC9bnqbAk|wZKb&kI^moK1DgBUtb@(q=wjD&+DUujZi0JJup%F!8YUb^M~(K z$5zY(sMLn{Q=uJr0Udb%XFBqEWrg2-k1o6}I0)aTrrq^l>(^L4W;{*ezyI`W{$Bl> zZ-;L`eEv0jyZoQf??Cs6&syTz=^y3yrstD?ya-Cto|W#+?hGnUWZ z1ry?H_v-=iyuF-v|J<+tZujdfst>>X{H=6W>dfhw{M&gX?=LD(b$=7C6J|HjtAE!w z;X2}NW5y2`19vRjnDMz?;5{~JggQgd+qKujXOZyOka4{w4Hyp$uFrUAU_CrKr12kB-rHPRe-;6rS_tD) z5WbGK%wy_o104B3#~+z5_jUY{{oO3|j1OjIy*Qb}-|>&f9~rkwfsc4H_-q;RN9jwR z9)Dz>n}$C!UZ~-3>^m5T{!2#wBR5Rqj6U<68yJiAODuSC8t%w?;8?7KVu9~zkGwvL z1)n#3}cK)oxjRUTv`Oh=IFLNA{{VX)!dFGYIQ$Ms98s2;A`0?cP>f)hcP{CR6jYD&YfR2vBJY?6!ZRM&yk;}6UQ>Tk$+6@?Dt9wpQj!s`|tcZ zgR))??G)S1ou>AQ>T3JZ9r=ngiG8U&khA9j9mp);VYBIGc(1$>t2Cddn-vZ{9`k$- zscr6=bAcz#qaW3v$$9iebos9im`^)h+q*tUoKLMCE}bbCkP&wbZE!J1&R&aX()h(D zx85v*&SxJZ^0Me%+-ds@NZJ$B;$PO?Y$Box>fY02h~@f88pb3t|+$o!M@b% zV3tw$&iPWi0t;Ke&frfM>S`i|M6{Jf1^J<<8YdeYDeoRrzJ_k zH(rUIbPAwgrOoad06(n&_^1oNrmznp`5};|r~)<3zlr_WgJ{!7)p(x9m6IBRBV}$yxP^S>8oV{b0GuK1l^B+pp&OZ>!x+SF2LAETREcVJ3hEbG2gNrr@ zr|KIXFFIRlDS56dGj~s(2;_oBApbLxKF(K+o+9aZ$M)OSdo802;%cw;S&ng80Y9Ua z83@}2$^&inc`egKBmj2G%Z%Kf! zNh10(vX7LC`|@Y>WpwDzO1}v+(jQh+nC4f`fbAQ>bBaR^qz+Y!!Z7=m`9<8v4J;W13$Rd!$SC9AieFNUkTk4f0{{jB) zB6mvtol1ot)9mJaJyoE)if_gB^}RNXU%qI^+vn`ad;_OWIBsViw`*N^yB6K>yt_U# zzMvb{y>gxM-{K2;J>_-L037dk@dcwMiuIFRdC4>X?c=w@JqD!km1XW%@@K@;I>zx? z|8~^0XL5AcB>d~`w0HbH{_oq(s|XV_bx8l*^Xh9jnNtqF3OS$t!O8w!I9X=DJBdlZ zy|4VYes^{m_&7Ilyx;Y^bsFQ^QkfVsg1c`*|9PALq8yAW;S?_1%X2@*K_?;5x$iJ3A|6~XNg?zQS}+$ z8(WX@Llugr)) zs`abjKQjL(bN(aqjWqo=`v{aqedmDsv=sZWH7&{GG}IpTrX7!yX9@6bi?cpEtSIok zBFLdE1V6We;4|8CKYo~&Kf}0=^cBd5zIa~tHx07pI_`v(Ue(Q-Sb=Am8@$F`JRUbJ zIbSm{2XxrkIZv}gHt;MhP!DE>51cvpl37r1o1uO;g>KXob-M}bcpdU$u~gzm3B> zCJx7s10O>2Ct|@9iG>ba!wV&TD0SA7=a?D)k#)#>=q5epnH7QB*J@Da5fPWD}l z18$TNe`G#h9QYt{;IqWR|2H1~!P7l9Ct6xU2!WJ_hjR48WTWz<)Kr$*!tkUgJk{UP~f$`iVG?M64?l@%bha^D`5T zzM<)Pl8kd`dT{<6li(wg1mEH$BM#2EcM|Z~B;cgUm^aCo*U9PDyUE5pCDpz-P{Spe zN2=kH_UZ{_&Y%2Nd6%4Ll#2Cx=6RRwV~|RG9jTaisnE%%V%$@Wx+~_pjfYS81bVS% z`I8?8Pb3kZCmhCI=xvQ*Q%_f$M142EYSgH_E7^PR5RUbe>E5|6#eS(Vg}jCwI$EOH zR0{rnQjZ1$rcv;(CPVknoKAJiCR}XT-Hn>~^xAhs@E&vI-!gaLoEfxuLu&PcrQFGJ z*p7;Ehuq22X|UO=K{F|}a4YvQ=336Bf{FySoke$r%Xq)IS=1`7`ut}Bv%%k*LlSpn ze&$^8yXFD!nn#Vx6sl`Ec|Q1c3#jOu$F&O|TtM^Bo!A~ZXdx9-32O@}%I;jxnqiBm z$>|R3raCVsHD2)YViI6hjPDPgRA+I|1szO8F6FwNS$DM7{G6nos?f1t+N`(tMxVnQ z-y3i0HEKjHhxgvbJWBq4`p|@VuQ$%v=tEm-D8Qf(O+PeBQ1E=IZHJzZO@{bVVO7}X zOOqA2^tLbEIk5Heiu`_5zuKE)9ozfSl4XifRYsqt{RwA%bhZ4c#BlT38%Ft)AhS*C zxyGL!ww~})mdF0UqXI}t4G8J2>84aV=$!z{8a_EsV9`J-GQ&kUVg-^azgZnf$-5N8 zqd??71_1{TB1_?(l<-RUIa#U)eg9q~I_D61mBQ`lCzlW!Q@UPl(@!Dv ze3Ihe9}1mYDAiVIb>2(J>g=T_hT372v)8@XbzgJ~JuWJohCHqGcElXbSDy1h zBdDiJ$crQ;4fX2VNOC=#H&40HWfY{yjCwBzZ*K)~*Ol-!TSc}*YM*o{wHi9AHDsXz zuWR8qwI1iQfx39-_};S7Cg_l&sJL+Z@04c?S#Do7=|uUh;4?`uxz@W_>lLv{n_-%B}Ff!IFq6%T+%c@X!d!^o*TLY-7V`xyBvGO4@A ziFv#y>9B1X5rui06!s?_KMNkHmUlU`lcJQmjQ+o%y%3PM*^7$Fq$>?2jG z6zX00ikB;c`W5}}@bai9D*}J4jQ%z96pMrRI8^2@*5GBx2YrB0}u zyYPNJy7G0Hb?3i__s~l}R7d!dK7{`$p6b&36gc690q{kX+ojhX3u9vSzu~|a<#y@u z#+G;?3hXzzUHbJQ@9od~@3+IB9_INg;7{rO70PAjv(D@jlsJ@|<-gu8v-kh6{{7p{ zD?6LN!o2z#u4z|-uR_kJe{juza82dja1r>PyifemxMpT}YD?U$|69k+j5j-=6Mqj} zvCOE%8B>yTnBX#{2#~G;^%(QUGIbL`b~A{OOQ9-w;G@4 z5=Y+u;i~++Zxy~S^UC0FRs^0`0d-}0t^*56y-OL!Q{R;4>wE6NI^{ReU8j`fy3?j4 z=P)?iBfr`X`zyh|jmL@s*DI>$;V%MRbRpEK1-ahrWD9+d4cCF?3g9t6{+as zSu-BE!ixLo2lGH*otyn6-{pj^$PzhDIiMHM4*q5~Bj=r%@^yEYIrcj2 zN5}YU-Y>+s)@SH;)8HQ{{TNc9yG@4wUJ`Ju%>5r#AJ(&)|0CzY#6x!*PrMG%@@8Z% zH1j33JQ&G0l)jA8_fg`F5?^HgTr6~`S`N0%xt5QNw`I(|mb^%bTQUz(!#7zM9g94a zjCdsDahh+X%*$cDt(NbdKEEbCA5!{aW|n)+{Lgscfto&>{RI+`f2Q#wJE}lb0(8C! zz@-w5KEQnZ1gswoz(Wlr*Ncol8^AL)7<0>5pKbsytKpJTw=MHww;hsUwT_(Fx)|NGAl(d;a!Jl?q{xMoS?tJaswTnAhgk0EtC*GYN1r6z78ak6s zuc^LpZzB&Hq#De7AfIp+czLrap9(P8186Sr#gUzc&TK1unN(h$4~?=7 zc~kSU56w&tsQaCbFYRAZt#^xVzBKg5sooa@d`Y!ey5>vj+w+Qi$#zTbe(0$AGpTag zQ+|}!&@=g>xxf`wKYoEL=B<=_*ff8V{!Gk|^9SEAfRwYS{!0KYv?@Nb=#~Jgd1J(i zl`%q39k%^Wm70O{$!%--9xj0-ec}_Q=Z<}59t6Bz<2ADWSi>8~T~0ZEBRrT?_%JOP zJkt?>`ik=wmugQo~edAvYuV|JdNJ5yIO-t=z$~2Mz~R38@r5J*051$s)kD|=!9a!6}6I%gewHaRdi-al?C(8t%e?aE%3H=bgA!Z?|{>S_bA-wUk%tu zZxlPTBAe+%c}2J!MXHU{+%5FJ^rB17>$Z|Avwj{;J?xbkx1GXn+$_Cr=MEbA<#cP` z&b#2#v(1F z#3&*H&QJ~o&UHOUoO5siIO8RXm>2cvmH%brcV49-s`1k`Dwjt=OmEe*uOt0}>+Ke9ugz9iRci%Ov%UK;pf z8O9BT4oCg{sZs%TAo}GkP{%fdu4igB@FA;nJzJ|LKW<08+_etZ;d$!v{@z1({iZ(G zoz{dtzn;(IHR}BO@PA+3l=oi=yvOq`c>Bezc)z3D@P2-7$8~#12h{f+fzNgZ{@I1= z@A$5~KA74ab$d^}Rze~-|&n|~1%{ugl0 zkJbLcIhFZS4s^wyE`Kka)A+k-&-0)haK_*DyXoet|N8Id|9xK!8qDV*?~9q?k{2ib zb~{xUcm??}hZ=Ex5Y~w6kst6_p%LR$_hp|{<2!a%j3I@7LzxS@gIeB<>i=ocfa|_8 z_4#!@@~(S1bA2+lE_5VLsORc{*H@dLzpRD&3Hjm9HK9|ff&M9U*SFyNSO_|le(>Y$ zR2B75Wz=_-fJdUATuSB%l{5C8RiDdUWl)!u#-ju0!tN-gXS}2&&d;8CfL8Xv9g#ni zTpal=#gOw-6#AUP%vYRIi1*XFAnH_G_yO5~&sYFHj#A%~5Ba%yf&W>wQyzOQjh3W9*lh1U^+F@UBFoZkKa@4A6;cInO-)@xWc;p~Ka9kIa+Q zd>^Imn(-se?@{88>?5e*jqF<+3;Zk=`rcUJKQezyd(QZ0Ecl+W&=+d^lX#@$NlKqd ziGT9-#2R(s>i0M)KfieB&f~%V z(|D0GS35lpDfRD};gF1(h*SZ9X5( zM^fgYF>akXPm*=SN$@>P0^Xbi-mT^rU2tiWAAXpJ@7;W|RE-VilSQ`YFF#FQ0DNa5wNYfo*A|i>1CCE~ zUqmXc(Qz?dAFBXqi;X_=QeVyA8!xJ%q*6wEk>ZkhEsHnRP;3{wc$4&TZ~eT>64oel~w3ur-g64P;Zy8_N9u7OuUCL=~q11pL>Zfb(?cHXPt+dAAH_w zrF~uw@uNM4F@gc;2OQRq!iFnIm+)h(y1eJ85gMo7PtS?_F)0Ybrk;a zGrA8r`C9X7Y>?;u`P(A{sdLQhqGnqI>FTGT8K)Bisr#qq&%G&#n&nzGP-wrwmklBj z0xGDM!6e9qzs#B#Owrr-w;X;Zn8JhN2bC)uV)SqPHF|<@un!?YE*v(nLnwHrq15Je z7NIC#0)4*lk8hwLk72ZYeAilyu7-gp9ZpM6`mXq~%u=eLJ6>b>%caN-ji4u8bPI=F zj38k?DhQ~Nq|#Y$Yq+D|p-$pTmIJq4PQrB4>S@FZdK%#oykq)GI^eDtX|AHW*N=^? z>9(2m zVsvBstyJ1oVY)_>FqNNM-g_H(x!Zx??xd3+MkYs>*bUy{9{95VN}N-00DQ)S$d^0> z{@@Y#y&k2BmF-K!{dAlr{9Gj0!^$V=mLi|FIZcrYTv+-n{A15kE`g@s8GaGC;3c}= z{cY8~Wv?KI@+x&#Vp#iYd6)cqa2tH)yYRoiPl`Kguh|djv`}}Cxc`Wb3|0WrC-lSp zpGD&8Q*wWNLO9+(hu`Z<9RD>9R0)r7Nu@{Md=Gy6N9Y1#jDE}9KZ=L{NP;o{jPLu& z(6LKi_GjGZWL;v)yu2}H@MX+`dL}FUva`W=I|uMd*|*J&I?W38o;7qY`QTrlANmm+ z#@&+P-+iSJbRk8cw=RbMt{vA)z3f?svY{mU-43W@OQU`)i#~aI^t~&9S6B(#S4IC^ z%ez$T?@l%N{f9H=U2>mM`l~~Cw5tL7>*6*tMksztHR5`9cw>HkqzNCdZZrP-$>xlU zPHc(uY|ZE8*p_j`M(w$duiud$f9eE<7&6x-0KzZZ|$|ksds5r+W&TVpdfb#{cNV z10yshCXC~pDgKXH|%;cdH zZ<09;*cvfcoxw*A}dtdpZd3zE^Ygv)a(;cT zH`dqVy5y|vzd~=F19eeFCw{#xbl0P5^Kk-eiFqXcI|#k?#~P@Yknhu1^L;$SA_wTjOR;|0vn2cYY_VrN z^R69mNIS+GmlTKJcrnh!K3RnE%L#?SXDkGKu^^AvBOBH)pDDn)?xXop_sV=F>343; zy6Do@dKFLWV+Fi04~~-y=bsa~GM2y@vm+-ro3ZcDxye~^JagpYNPa*T?AHwWIHq`? z32;gi{9VV_v*Qc=n?4(JD(b2LR4R1RDZnF>fhQ#!@gC-ZB^rGJnKx*Fo+|&3O)8pZ*&Ty4gq5}*^;@@u3o*CZ7@X5G~(aSMYW|Xp zCno_n*Yw=!`I7uOYV)7{8nrxdp10D+Ow)C<|L1>>Q)cEn$+)}5o8*2#3Ut3I;3sF! zo8%8Pm9B57vA=4S@xW2WQ=NNTo1`9@K<3phZm$|Kk<1)I^wtYpsG0)ncub;Sjvec? zd!8#D7ytGSnM`Av8aDj6Z3>MJo4)t$jj1%G)6Hg=%%)TMDBY@@McwG9{`#tSce{aK zHG>q?X{yeh-nBl{a^GrqigZ6>S+es?8hj>Ze4)=XsjL#~vCe}^MOJ>%x$i9KW@l58 zy-h_D%53nr=1{(CeMB_jTvBO_cQxLl8Y|LV^LgYL!v)CwTS)8ee-=?Li|E|=!XwuH zx`;j~wt6ELleIz%wDF|szt|*fJEG-RGS1>fQfFPS%gbMnSMjD_j`p6C!_AxO6)IYK z^LcMF7jBGQiuus_!wS*PhbpFQQW90Dux)OS!6v?xy@tw+qonp{U90(Ny6Uuc<(eL} z7kozGjxrxchQ)Mnmtitpd?62&B<1oGQCq5`0GmZY&r?j|M4-V-Q`OwqkD1 z^;$0F_vOmo?$$CG_;)a^YoY|Z1d}jHoL9e92<3lQVMXeS5NcjpVZ4SKb=9i9eXfB^!3rw1KVNjeoGZ!n)*IoRxsqDl zXuJQ`^Hmh~y*|O!u$n$kJwD6KUg)ib+h*RO>nP;B8r*}tp^a2QkU$qCZld^o?7w_m*{J>5y2n=1deoA`HPFDb5(bHCq5PZSu> z>i~WiHQn_|3q@glgdE$h%F(>^G4QF6lL|k2orFKcX;SSOgU&*ieV(=}ahmHcQgJni z<`R4>uaF44)ZI6|Mvi;S3g+W=;C(m2-@c7p&AYgtKLAhkA$e6(kk7}+mwAGI-7~U! zwR5xCi|5o?4Z?hh?O%i6_!fNb59qgi#C<%*=!?QSgLwQ78_;KyIc3R49|+#=3-+Uf zzS#A)OM>Uzn)TwPNbKUAzmHXlE9Z_#r zM}1oZxFvMgf$%MA=7hep)EmKn-L@glQ|3lC;_F`q-IHlku4|_>ow*+E*cJ75H-3F^58$c2_&i!R;`i&}=Opk@)vwy1=W*Dl zNBs@{Lpk_7MG|n@hQN8DyXw#Y+t&xaTaWjD&>7=hm!Iq4J8$pAPXFK6A8J49M{WI~)?JfIF~8QUq@MGZ z>`}Md;d8RX^%mEwby%fhdR32cstA0Q3hTLVSqSr`Am>^>w!!C90J<&YUY^Ov{N4Ni z{`!M`3vyz9St5TaJMy2h=~<^@fptSx=(o)EoHLn)eO1%U;FD^m=lz-D`)Yz5OcVG? z>G1vif`0C2^w-nyJQerb6!=CYL+_D{zHJiv7n<*r^bcacSxx_Q=yYVW9kKE76^f^R zs!@5o(GQ7z%QfDEPW>+qIh(Qg9gIc&sI3RM&eYZo?B5>?pYs?a51iLIF{oFyN7l>4 z7`K=2XP@?1^s8gR1JL*pavdUdS~5SA=ar_<;=X7sc?edj6e`$GFAArz;+xTLS!$G<}xjMM!@xUI!(hpPvB#e-n-VVmv;H&0}zCuRd`^@~Mc$`zf z=ShK|a|*^g1${;>r<48qGxxujdN#Y=fR?O%znzij)jx6|J7_xQhW z*RP4_@>jrPzt*p@8^Bi~=hHv^n!i`ShVMIBbRD@(t~-f*B|O!o_f_qQ7uF2t|B>6d zq~k9SzzY}CZI`}3gO_y?;62OzCAQ;vIXqq8;Lmy&ll`ak=l#3-PhOMtf1du+!(M-d z`(0-Jr);=e%lY$1_n$K3$(NhLqvj$HoXKOMQ^g~Pw$%8K+ZwnYnfi1BrR|>{`}pWY zn(&}n{e);2y0_h9%EjnO)FZpioEisQNsTkPHkq;~TQ(RJH-#Dpj(J(R_%ym0Qeygu zPSa`KlnX6An!8cK{@YGizH*~w-&^?aT08^%KzHhM&iP5oV|Th+sb8g>-ZQEEwhbvK z8hg;E;ZNpnPxLV6Tp!un_vpkyvng1x^bCdO06&`pp59z4D$<`QG4*X}*qb}GX`_AVyQE4NX72T+J=Gcv zoM)lws)I(P^ynU<oY6=4G`3I!Z%B<-ex>D6J4|={cz1FTh9g<^a|Nu^QV2qhs37Re_| z=wL(V@z0`{(EA2`f4N&ej4o|zEF3k%C}mvzp%K-?>Gp=?z9Wx?(?~^jJZLGk=$5bP zJ&On$aeUdUw}T@{gnD1Obt-~B9^GKuq;4dswwTcx?)Y6tC5dMleP^Rw!E!29;JA%@ z(G|3@ZQ{yl_gBylw|e(?*rw%MzsfymSdK8Ew^oI@YbfE;+KNk`ttEAsYptgg^SuM_ zEZczd+eEQHj}%nL&7`9r=A$ zo%#9(b^)%{731BVansly;79i2?IUDvC3N8P;p;S1&-<+jz116neu?;e_B3RCFNcOZ zs(e|&dr*Dc_tgVli=4|sz+oGM_wXa|S-(1b9tUd!pRR?^qZXfk+nS8ey4S#QtMg-W zHQ>b6F#e7_-_}&c`>ODMb(-&!PWjKR0>+~}aO840URhjE89bJT{>uTlW+~pEz9jPy zhS=*FH?rd#%+L~;C&e+oMfL1|Qv|qOVeoSc!oSHDKBYF`M-*VZaBP0$E9K*P?wc2Q zp*8!KKC$BC6|n-Im>asRT)^*h;(L?>xO;Z+BC;{wImiOJPFaC3nnTBx1-Po2(Kmtn z%bM>z>soZ+BkM4JU!Ys~jQ(*NaH>@3l2U+^B?FI40KA~fEE z^m}5wG!8zsaqxYJBgQFXasShDDY-uqORVeCcncC&x*lSK7EpKdi(q3ezMGJd`-}ui}A^YB{2ei^k*r9#5=4ibp>@9z2A2`cHWg?5~m0 zH%jWYcsvaFJu<+L+W=hK0RD@HOY-lN0XS(!|0wn|N(5e;i1A5;51Hm~&!3~lk60$q z?zF3!^CKA7OG5un<3})lE`J|2KPkp_lZ?J+GKX`9e-i!g1l zpXBdDMtqX_F`4IcGG8Yp1O9juzJokJGyW^_qTvI1eUovEzvo}R9sX!H{I9Sc|0@1C zl&?b0r+@IrzZd=}aWj`eJP%%W=EvWKn^{fK|9Nn;0i*s3-_!K{C#xZR)|uVK<@YsW z+`rx~v-kh6{yj7Naqh6+j?=foA0t-saleK?nin!Du-I-qv5t2o(yNX<8@u&y77@;Hx-^_RoH}YhkD>ts7J!%_Dj;^vqM}i|Z_NgV{9nNvBhmqK*AS z8n}^Lo_>3`JrX!%>6caG=FXrggTg92sNqiSel@E<;*mSOZs30<+-D}m-?=ekY;zCr zp*$#3iM`l93wqSq)Gl^$mvIhr=<}z3+p9mCgPi5L)c?b0m(9KBkt!>;olghfhS#rj zbv`NNy4PL{$o_Rh-P(2w$*_4t&GP1pX!WKk0WS_MqG{t^pB^@8F?DtB`Q?S9Cv?A> z&!hFC_jVIjc_F96iy{O{SE#!;ZCPDRB$0U2VMX?9=0igs6gc#yyANd_SvT4DrN8JOB)Y*UE3J$OA`xpp4R!D&|UwaAbVPVOww(I$md6@4Pr4(UtLq7 z_ignjMa^6<)t^=l&9lw4iO^BIkE%LiVE}oApA(73T3!s}R)OTQd+vv$8v<$AwHH5B zOwe@I(Tcm{f*{JHz;QQ%kPjYA%Pe2_c|Ii^qgO z$1Zf%-&v=QE*(n0PEweVq4a)BT%_geP)aGO5LK5zzr2K&Z&rhRX#I;7hDDn-+|jqk zi-KPJ!s-6{?qyOtFQvAN>#dv_zZ8Cn5tO>n(xUNJfj^4W=ktYx&RWHJBWXx#ig;xi z_%O>zVQIRQT23vKT5a!eVma0UE0ho%m$Uknq{69%R?)CZ3bS!F1y?BOe>M9WT<==y zBhblbeb>=q{jZz)N3Ey)=E+UN9X8U34fiHQ?%qTLe|CypUpI=**H#eaEp)JqlBm8F zKAq9@)KEL^mghFQcG{!=>lfRB%k3l;woTeaQ!hsMir>A5di2?H;BEM?w5G@D>PNTi zr=5e8B%p)HX*opu4=I5%M@WqkpLmoe&#WpKkjJsUI6>C66(sQ#?b0g>=rhztiGw+I z4(sWQq{_6rU&8S&WBq)U6cqB#jca({4Xguik>Va1yZ8<%=`qDl-6J&~r_e*>%0D8- z<+0I)$H;SkN@^^2@-uq4#CqkvLoblO{fa&}Nq+a{;2Y|#PPmM|k8(ZEyr(#0-W>DE z4Oj;!8U1Xf-!$X2I^@lm04Fg8-XVEa=IqzK#{#*0*%|i*|cB~pJE57uJ*sb3w&>5A56yfD!jcv*eME$xZ%!=1>xjzz9y z^CrNpn)0~RZ4P|31>8e{^lg`@006`J#C2Tc5|ruO9rIoG}j4 zXTC0=K31mjORf!yi>Xo_#6C1sjxvKaxHB2l(0{cfADrnHDP!98bd^ zReo8n!WgfDn8&v8ak2qFvH;`dT)<6p zLXVZh_&sCXKO1}xEby2WxTiUA$}ISPn!(536uwiYJbztHpyQIbqYk;AU%<=z3_L51 zSYMKA^rx{>g+0meXGj7cPUEXFo?(D~$pF4u0`yu5;Lpbc&x|+XXpB>8yhrIXFLNh9 zu0GzT&b(OYXEdFa)JsYJBIB7c;KjwjZz3ZODe*?;(P^)UOualm=w;cpcWye}U7(0KU7$3s^X zkNbT*N&kNaFca`OCjj5m_^Q$;>fhxJp89QD4IyS=W>Z zd^r)gv*h(_{`JgfO~SlPg03K=Zxrj9G+h?+2><`rWpRFNGI*Vu4;$mWDd3;}=YICz z4mXPcBjeBQ-|;ovtmhIFHY_)eJq-*5Ll zedx|tmihOz;-AoGr=<&@b^39W&*kVwxc=+yF3ooi~3p zjwtc?0iJxEC>-yW-)9uljasolWz9+moX3idj+smc!Z-J-Qe-N%Th{O6i1yRS)AsTs`-RiVFR8_Y6(ii}PJYh? zKUmM8@bC7=58O9{DxWX-Jj+OTD&NQ9UGow%=~JFQt~IaCq#OsXUI?Az!vtmzr(*3S04&Q9-MRi2VbDc;pDp}`9 zuEbO?_*QyTVya_fmu=pprab5JAw`9}XQ&T&Y(8Xj|5?fX`FyGD+&y{pKlsw=0?Hq> z9GR8*$4zeay&nmaMCV1@{AlIv)laIK`O|2DCSLF4PlEJVYjT7?bi@ACPl5aD1wc0& zK(_8hg*02}toKwB&|Dy06lpH?ehj2a72CCLv@?*DwB+VyLG&zimrj>@;&k!Eg#aRp-v#pm0*@clJxc+gnOiie?ki zYk@N=G{i{}v~S^{-7Bv}&~7DOyG|t4IJ%|EsO6DVQH(}`g3E~QD23kIMhUK7j&T+E z!9x2wD!x}*(Mep3aZl;1?VPh6f;WzA+%Z6bFH-$&IzbPM>tTS-X)%KtK&N}t`9 zRY53IC-vy3)pQ;Nt$)__PlEOlre(Mpv7keqy`U$=7-B?g9pVD+S0RA~CZkX?T z3*EH}h`xp|##`bzo%ir<`3T<7C+M4){3c1pb2jzLD^?*>27Fi%mY@Bl+R0W5fKdhqlm#76NWpgz=y& z#ehfJF%Hwx9{5m6;7SgR)69pzcoq2me3U-q6&N49Q3=~acfHBch+;2%e@bY9HBzS~H8|l?LWk6%_`kF8IA7|; z@%nc7S5|BQoUuM|KIp84&ph)Wo%!)}UEqmz8E0;+;g0G$I9iTdE$|E_j$0Gs2fwGg z)xj^U&f_^8_+zvqJ}2nnqpN@?TN(IbC7d7fE)Q$IPkf$bfv=UpV`(0LHwXAVm4eQ= zq+Z2^&e=0gmu$!W0*-djVHd}7ivb5L3f!A7EPs*GxsoR#gB>P)wKK4?lE&c1+zbh7g z|FPgB#%A!X{~8~XbNJ%G%Zvv{e=51=YWO~0S$%kYTR=#tU@OUCyh z8GXt>o)5|Qi4=VP8XuB%=b8K4SJ-%9|8qs}6o=IoMQ{SI|?mBAO1ahl*Ym4>V ziR2ynDC?AIn*Wn-%-dUIgI%e#SKhrlc21^!PM@wVemsSS_shNaL&0fOMk!x=PpAD! zx$@=e>_&s_E>wAt>_)T4xnz5?dIpXA*mk&2Pj{-U258Qt=>8M;#2%eV-P&1=FX84v zS%o{$z527@Z#0XBwsH&Uy<;}~z30FueJ(vJH);H0lX>*xfc04x9MRSvs=ZX_1$59Q zYp%3>n%{hs+Lm8LD&3*~V${W+Bz7X4f;>t0q)^Sc4qnvrvB{7wo4ja?NE6(e(;MF( zZ;CsT?a`&tbLq3;CCVe4cc_z?L}FOfzWUs?Fbi&V)89-6;XaW!Dlj}DJG zv|zux9}N|$hmqGcKY1ZGdRT6fKZPl=j3@ljzYj3_$n*6F(2*Hll?Ipwl4^h7N$?sf z=9{*5X&{wwyIQ9G`#^eiRSB5X{NvU5&)Y#1{bByY=@o-Xgm^AJG9?&wYcL({?_2A& zeF*eBA@nS|zMznV(4~N}q9hNc@&SE%=b9IaT-#9aNHl$w8V_0`jFi;Tf?i>yxF6-o zD%KmP(sDPO5l#hq_)qPTWhrf_t9NYSxs*~xN@lOT5p=9baEs3aB2ec?(4jRe+UxU0 z66c3T(jB2bGCUQ=FiK2j-(}QGH8fgAe!`vp!B5MfUt2*d1-qg_^a?65+iT@86&Y&EINxdLn8pT8FM{5mqbuy0PA#p|g@!!xlD-)|tD_cT#yZ=!8K zD~?W4RP^k} z-Zb8H4|UMz6V!se;4AE-^Ma+){p|sIQoHcMK6ZyljpZDC7`Y)wDCNw1;Xrnbgm|s! zo5#nAPyZy=38(3yNGYhX>?~eCPwFyb%|-ANF3~ix3Tryz3RPE)>#x#hB~~-?I@Sp{ zsiH#v7=D{Xh=8C*+y!suKKApF9`{rR_%U)jp1>#n8L6=YyPxAcUQ!d`PXF`#*CfpG zg>vpKy=qxSNE+Y6r{g2;b20E&k$x!gMjt_5he#idWatf2!FT$M`@ar#zwDQqvA!g$ zIr`7C--HXHxehN>p6gEGPs+ag(Cs)?<>#jzxxUX?9l9;}5Z$VY zdbl?F=uTWG--plY>3ZNXG~n&BfoI@^T&Zb|@jCbqU7B${{j53a`E6l5}-G|Gq=BtqN>7V=X z-|as9f9GD_+{N?41-FaL{5(1y`0aM`?xNxug}`TYCe&NR_){JNe-ZfOaQMu}qK+Bf zfVaC)ANW;$e!q+6_sGX_1|P95<6h&P7^hob2Re7~9&Ky${yKpFI0w4+W61Y0h0kWQ z>Rg8{tOlIek?XNCj=%iplcwad_uYF}v50>FNYI$kA-+^)Q zU8NZByHpaqQG4ba7Pn_V_RjEqEM5XQWij>xXjYW{13ndIz4FFFz}X9;ZnI^4vaSsu zze)k%nfcl8yF zi&*H6W1(A*#kw;V>-t#WYZ-kZC4ZfL;o~sgaYnyP=EcQ<*B1}nOFVJ`GU~4xCyU4D z8V`Id0k~cQe1j8!*Ct?m5-=VK#{4qIe>3_)O8z5Xe?~t@<`aHhcg^@`B5=Ay10N=e$ShN6+8)6s+$v`q8J1z2x<&+;|!{aE0yml=0Mf`=NO+Z%lyhLgPO$&tMXH zyIp#A?vX3C|Jd%zFpDW9n&!y?b*Iw7?-Jg$pE!+dI<8smd2l-XlicW0^!PDRb!N~# z{fvn*uVzrfhvc)pmb%mJ<4f24)N>{+I5s**#R4A0IwTMBP;HK8QSR1?GtzAI`{&Tj z3QBO~9OMVir72C@&U0{`N78TJuHTKSH*+l@_CH@hOVu{`Lb~5e*wPkq*YEmqv@*V_o_Pkmt|pezr=@b74wCY2=(kza-N1a8cs|W(xjzi zE!>P2WsRWIT@{2ef)sUEQmA-dINoZ}`v~+$B1vJV^j#fE8$0E>^fLD{Gw4$h9ZPQPCrfs3l@2-es(5=WRjizpnO48#t z(rp@iqPg7;;Ho=;EA9p_Xb;VgQh@7UalhP83QCtS{vfG#@T(3{{)3a`${skb+)T9CC_+?)lD{)%y(joS81D9_QfKbOHCVOEjvc+fKdvW%}Tx zIDB0p-RK!vj(J|A3eL(qZotp}7KLOh65g-;9q0${(E$a{-1Y$Y`y=eSUQ-mSgM{Di(#4D?}f=+DUhm*mAK z8TAyb=SU;=vG{`e!i4*|^Gvy3(q(}^jycz{Ei8~no*ldfOZai;f^I7h>O(88FWXAp zNj^RMn-qXAjSc&IZzu?VoWhLvg%^dtPI0a;1L4ba$DZpkr&6dh9ngm_gT8oK^pD{O z6fN_SDjWOiYHqT#^ch0`{bdc{khQpuO{>lI?{?%lEp+Dh&#I5Qwjtw(R-rJ3XQnm;9@!8)$p+|yN*-r@)OE7HsR#VeS+5>X55Gru@E#94 z@!xe$*e`gZW5Iu1UyG0bye1!~6du1vowceu__ftg*T{Mdywpuqxxd=C3hJfGz!@u| z{;I(BmTP%zR}SZ27WilxoR`c)ci{K;C!TuTqmE+1^?8HxtHu~ zn9b;W!2WPqfiIea-(fs(>U(f)3r~&w10&)&D9E|x{@!-wH;W%+v_rw|f9+}Ue<-JJWqvRVh zzf!{&SA`z6i~1!7JoOmph-1LtlRmgH#CqNstaG&I?9Uft%BBc}>={SV(`r=vZti#*9QC;Cj{_$lH*q56&sOi)x<)QkwPWW2 zCT%B?YaN^XS%#4nNuiZU`F5J2Kwq^WO8n!dw)R_9yDf`@3yS!Ss zQQddt>y}M$qgt-D^dr{HptLGKo$KDuogSN8uN`4KlYFu~%2Dp>Oxo|LIQ4i?tKnyM z=kGBKJiyuHqy{F=2L3jO6m;m&sJYZAWXo{pdh=*TlQo^AE#`y2H=jy>S0ia?=mHv? zwZfAJ!xqAiXc2f`i>bw_^<#6MTucH)`)-z>Cr#j>LEukbq|zE=G`}a+)_tcp^guo| zv*!20x?bZw^1Shdo<`(cCPfJ6Dqos&Krs&Tqp`|imip1mwo0<5ABphF@pU=~A9+=H zq~%zii1R32ykh|U=)NXJw<3UYTb;f1#1H_yM(`U|AN4?5v}9I;cOL_xLkps-JI}t_ z8Wcn>%|0IRf2-k-ikd1pAQ-x%U=kQ=-_K1#=xm_vfD&OL)ViON2q}E!mDB4ge4G^9 zs;!~mjV^&N(Gp_cel5RpK(7&8#k7d?^W&c5x_;@5sDT z;qxR^WwlKsfp0|;2S!Fx+an*XtCe0xH*6Irt!2=&EhjbZAY?f)k5uTbR2*;xb=p@e zs+;>t`0=lziwcZdWHlZ5w0&4WmNnGAS%rm_v#h1)pqs+kY8`ZW>uGAq4nCWLH-N9X zi8?-Qb-9-BW*YhU>9je^qJZOVp@OOb{8lo**Y9${jnSl}r51a%jUHC^ib$-sgBI@o zQGC=pY0YTG`Dr%^^CY2k+C%FbD$Y;8!e@U!(eb+?xk2-NQsr4GhoK)kN(y^%^v7c~ zMKyvtK@R1niCv$fwF)hC;2HQgor7P+*YU@psu1r6sj-;$w!1#%Z&p}+M8=l2diQXg=?`DE<(v7b|%(RY}Ak)%FC z_J2}PU!c`5s z4(P9{RO7$9ROkBjZVl9@wSZ&RM*S}JMb5za;5+XLJ<|`;PpJ{(q3;`Wz1+1aKVEId zJb=+H(5G(2=WW)8@y5?>xsJE%z<-bK$k+X@6YA(LeBLX&a(!JE_~Wr2{607M&JV~O ze{=({LS09QfBtCvQQ~H9Yk8eC0LS}XxS88DaeZ{ z&-%BcrahCRyJqjd-cEbR-{b$j-Mor8{#Te+U&GBlp5v>K^XVVl?C*t}W!Cpf-2dDA z%75#3XVRaZh@flTJs*8p*%GcE#izoH< z>VDjSJ6a%TW-9dMFP(wsIdgrq1UWNroKSDcx~LB7wA%cbR*Uzmuf=^+ca8VRe773l z3qpS#UJZ4VBi;x6u}W3omz7cHL3cf-BJa0x1+Jfpmq%Z@9O^sShc1oh4tU*xb^C=& zF>dKxlIzvM_QwA9{-uSh-dj-u^<{DRF&0HVTZGS}RAJWRye`Ooi3e=ir*xSO`sW3Z ztDPS{0nlA<$qRhYny*u5jeflqa;>hds^!i|KRo7VCE|UF#6E`x zV?HwLm=lb-%Z#_h8}pkbZpOG)oKbfybEDaZ@9X#@<20JyTE%<&#Q-nU@I;9(GH#{e zk@D}XGuCj+U&kp-Hch|Hx?>IRWF492FDY|xr0;He9X5|+EHR#?<>@ePtL4&gj!8y7 zq#P&4S>wPni32VbhkWWd=-A?*d(N0g!}{TPqYo$hQEK_v(hrjJiZnk+`FZlZ`}c82 z#$65I85+PdGyumlfNy1h-?9NZbOUt$1|zRl{eC)VIY-R%O@zKM5$oPW;B|=@mqhSY zwfq_G10*6}DGBT5jQKO^eIQvcpHXkke#%MEi6_CYC>j2h$ws~~^KO#C^G!D9I58hL z8NA!ClINF(H!|-u1vxq?7;m}0Pa*CzX!+PY?^1yGr_g|&pQrSR8b_0yd-&yb zA5Se7kIUM;-voL-{-}MCmJ{hx@v1A1G;tw89xPs?<0SaYxYD9r_ul65n@p}nv&Qx~ zIfVjG-?46QIgN(D9>3sV&*@}n@OpEPo&tB=W^&Ulo96$-_?&V(q)!Uz1>?f(Gz(_UKINIZHxIQz2H0UO`{f6FEZH2 zn<9=(nPigSZSRc&f;`%%>3E{KzjM ztB6L_a7RTAJ;_Aij4IDFfEHR6A6ayZ&|QnO47Ug*m1fs35PUV^_q1z_or7f%JsQ+Z zSRw^cOwPi|Wp@RU>CX4h*X9;^l`3y8n7qrjy3uxjF#Py4`pAFpdN^;Ma+;5P{z*RL z&OHsK=3DMw{-Na(dTxHR#p+ESOZ@w>_fitS@(-RPXSJNa)#x&wOfU z8eL%-Ma)x(gUjgr+{^bLS_)rzRamd_9)lODtw+)-}F^Rv1qJ=IXA^}w?S2qhE($pQ z7K#Z{f>yWC$wmsZbt`#^^ho;>+h~Up|JrLiKBpa|xb%w;0DkP6?~~%*H23>`T5xTF?8?PLNPsnlFE7+nRZBEj-?FAG`Hu(s&IQiWf z5~6NFVLT5$_(f7*P7zdAmxQ z@4VV~xzb1f?QoNaS9!&kIghQ z{?c9M=Rj}0rXKLMdZ^E2y#v3;7IlHsIq`N+>TsP?u@2WMW29cB7S~saHPJuS@~&0< z@pN^ZS9RXc_uxNncZ5%lBkD5LYi^ZM*Hr=!vLbks<-r#$$H&`M7CP%Pc!VG5CI{v< z9xBCo>32#pp7+^a&$+ku$d9%|Jz4_CF9tnyQLbODi{N;LkONZ?*KNz!)58XJasl41 zZGPyW^MP-P+@(Nk?B5FYuoe4IF3OGmbS~cC4NDv+2jiVTWHo|Wp3HVnc^utnD zWia{yO8koRg0*}U-hUkMmpG$Ni*>=VSjT9%qtrKZUbmK8t?HOuHNGR`I~uR?RT(7# zTI#@Jpl^-=KBPS|Pea>oy1HQcf7m=jf5>$UdYODwUa8cpmV zcI;h2ETE_$*cPjV;uL&CCUW_EV=obUM+ zJ$k<-r?l55O!D=F9+G*S+%AzvDRi2m7f1Bfh#X7d&*ogg1n}Dg%+C^V{1Y(GOF*uc z><4H5mI$3`BKo`&(Z3@5v6)kSIuBC3Pl87>2Tj6pOUCg?hR!G%ye4~pHt&BjbcV^q z`=5e&W(qi23Vh-zc;8cyKbnI1uINeoG?(PhMJo7SDs-AzecG&>O~rYhiX2j@hvapV z?DdeWq{RvP_)(p9YwGN?^QU5NmLvTQ{*>$NPie)IMv$(0!t*5- zBWX?DQZJ7eA4TrR7j7TXWHb$Y=v(gm=rJ^FcK&8Z4~?b$yWPF&=NnJ$G+-G>;a=x+ z-+dlPj&Fay*m~&%T6@~<>5EPiY4_Cu+qc?JqGumGu0>v(M5^1m%aX~YlnXir_niV? z?No|PD6+p%(p31tr{VfD9lUJ@DPlY&v3@4~_|{&DMwk9;)+f(~e^utra~`^qH$OxT za-2u==BP!8l0Vk&7<=GkWyv4&X@a+4IEEsx^^cE~NaEzfmNR3rVGy*Blm+CchiB2Xeg;|jQb{qlE`;d+Z%gUQ*z`r@Fe}#Pj)+Y7&Sf%~* zLARyUU|V4B`}>xXRs&i*oE$ZwUO2A%;pkUfMvmtyZJK&~8QoM$JRkZjCo3-WB$evr zDYt?q)*O}oaPY%QqOjes;)V=l4i9v_gr2-idL!ezhhA}^yh}{BicsOSBDOmrNu_mu$CL# zhRj<<&6PIN_$I4Kbr+wrT|=+pM=J<<4Y`(cKUV(XT1vj62HdZsJGqX(FBuC)Y!%<+v)MW#P6xY4!rJ8 z3jB6e^K!AfkYl+AylyY}+*7Tf549(@TH(Mx$5{^%>{S-nb@+8cizxxqJy^Ga$YcEDy_ed0d(@|U zFIn$j6gtXc@Qsw<-=Dj(p0bKNuOrX*03Q_jKF~k*MGjEi^5BjYF+Qw}@fXIqGrgGO zDLLqzKVKcWklygwpvSSS$XiDad!D*j|0mX49?|J|ej;>_4RL!T9#1xF0)E*Pyb}KF z1udB~E&+c$*_OwX`Jj7j-GRs3(H$}F?#vu=IrNW>yYe{KraNy>LJy3?>)`dEXUM?( zBDN0m&z<hSZ-M!#jw+WdUOYVqq{hwh<5P2Rq-zBo=k;IKY8zBTxGhI>PY zTAjzkrK{t3ihTd7I9^rx{cG#R_mA}C;}cf}9J?~#-WU1@kBZPUl*c@v9Pj7mvdo#o z%3$1G8b3?%_Ae;O{g7)txF6w|JCDC#y1`%NhH-B^X5f&*NXMb4seyr?z zGWqk63Vng>$>jck?DY}s6EtAHB>Vz0FDhKM`}H$GS75-r$pAfv0Xa*eU)q4yPsu22$vuTedEXCs5e#*R?uzoCtsIB$-G3mTkd>b+DnjN4<@%%QHTO?cc~ zQrK02p6%w5CJS>2fnBtqf2&O`zq{T`O3#HRGolgFIN%qQ!KFb*j{WE(ea~_4y zT5!kL+f*a+Qc@{ck;6-=tw*JWyFJ3`{fM%85@&={TC7@N6Hb2qRecq2Hht+@KmP0U zO0T7*x`oTBrN#B@+jcIem&H_P?+W@-3%Zm(Ywc-!D4bFAF-K6yY}F{P{2a7vuUFkj z_?i{|s2m0F*OAmnp^DF&ucRVM>(Ah=D`}u{dx>)H(r?YW!)Q8psKUgLo1&@A-OkMn z%~#QVMP=J7aTRr$c;dJGq@~F8C?d>mAha zrMLf#*E^A~xSLv(i%p(?au51s_E9a57NaLsIRL%lA<}STk;A0bOV&MtzM`YZ**FG0 z><&hFF5-93xGnDbPB;?q;1`!5p51YCwr{0eo}ihHgh|Kd9Rs&&IF9xm3s%Q9D+QXW4mf>TunKl9|D2fe`0s_C@raA0*_m(D5j zi^RHqO@94OwVC_$s>}RsCiIVSI({Cn2DrT;??-wge!gi<@b_lS$qda|kMOi5IALq% zZno|C_j>L5xK2Rt%>9nwbe;L{54+%XpnvSxowr~2C5{ugVq@qu+t-1fQs^S^`@Y)X zhR{7ctA+im1-@64x6898_@po1ZyXm-_^!s*z_e?JmgAzsd>R(vfu) z8ys|;hi;F4SM*)l*ug($i=6oa;HUZ6&qX%qx6A|mLT-Hir0jGtS$${|Mhm26WTu;3R1#e&MJEa2v5+Z7}72vtB}S$5Prt zezJ*I3BMIzFA}kSn}~JvL{t8{@L45hTn~6vI>Dsh=5-4_bP_VhiML0O?T$wtMm&5Z z@!&u4#JNiG@cG0e|2-Z#8uBOeu6Wb>4f|~5^RP}l-gJFszfHX9^@VFPYS;lue&F}50rqsmjw8gvg#xF_$OdHq&|ZEWirp7`CB4!UR74VR%SlQ zTrdea#YxCLO2Y9>GWD49>r3Aj9|x(EU_FZLAK>js1_w+=uD{HU8lf4il94NxjCK1I z9FMGe2|jP6k4xl_@%xp6^CHEh&tcA-g7vmk^iZZkcOdiaMUN)yYb3Yi^HKV`SdWv6 z^EDOgeyQ*mX4Ow**QY7+?oX&VGdL^1htRceByxD8L+!&zs`cr?WjL5Ju zBWOxb$GUM|G6ypE(>mdYhmWF8>5uH3){mwgAxGNlUyq?v;orY)Sz{dKZM<(q$Dr{v zVN2}I0iyzulQ#jr%L$a$!y>Njx`}ji&WNTb`%j`u@2-D2&~q}y_fv&*lgZQm?$F97 zrqCd@o+NlG{K(TtDgRKKW@P`hCI`GdgWi{#bEVe$ncz*cC{4wL9cGhKqO6dzIh4zF z=ZuiFIi!>wD;D3m#5slYXz|A&r2shy`U}~6-LA$jd43%lOmS*`^qpXu_ed4O&8I5W zZ~YLxYCiS-(M_@FhM<=@gk%0LhtTZQHs?oqEui*}u?{2WOaHaVee7-@v3k*_g|y9X z`mLnAvgbM}VYR!{$wj2Lf8TIhOlk_|!m*2KcX-Poo$o9rZ#8zZYACrj$u+OWT$%Uy zby=0nDfy0CJxdsRn3vGU+?Bgr@3VxCmpZlV>X9Yjv(k6n)$H5kJ@nxr(6qK z?>)L-;gQ<$S_YlqGWhCcuk{6URq?3!ua!~jyD=-E^N1j=9=cHkT^wv#k7h?uqAFXx z89@gJjd>SVDv}n@QV&cdIdvGPRJ$lW*FQNgc~gBQZEZI|ty(tut|O{`7<+O`6sc*J zw{t~Ph1M+qQPP z_d428diuTsy7iPcvSVleFX59Sg3X#4A7igS8Dt*E0m zSRcf3Ic(~^&ONh)QU!FBG+E@9W9WxD0bX|!T<|n{y3dkz)cjiJtuM8fC{HMXC_;I63!r$b9d?a_~;FsLs!*b=G$r`Sl^YpejxOp-3 zE4hHjid@pd@KqJU> zA4-S*EDhI1Bd#9?e192CJ%n8~Lr4m4PciW&!J{}gHVOJGnL97?j5OO=@&;E_WA z$a*!YGZg+Oeje$Q;+!Bou4`F+S9~4I-hU8s*FK-c6L6hPfbS>) z-`@#1-ZBTuSp(+@&}IJny_lJ~;xO%tDGB*gvJZf{T@vztWiO`4?cn1neOJuqlEJZ( z;p<3-jy4(kJIN8b7c>PqKPljbQ@)fY};nOw>0qiH2QqpECPy*zcx4P>csOpF%SQToBchxS&SW@2mQbo{t!2F{WEd1$HjTi zvj3b``V;2tG;`#w=I{Be|BBCRM8V&`U)D$dci-~)uK%v3{tD++b{z4t^KZ|a|1?Jw zJibo_ew`S+-XFTI{0n*dk1Om;T2g#C8S^>h>kv1bO8>O}eeeZ8nl#{j?D)O@^tyii za^3fip!DZub&lr)D6Q_+HVc0piE;mEYWjTtf_>kNp%DcxkFB|VEEPEx9??4gc#1V# zYvNZckcyq#|JpnukSgA=K5#x}0`0c(ZFy$sL^?R6LuiWcB&uiCIqC~b*?-NwEK{iB zieE+!9x;_l?29<`ZJTN2pt!4hl#<+W%NW&2JcGt6seDO$XHtujSI(7PGz+~cv+1za zzy}vP&Hkc2en`xxZ}Zy~;B0kvYr)_{bO1vdXh&TsXCm z)OM2o6&8`jiV_MzTtphi)Gs2@Z_T~Li)nIs@6i!Xq12+u#iPspL#e=5-{)C&OX-;z zYt~_@Zy2#oB8+-#!IMhf*xzDP;x!y7aJ%=m7nh1NQD*mx0}UgQaaA{A^o?|ySQ85%o!C!TKr^( zt)#lPPuJOozUS?vh+7py@($84;N+dOUaiNzybHW~4;9F(I+^!U$3RQ~MEo zLF7_fFjv}a3H_Hf{F*tyO>#l^l?VNMHt5yM5B;Pq^kVkxf9>Z0ouni3vkS6ru4y6k z0m9!}(M89(&&641*2xt-#tlAFcldHkLibn-ysZpwM=nsS3eZzlVqM^ZD&Sb2(4ST1 z`$tye#~1d-{?=eV)XNw8zgo<@JcN!AeUf#ddmK`qU*|vraMVWpI!hXZpP_dqwi*BZ zPz(5=TQNty(gu3QcKmvW;lIv@-s_>Acst`e^Xtt1g1KLlZrJV~{5lRj@jP{y7w)M8 z9xU>m>VVHl{;27D6dk0-Asf`@?cP@lzG>voPpiq>{ZJeaU+74EpnI$VonZ~=M4^8S ztIpf~q#AOK;J@~(itQ5mQ!n_BJ;4jB;J8(W-?}37sulQk=9PyYvK;tzS!{n9aMRL! z|GK4cew9Seqz9j$qurVFMY)-BMcJT;e)Xlr!TX9KFTN<}CrvGa=PL}IZz0y{CKoj6 zd0D^Z$hiSe9gt^g4{m7BpOZRv?B^b2i}SMp&g*>GKO5*U^K$Q!O&;VRaS-SpsYGVh6XuCn)1_^df!ECJV7$r&}QxGDkq zJlS)}yi@8H#rl!(Q}gvZ(Zq52{Ye5xl6ms1&rE{OFB$n9(kIQi|B@53&sgdUn`nYe zkrSL^%I#o%yX1YmeNqp|I?hz&-W$-PYQXouUR;d?$L@GE6zi zoD(AQN#7;Pcg>J1XNK=@Gvq;->0HN@y)ysQFe+BZVM)nF!>Q89 zI+bX!AD!y#1P1bY9v^EbnF6DhiLrB`Kh zPNEy{-c~4ZRr;@HPu``h_)nq06+;y3%v2h-uVU#MC8p8$T5!)a@>WvMdtIGQmRgbF z47z+-jX0l4BYXbb$LGgcgwykorxS#H^dRUn z6rDriwX?^s2qynyyBde(n@@4=G$8}^*8-#F)3X7WD&}q%LOl%?FHPF7QA$(E=3RMQu4a^XmSIqa8g7G zO2U0O?NRG8Z->(g|I`87nk=J)I(upl*u9K)DDJ0Y<(Jdb;w_aa-*OtK)(sS1fu7J6 zv}4He?ql*OeyWrGigj)sfxgfP>Z=7|MNqqr=WZ(2G~}8`(zEo|Wg8uiq=SXd&hU3y zNkg>&sFh@{8NHOAOI7CK6GexnwVYdfRTOEPT{N1kwTVwOE$jD%+b?BSQRh1&lxELW z$Nx0bKNy2yIcrYXCWzDsL$rn!-{ zXywPJjwauY6rS3qU(@rWJbnszD z{4R3W419Yquh>g_becg5*AJOHAFQZq246f3U%(OKUdm&*&K;+&XR9hRw3C=$oIj*cfkrpg}i)v~@g*&)@-oy9m1I+Ut z;kxpKF4R^VQJ*3o>KTpGj9I_ny7-d9tF7GOlNw9=?#|5kHsv*$KeSK|(K~Wh(yR&% z`xWz;IOK8Yu?{18R>Znv3i8BK;cpbz^$h6jKN5d`n862P!Fe_@miXNo})eF*Wcw(eot6jQ=9#$XY;|9F{u8sKl!W;8=yn0if7rbu9e?Qy;$FCJX{#qM8F0x8_WAlB|A^1c?JB>2zyI-&zs3K4zVj-g=3n8w`qXu}Y(w4)aX$TX9savr zhpo)ij2ZF%+nU*G*NNMm_`C?fRU^CH`F1^idp~iJVSOk3*Hh|%yUL!+-~8Pg95S*t z#$D*WTw9C%&(5_lZ$<9>Enke&e0ls5;KSpn6E&EN*+~AVji{@ zJmH1c@#4P^z_@G*#%XntKW~Qo`BN1zjw{bx(ytu&U0HtpR%O5kMGsLaaJG`rv%-Hp z&7F0$o87=wU9lam?91L-9D2lJ(03MP-WXa0dc?xudxfAwbOvX10!MVzX?#uZ0DrZE zPScmU*_-sh+Pc_STjUHBKt6naa6%jKgS_xb=YbzP7kF+?_|tR1CvJ^=N-OAxt*~BT z3E#B^#+&BYUUTHC3Lf#%l)s>+&!=?Ez&b`cbYE%ElNn9DRf02#ygk-8iur}~+j3r? z^zriJ62b3;E<4f0;n;^N^?^diEquzCQaUQpin8ZY=pK1HvgeQNSB(chl0U`mf=}}2 zNRQk~Jvf%kmCT$!pPl}Zxsx9ADLv+Y(pSwov;@pk6To#7kQbN$|9e*5qtJ^AKQ$i@ znKv)^B>T8!-oO58Yvm9ofpaB+b0uM&O8Tdnt0g0cQ06_6m^`y>``%h)ABj$SZsc&TND)Z!-ucg4Bkc#6i{m{G)CHpP4>({(g%-f}&QS`8~-c$BkikwpBv{J{& zd{yQ(a_+tX+)wxdWS?c`oJQu-M(|DPZ|3(!=ESpK+i21c^Lb%}U)u=&Ddyp6nD3`S zCz>@Mo_h+?kROnS^Ck_sscBe0O~dCY4cs^l>&a>85lA=jS^nIlgHNZ^xn>8~481#y zPUl)X*lOKy@@e04ScS=cw4m+0p9&B52X7cb(S=;ESj`NeaqIKsJHBlsmAhO{G@E8Bs)eB|=a5YayN>QN=Aw^q9{LW0NQ;SDD*aZ>M}w)` zz#qIzz7M8NYQ1Bx`QT;qDK0ZAsr>2_GYy};B=BQLGD*Vy+=82!G%RbAP510BLIuJqC zRGXA#B=WLkuDr;1>ehbJ4~6Qfv~}jj9~3SIh60?R3~p zRd(#8g)2Ix4X?9{KICsapdCTJNQDS|PwbT5(~$l2m^HI-5hpc^oqL>9}fx z8gdkQ`p3W#PtciP)JUb1@Kv3rlRs4t+^suHDkWcD=R9e+@9T@ieIqh=p09UTkr#g* z-&;3H3G3?F^7Jj*Uq)4C+@aSC)u8)(@L@fm&9{3i%7w?2v{wa+Pmu5Yl=iB%o6Vl% z{r&|xCNIG?U(pP;jx^*AzBk^%Ul50Nlz7uRA@_hJ!e5nybsW(zBJy(6FrLVOzTXVv zH*>6uSn&9)xE1sc*688MiS?G;SZB@)pHx2NT^GQ5uN`uo?2(t_z&?=PPNs32_C0*5 z5d2(4kn7~4<8eRBv2|tW7d$au z_2Tj9TI8P>sLsz94E;l8_^x7oF}|*a_2xQw-g+1Z>v(*By*}Swx*@-QP$M26J2l~P z;%@X_`ZedDrq2Gq5fH9@~!pUaA8>|HzK~_?Mk{elV~LZ>Jq{pRRRdF1a22 zac@suc6vcG9nV+zxSE;$r}cs&KQsoxok7U!6gi%mef@jzhdr6@ms!Vr829Ug+(z+y znRSV$@rTFIKa2atdh&ihrr++rI1YcdpF($;dAt9R?($ESgYdX1zZ2Q(xvTsMxn!XR zzkmJ+jxe~<@89pwcE0`p-k#6LC0*P670#!&q&++$JGv>wZPNgwb= zAB?AJU_9lGbyC@Tsd12*@Lk`kig8j^@Ix-GQx2F13gjJczrAAkS+0e3mh*C=w8h+jy1!$Ui4oI-E#)?X6dF} z2KGH0p`$Yr`*#f{e=FzGWuO1ZoF@tWUWxE!OCK>mUg{o&UXVGO9y&6~8wLLp{%FAs zMIIyTi{de_i3ewk$NVQA{&M+KKb$a9o>d_mbhaOIk z_-)06OzvrblzE)_ z`24v~G6lJpDd1|UnD3`Tzbo?`SudN_m(4kxl4IIvfdsM#laG@Dy-5aeK?C%>2F$w+ z*j}mgO2c`VM(_O(R&N|QjNa5(n{l(vaOyt3rP+sae$;iS)2v61{`7OReo7S4 z2%2lr=*aAH0i@Mhwi`*wiywqcn=*=qwy)$q^UP=(vop%KX|b`id(X-5w~Zf1UpHEL zdE5K(^wibutn-dQa_MCoyu^P3O}H4{`bOP}WHbVe z8%>=;u@jApYWAE;!39Ru*idg8DVgkR9~PO8yqf96dFwOCt3iMw&6`Qvb9SHLwqX|4 z(1cyHY0vy(MJEKzA(ei5_MS@zi>Zx}^GK6b77U`kojR0>m=Q$oK5BAM5cy|Jd=T?f zFljcTC&4sp^>!uEYCb*sQ3Y4?>14r)E(<(EsK|r*Z(Bu%komNBtG+9+fMPv+_X-@l zfG*ut1C16?bMHHi z7rItoMr>PJhFtOGbR_78(rme$zTCL>NOhYPbk$5HUn}UY?^l)TSx10R$y}$x8n{&a zS08pOM>vwItQ{0~?b}FF)0YBvD8CPkGCyFw5_-awq#dRmE8)k9A~g-Z#|VWxsxd;( zqiCNRbM-|u^7^A`ml|)>P4Qb*ep=h>%_@plZBo-$lV)?PzJ^K!UN7C|{Tle2){=&$ zL)THx-l46WX0Ip5MFF}y3pP-t9&ct%-nEfBYCv}rd{JA_cN#+%Yp9I^Tj_o8Za;L$ zvyF5QH*_hTz72ZO9b`DzdVI3SPO>_?`pYLhcTx1IUw<-g-%TnNu32_3xZ6JX{SH7+ zcnG}qFmmvZ(0DCy>?mn933rdtq$;ge=V@{R{SGIwE_a$Hls-Cj%@=3k`;xg&T1?Zo zmudW+x+A-;y+VhMIG65deT|e7%lYTVUq@f%P3S0ZAs^}vT~_Nm_us>H=K=DUA5-j| zjm9s3dP1E&%dc~|{FKgiQiJTDQ;b4$%f9=C&c9cK>|fF|CG~z$&?_3Fk5Ll3-jM6n zLCP+?gMK{@>y+`xx6orfBhl1f#`*CnSpPDZ)=vs+f5;%d&YGb=PxNzJpkL1l;~;DJ zHF9EoI5%{Wd9j|F5B{YBJYI6JgYQa=zZ@`*bz&WOZf9`BLKrs{;c@MG7mU+NKo{1jY|jHe`j)NX$x`J?8WC@uM;_V*1{!Skv^CjkAUlB>>-_hlY? z3O=M$$WwY#kH>#YbUc2%Q6J;HhCF@@X~f5?P!rzXy-oS&$mZDomKe9U=5g?(w$Mkm zfatU`I|VpYrpvY`^iWAJ^t_W zomUZG{T0ruPjR!jA9yds`ScGr`+IS-?AEROfL}KsAh`s`9v{a8>9Xy}-jfal0qR zU6nD8tOQP35$oa=z$wuyWL*yH&1JwHv+_r69X>3jZWx^anxzKg{vJfuC-@9<3l@eQ#1=i0 z8UQK)4w`-cj25rBA{RJiPF@$Ek^{Mx)_h!|tiVMr!8I+wQ!RAN0nJ%|dDe`#ue2F* zBR@hPl>xn8I_4>9;A2MUrHm#&E%(f%B9Ar&93ut&&&kj;Bx9bDg!x4h{+>vpznSwV zr7xNFY6&LYpy+84I>UdLKk~ds_Rw%{pX`|tzjN=0_P9*o3C(}xWW@cPZhA%G}=ZVY_&CDfP z|0ng7VqVMdQwn^4(l7q6_RVDGlbpMlwI`dmHx=h+Dn1{n7Q3aHN6#H||Ej{lB(z5c8s@X?Qpa<7( z6r1(aL|VLl#|iIxlc@N*LkY9&C(~Dl4w$9I%G~+e%eyH_?NceR!kw*l)2ER|{JwEV z22Q6bsy(~&49YoXTp_nQGf7po6(~E44hQ7Om*Fs*ij8QI^UcTEG}3Rb`JFd&C}yK7 zWR$+^ot;z%ZV)}|Xg2%%%R!{7BYQOormNm+Q)4ihd++>lQV~YVZP5$`KC~d$NEADX!|9?H9r?ypYzd@Nrt_xrl+~Kr-jn(U1hh|FCC_(H5~{JL*Hna$!C37 zQO79>=TvJ{`oq<Z4L!U`;g4DnP&o3^!)Z(Ru(*~P;o#)Ukc++yJa#$V9HtqT zmF`UiyLDJWM_lTT8+1+Kk0ILK3lWkOCd|9gN-zKDdpv82Z5NbS7q| zPt|!l=)mUQ$|2ZE38zcg)JfR|zy2Qb3M*e|;dPn&q+vntgLG5HePw<|pXOou&`>o* zAE8YO?K|<|DAtLN)ALEo6~*KU=nzj)k81~1r77~7&LY3*0;N3f8+o((CCXiNd9QNk zE<<;CmC9gZL{`XigiDJe-hw>7wcik zrgb5qBj+5CbojMJeuWwQ)aLMUSR#+c3VAp=u&$aDl=%I&EB_teb1=`D; zai0eKxS)nS4zz5H-XIAuG2o~G^j{xdu9?=L&@c)UkvjLW<5 z{X@I*et*}Ux3lAyyuW>V={_Gfc|7>9z)dpqxX1l|J0Irpqx@I!6W;;9e?R$%zsLW5 zzVpg;#9!gO`V^0gn8bS_&ZmEP+~14GiS?LfKk|8S8eHlRaj`w0=3<}kbJ}O@U*U6_ zoqxH{4Bq+xT)wm8iN5%j6Ic2FG*8TK`$EHiyM5W+@A8)4-cOrn7N`ZjC;DT+7dH!C zqvVaeE?WyaMC3g7s>$P(XXu&v(ieXRcU1f#JfDT`G1gnB9Uq-H_+)h+cg0qNKc*V^ zC-jdmyl^}G*NX*rtYR9kasFB*+^-^!yBsTE+y&qDefX}=mjTCw@A?#c*NQ(z^M5|~ zVBTlu!Q8QwJLfufaO3>M>8?E9om&Dtt~h$FT{zeA>!QpRixt6mvk>~SozZt)5aU88 z=oB59!!CC~4v|=Yw}T(s4*qCctgGkOG5^X3eWnfit3|F+ZuH1x-+#@zz5hFZWWJF- ze`Ft-z&S#$!L__OS0v zZ_2@9{jAKbRLtYYU1Rjnr|C`m$^1&@Ua}8f>Oy%t6Ttrxpih;#k^KH7nsg^T|4c+a zSR!OOIHV4kLdWPZP5uZlJksOs>y5%#wx z(7P6@<9i}q?bP-~iLsNY+U))HcXXKyU+NSxe7CgdHHWD*rs7yd0y&jF#P?E?)~Asg z+UI&_p0XEo&^v%uYEgFDTksM=~X;#^W&G&_GgkNk&d%0jZ!jLbn) z_{7kb8{C3v=i|mof?_bKsdl&Q=hItfHHmOO6>-i#`5W^P(qi66hR|~_)oHHe&U>j% zhzm&PsXCPOK0q=7CF=kOCzO*UT$*j-tPkIa4^P?(6-RWv*i% zRo1s}87b!B?;@%$C#y||Riz`@{L*NDo^mVb*Ul9j#;sdHKd5!1juF((YW3GfxeI>O!+UnlV+g4JjQ7xQ|qDhLH zwEcIA-qFx}XWLUzq}hrqM$=cCtTUQC4moV^WwVMZXhPam=mT91pZaQQzVAEzg&J!p zSe0i!T!VG2wWPKO^zOEfG<@i_o&rX#s@TwF1JzS&PK#|M=7F1N;wJlw`M=)`-QpIi zJ!gkPo@1zub^>pu1`R)2Iak<*9DK!Zt?}y}=>ObF`CEkkkoLtcT5DG5Qbgo#(km$g zF1hwnAq`9KgHQSZS*fzYe1}MdeN8M6Bk%PH{M1MBeRzy)HN*IEO5Atwj11p9)1JyJ(gtZA>;2ov7TeZ`dd1_e?CG#D)MbDI5&QRCDv=L zp+n38-$yQR!aP`4wL#u|eyqpZvQPT97-u=aUk(1)r67;D>B%ZyEc5u`|r>juTzut0y&}EY+4Jt z(^}YW=p3rm!gwD3s>qty|C;cf`-1cO^8I%D@bkF&@a+?kllcUFm$kgHe_7`rTCVp3 z=pNp9@$)zK!Z;nd^TsN?zk4cUeZLYvUwd%mvK4SXmS?^jSC+TuNg3Yn`=#+yaOsjf zo;P^lyz+qW$sM@>Zk(UA%oX#5637)Oj$9=daPp$Ky$E!>h0!PJ%v}9gL7e|i_?$TM z{9?ZYZ~qm0Q<_DuDddeE3}1KzE!M+&Q<7`xJ9QZ;=yzu^jl_8h^J! zKZGTEI4yDfETFG2$KTDc9w73nKjQlF!IZto+S7~WWGB4rxHxpEivvE<8dCRO8=736L4>!%xB{9rXK6X@x=2Qsap{9 z2r)0o{8Rj0tmCjQBOc@Yta=BLQ!jGwg)W1AGIGAe^D#ZfvwB>w^|-$4;X_D39(e+C zcoUE(pMdr81dLO&=0dSwClT|qM66p$pBrEI6EWXO#OuoZdS0iOdI#>&PC^f75?(jS zq@(9~Y7+D?$>^Jwd0#yKO~yPk8T*}#*O&7RUhk1Q2ln-)n9d``WT;ecreK_wg7Zk` zMu~YZ&jVAS3rK~pAZvb<&^L&@e9p0wy_oC|lk<%1dNDPBYqjiqF@>&ybr}ZeXAHh6o}@APqX3G@N&7 z@ZY6Tmh~F=e);p2^s3vxdu874KeX;;J3;p;J^1Il-aQWf)b-BuPmte}-Fj9oT&>0V^SRcu%I@H! zCf3`;>u3JiRIQ77IE;S&I^ga1TZdDwU&gvz2==3ls)ao4r})#2V2@=Jf=5t@dBn`3 zy8|e^stP1WQb^%J6%N)IO#!=_4%#zs47JF8Wc?_^SjuC6?}6p;@zna3Lr>>%fmGs~ zZl3W?C(zwmzPFbann;6MjNCN&{Y07*dgrCr*-2E!(fzUQ`pKl#Co}Z;;fwkJ(koxw$*|aXA|ce&LJ&!(Mk4QGUo}RsYT-qeJ2Nz+M-y)BAAA% zbt-|uq{#@=f=xX$oKvXeK5Bx%5K=UMN+PA?j+|4u06yV`)IOr^^X69<(!2fcsgGJL zqN4j7CEYx{2>fg@1?-*v>+y|?Y4x7)*xTNmoJT_s}W$fl%UyTo= zLVZds+ounsI}L&+*?+f$mZ-6hcb1Ua8hNzUQc~&U-lI#Yr6ybpM;>Z8Ia(VVEibu@ z8d|wDSh!>v_J28bQgKw!ayoOm+wE)lR}d9bn{`%@R@;&@f_^QklFbOR`q<;l+&M~r zjMf7hL7L6Ba3md>b!cMsuOsQDxBraSn<8&dm(ttz+kZ6K{?(|jXc ziOsJxg>IrZnPU$zK=t139^n)Z^&UJVBbA(e@PduBV~DJWI3h^)nkZ;XHl#R#iS;gs=NDX*HUAu3+AH4Y>i= zk>@CV*IJxF%pL5H%zb2C>|^v>KEZtbDfsDg=-Pil&f`n+){1Rj(Kjki4R}K;g`B$P z9rAkPkV6q~%1IIPQO?N_`gxJ7VZi)W(_o`P;4Htan`M%DLT7 z+<1F*9(cZztcz?_8rxYGoTnUoJ{7P|jowQ~Pv%xF#Cm&GURTe+`ute*H5T^a{ko2x z#~7g-sKe|1m+JBB&eq{|>VtPS1dnS3?$?BWu4&5K@m+K9ww8Q*)7JcagW7_Nf0 zzF}*@d2DIgG4VN^S3lpPPX7A!dJo^Bo)4-6y)QinAW>FpGf8j@w&0h zooBw8XyR(@t4T2BAh91ra!1iSDf%e6xJz%!ljmHdc<2LU?vv0tFc*r4&LZni@po~5 z;oIU|@_6LJe>w*$GmjM8&D<;dzRZ8ue-VemU{|YCw*b$T=~XdSh9SW5D_Jf7d-^=d)tp znAAP+I)M?NYa`YpjTk2y(SMhQ{mIH7Z$l?&md$^H7xfF{`As%=``g|8`R3!U5r2jG z_$T?}a^4GZKK;WV|6cr2aI=6Vd>+Kk`$ zrE7hq0%I(Vs(vHH&~!XKPnfx;_z!_JeDU#acHR?c?#N<8PUo0NUP~6fYxr;?ZB7`p zIAh-=QdMSMmQ2PteF}}JCzFkPm5)Z}i{C*MnY5;2ywqNEua(_-J)l_2@ z4~NqCecRSf_YR|leTMiZYzU*{y+gcTyDcHTD)(Hx1bl5NwbhEYm(o}+%%MU7@9Ta! zG@N!Q>6H4{;nY?WKrW-Ms_p&ZGUO00r-mxVyt|xAs~EHU3exQ84^~iNmr`3UdPPv` z;4?$k43D6OTzE|821iaWgP(@4@{GCfz)K(!`i z;!3hV8a2n`=1Owcif*Fl*5NL>3r>qde@hf4-MckmSd(a4;CU^1%f@JG)M`e_QH58L zA|@O^an>r*?AF$+P5F+TGphKjHAD6q+MLfxsnAw>t<_qb4{M=&T}Soa#VLu9>&Ye8 z8H>_`m7GUSD7ujzcH951!LUuxL2RbVHQz7De{&0XZwy6bG_xz*Wh-el(H`5Vy^`L! z!(uxnrm8`Y+u_^aL1r5G-bJcA+pD|6A3tmxt&iD*$L*uMn(=!-O|VkWu!Gd{bk4d< zJO7OP9Y#*#5#%%;LqE-N%$rY8ZLMhM6!eOxq0=~v@%nl6qF|pM3?EFT0i~# z3Kdq=x%&Foz%8#+>d|l3_vv(#*fD(@`Hgo-t7+HY!}dO;=W2}*J%-No33TvJse%XKl^=WpGZ;xts?MoyRd#TUkPwVSNLY!nZxw;0Ou;nJkGB)^Qf}$U7M9>{hkp$ ziG?fkc6)mA{rY*~dBMTl(9am<4V|Blj=vA#LwX4R(nIt~S`+w}j`!yU_+!n6;DL>p z<5g_JuY0*EbJ5`D%+rRqWKK8|xsOq8nXjd_V}4ev13xaPBOj-ao%r>pcVV7Z8ND+J z$bGzn+{ec~`So-30VjlR@u)BOXie}}4!<^Y&h<4*z|1aN26T{jun~Y@C%pY8<4m?7igP^2)rw#gYG%Q~_MN zJosNZyboo;8Oz{jY1W}em0~Wgd?#sK>5K=q!<{*!tvmFLZp`0Cx`N}CzDJ&m?2l;Bl535Kqr-s^^J6_ zv!t1PAH3dUAl6-_g8#|B!~B)DE&Fv%GJG$|rX2GY+5t#1`G8ozmBi6l*SjRL%Uu(pE7_lB}1mDfR zUz3k}8ht))76C;@_PV`4gO24>+^p+Xp4W+a_&?n2@5#+#Ht~7T4}9SdakIET6E}Oj zkN51){W;Cd&6>sVR%gez#OF0)+wb2myT|{x-v0Tn|E@>=3g=aJ9P#q@-<~)BX^tp( ze4kVNIx%>?KXhGjov8bij&(-wty5>+A4bIo>3a;{Hk>9a)at`RKlD%g(@e|Ql#Hb# z=$nOCs~tQZKuUQ=DL;!*w4ha+cQzeI)5W$!Tmp8Eq2yfN4cC_)M>YXreWNyxr`yf! zCs&9Fr1>S{E8HABfxLA;tZmZ)RLdRl5L#Tb59UFr5Ayi#a@mUR% z{nmmz-nVO$w^yQ~fBbGztExj6fg3HNx&_`}y!+E)+V-`F?Upx-Y5&qSwVr<$O2@9L z!oE;CpEqV+o1U^yhVu)TP{86@scp_Lp$V4?cua08^^T=HR8kp^J{8#`qhuy3h1|<% zZr53D%{`aX5EUoJD7r_jaAyU4$1CWiierl_Igab%ueSawf|?a=y79!C2s&FN$#%~B z2-4CRYedr84r+r>Bw5co7S{VhB!#xGxO+zt#ZO(m$(yzPSCX}6$d^4bWv1^dpz9w+ z_wI)-k2xMi)$Ru>TdwrTq!d=1>x$1>%kzvT?d|TkibS7vFFRF%s`ObW&ZyIT-)j1x z;?DYOX!VVtJ*Td&p_=0z^4JYt3%%kx`l8S2*Ih2HqbaIva^ZSvaOt}nFZ*wxep*82 zMmlVzzGIu{SG6|fhs~5QS2ZGUp<=$@D^}td^41E_w}Rtsr6vtj=lV8cJNkAS>)v+$ z=CB=fWpjhGZP)K4XSHVN+Aj1I?V-fS?>9d1-wR*!K5DWcIY;kM**Ej8LIFFJIZRHo zTPVuZBj}Mi3jM(`Qc7MFL-cWM-$~4~PlLyup*^~ZPfvxOgCFn$dSosk7xD_`l~<{r z(mvyT;TrOoZ&2If1^c&7xC!0nZJK&UEt0uQYFl~W?)!9Gp}z}~AJW<{&Q?9X^)Ym! zPoa}|24CEBjhTP$ zYr@;puNnW{y9IA=saCu_K5clrecCY(?bn|7e@h46{`{TzaZ@^jAAZ3<&!BfEtULG~ zavvjl@$WzO;r)w4E_|R5a-4j?^WdZQhQ8C&mtVJlFZiPm_8a{>6~JQ;*MKe&KTmms zYoRZEb9HQIb?88=fzMXu=W9_F?~BOY1P2cA1W&Aj_rEgUUzz(`WzFYXSu6OhE#Vut;C!po<~VQ7p|do@c6@|i_XDnD8OX;;$M0z- z-zVpl7{EEC@0vMG3jCjvJM#Ty?i1^>65)?c#QKlyd1TI$fV>^a?S!vc^h}EWN#U0k zxlNp}A5Y9j&E3 zxL=Bilk?|P=0b4}naqV^|9sY5D8VZ^w>|q@DBfNJbiA@J^FN&nC32iI=Rz^pHzI#5 z`&=mD+s>Rr?^)?}$o;;?K>~&l^iMe#!IeP`mLI6MJ*OsCI#rvC=AI zO7RI)ZOyr_zDk%t`d3>kSzeq-OZ~kr4Bs+|4tc79-ctX-Wf-R($8G1`_H3ibIyB=_YA`NbP&dg!KAu; zoOcIPvze!r#PRtQ>Z}@|=F@1kPO^3goppNni~FGv+BEfe-9_~lAV*>W<;fh9TEL z>K@XR*3W_tOUd%m!D%h$E+rc!{XHL|^Y z(}^<~`5RAIPEKl_q?PQk6n?9all_WyZXH37d=4d_pC3Vr+3CfzyAd?)iN{whN=DMg zS*igjk~sK261tF;q|*c!O3ssW!tf8`dy0)M6gW|X9t2*J<(U>yd9V~Qq9c{?H^1WrydRksm4gA_bb91Q8 z02}GWIdwv}iPYB45?^mdZ{rqHSNGk2jG^GZPJ_NFzLi{58`a~j^rL2|+lF!fc53e! z>o9Wu4w~7m%G9ANcT$)#o3cE+i{5;6QJ#7ay$e%~aC=E#U!C~u!~1Z6mMX5W*k*^Q zq05`6HHsX@dc_gaYB*cS+$ZimK8`%KlhnBBP(y)Nr%0Q&M4X|wYHa@KbI|`>K|X` z>lTkO|9V3H+Qj7|^kNr(B zeV_0;ax&J(QcXR-{JoHlamELHub5%I*4(siT2u?lv%Bu=d^Fm6m2WAG z*GluaY5~ThgUjRjEAsd=tTKN0#CkaT-t!>$DFEYT3(+5saktX@#K*5T=1+AoE+@V{ zUWajL1Iz;&>iB!DF@A4?c}6qb-hv17?K*5_re@5D z_utmcR=Yslj^pzp0GEsGa_8Hn{Puq0>cagxH86hh0T0DbqYsZu6kQ|hm%t;F1ZVW& z@kxLWk9%Cu!?V2xcq6#xVQ+9XZ*br0c;4zdZ99})P0ioMcOt4B%ZgN-~mXK{eLPV+4; zabq3iWmoW5SM(hf$GEf@xMor8UlEu_ISJ< zat3TMelCFVZGQgyuQu>o=jG$~T^{7o=f*fZ7xPowoI2)1Igk@+jrYe2kF!Kxy#>bY zVqL);ISFPM$A2W|P#>Us%K#rr$GS)wIFZqmm(BC1R8yao;6JP%lX^Jja!Ht%B$?(V zoX?(U%1>vWmjEAYf=L(1`Fwh;(@B2E{8i>V3Vox7O`mmc~+J#zf?n77G1dgebe7gFdxcbxWD zBfG4M5KAwVH$`ttQv+_mG36SR}Z%-L5Kd;iwTlj;uOJ=A%*v$+`Jy;Ph$K=lr6LGY1c&B2j*wyz37q>%!(vb6x$Y z>rkgzj~xA}wYH!{zo25R&~ROJ!7fV z#hGho)EiG)ym$XV+W+>}viEf+kW0x%hKU6ylGBD9eFvsYq}cvy^7tg=T~DS+C1q*Y z&MC-kpGwD?9$(OGtH=W~`O{d{nUE>V!>zVX%;lk3ZB4*JF6&J0ZP4&(tC@a-c z|4?;k!Q>ss=F!ckYSCp7l^*?`7fYip46JB94t2X`UQRJ=NIn(K2sd_^!&d zc|W3To&_}G-V}vsE}&B?zO!9O>a+F^SxB1fq2MCgW&1p0a@ZmYQ__l33NNNH`WPh{ zX)*QsdhyzaMMBZn7>f1$FysS;ktUOHmfW$Qy8BK`=|N7{oijp~QpYblC-<}qry3V( zx49A=PKD~ZD-lRap8V!qA9l}|IZsQ^_^1*D>N+g2&)niGXktw@(P{b&{>6{e9Jd`gP>cNIeqkNQ;dhyq*?a z(klv=4YXuyzgo2mZ=|K&cinW(y$Sj6n~|%(g*JX17FwlB3?&v(gScWSq{HQRrRHp< z2P!7*xQ%j_I=>^M!gi{(aJNTz!5tK-+QFQ5(vA}4+>e#tMG8Duc6~Q>Sn9j?QRE)l zeZ@>coBL?dHk%e((yMfSe6yd&7Q0RYQqdn{L~lSkbP^w+^Du)x!5qBJk~!it zE3BjDK%P@BaJM|rJJ>K6^v{o68e90Vu+Hn`VDh7AIV$A}B45WD`P_wh9J{9|^a{n8 zLpr$fIIEo->mZ`tF}^Dau2>3wsWQ+(ltWGs_+ye7w^qUU7XBV<_<#CV1HY_}@mdYj zc$~j?kdJf;y_e7GLYJW9ajvdDkB_G{z&IQHu@7?R6PxhutDEubi~xV^--_4wC$!<` z>C=wK$sz4|{P+O*Pt=LW)%!a0_IE(;d=BBeLht3ZFPV3~?ZvORsE;l?y`b5Bp08;0 z1LdFpv|do;hsGheGYEN|_|+`4uRj%k*pumgnRU!&7QDrMklQGpFS9N&7w-2M`e$*! z*z>&KkMI3<|HX0mv;7ph%go#Thjf<#6LoT?`@iq;=i^6@pYc2K*W!|e9{&FMBRIm~ z$G?BS|NZFy_ul&X&MVi~e}(hvQ(Ur-p7%nWPycYqf4HQ2b?BFekAvWn*pH0Gfl!U&bWbo@`_{Ni=*GmSUO$HZF zhF?D!=V!91PmPa5*4)UQwj< zM88`q^l_=+fT=kDB+txFC#hW*n`WOQ$$oSLW#*ck%V~fg!T|lP0ms`2KAg4RM)XRt zAIFHiqhU1P>Peom*N2f7PqSq>-3f>}F>r++bv$4H@|E@eWLxLZ!2y>?AUAy^ojB2c z?~LxFNLAzw%g8Rf7)O$I%dL$Jehs0_pCPEoX`(1yUs~*nR@#{;B5T zr|Xp*dfQD-Kh2#)z4ZT&y|0d|DqG(N5k*A-v9Jgg3l*^QJ$84Etz(WgwwQxms3;hi zv|xhR-Cfub()g{t-)Eiu9k`75{${Qp=g!O@?m35jcC5Y6KJR+oCn$OU_?e`* z+gu(n3%P@{$#$Rbq5iEj|EGi;0W!-3tac@oDIdQxDOk)saRUqXGN_9l)vyM&6)&!k9jXn6irZz^3~ zN@b5e9`U@h7fouVIIVlp`Fo1c${RU=-Z;)>RMK}|*rQj=NQi~ZIu2e=UDstDKk%KV zzp{0|?%3+RmUH>6kCHUFlDa9d*)SifUGm`1li&GJgm4!UfF&(|d)w^9n^lyfu9CdC zn%;-U`{j7O8u+>9_mtVbi;x_xrS=TW68rM5ql?B0^0_aO7b3isR5m#wEO+@&|G^%Y2dqEIWCUfNE?=K5nI|so7{@U zow40ao9ss}4zkz+JZvj;XWOW9-^elJT*GMc)B^Uk?uJoS)zB=Q`ajHj^h>AhG^Xwp zLA8v)_hSbsF825G?SyZ=hCfzS;o0=~Bjfj)@BHo`e-V+JN6@c23SGc4Qc%FUF~>=j zYqdCu-`7*?M5AUc(3fEp&_T(NByv^xL>!7YAS2c;pC6zI##{KK4gE*FR&NjDW`( z>-hO?0^BY$94Y}UC(unIw_a=N^t(xKQ zEw~PEkKD^fZTR@y+Vba)!2ijv1IDoA_`36Yd!fIYoH73B4qgS< zw|_qVC~-6QM?8P-js5*0+{}4~IBz)04?knHVe}((%Yq(joDdQvZe)im6d z6|PT)1D|YBh3g3$@FydYYc29+)a?q~QROuTOWk@Uu3N$?ay?X5>e^k=&xP;fEZ~oE z$RF>EWk3b4r)FuqN1oq1fzMZ#kFR_g#@ULM#u9q_QZo145p`V&^v{d4K6y$p<|zg_ z06(+`4r`Box*hb*wx~;s=v05a{)Kg{Yb>Nwak3~I;En~*PtVUf=t)}cjLHKWp9lSV zYvv{T=4Kr8loi*JdQ12%TJnCLeMStoIrC)F;f7K7!|%3O#HJ@~M)6!zCk^H_5<9lQ|;H*Gd4N zK@T2=9{e&*cg?z3O-Fp*uc3(O)%3@VgTw-#((HJ&2#He#T6jX|DD40vnN zm@jEKBl~bhgMX18hh%@mXy9$pn9oH6chmO6dT5PL$#`lE^1)-^_Yp(#xEbe)A&Eco zfNH$XwD{xVWBO9v7sukdX#B|k6n|v=FAjdd8vZEpVBT*$G47dhZuZx7*^Kk0*Jbm0 z>!E+v@@g1g)^KaqJtu%CqvdC(^^fH1lYskC%RS=jkq91;#+zh3I1$$)5qidqbF^94 ztnnxLzD@!@oCLfe2{=y@aMC2;>`D0EBtb|2@8gbN(`RRdJM#FZ#~r0Un|Zh?@Jmgf zt1WRynX7$i?$rlTIYxtzIGRS^sMYxC{xLMD*sYeOw~eK`DsVN94w$v~ZvJFE^_ZvA zTR2RhY>#WLIWlG<^-=@&Cee?{al?+bn?hlmE0s3=bt)xf&+$HMEq8LVxZ3`yxa@_eb~3+Tl7A8#)3)A)~GofRYYMU+zosuojNpPe;{ zq5X$USpwhfrPQU;+O_73mI7b%B3m)776mz7gXhv3_^Yp_)xwP`K1uk^t3jOW=)>Z~jmxsF zCm|m0G0S^Bovfx9DEX3tDn@qpCC1TwsmJH~!g^ifJ+}CCAhgLWKT_r7H~eTu+omGw z&>uOV{v^h%X`@TRXI?dM3ZPTTtJ}527r&6~%ZEomT9p+5|(_983+T)mc)q=>}3^&&UlV$gL~&KWaYnvwU{_(mzPx zk2?yAO$xuKw=MkQ3T~njB5k1Cn@wcWt%Qga*i3oU3$TS26+OKB)#a`5UEfCQ6xsfY zFq$V)NAuSYrwfr!603X)r@cXn!PIt|lN_7rZ9oJK?dE;Q&T9v$F!zd`bX>6k+rEnq zK2Z$Ycaw`^n_p=!__q7dzd1l^Tw5&xyQ8G2!ao)`PSsR{c+GcSL7%HN zJdNL{Gt^Cpo$qWu2i)%he3rD_OU|>5#B=W&J$|)JFfgxESN&eWFug&JO1$RATa;aq zM^C&%?bSfed%!1urQ&-(&WXSG5ITcL$PIW*vnF4O=%Rl@iaS>HtY`2kc|mV0>@R7N z;}!JvZ=hp%hn$5EhW?)X-8!!PTpf!u_;heiS0ctk`cMk?XJ=yWv9C%+Y^n+zxWySs5X4dHA=HcASf%#BB7J$CGApCO*qhDK8 zr`FXvJH|nOu?H^dz&Kyy;&@$x*K>#eQ{&R;uOlb1aXHj$6}WzV?+iQ>b+LCv^zAF7 ze+>R(hiY73JJvuQUJKi;1HF+B^?F_KHtRvB)PP^F1pesUn2+~G6V$cMfMd2`T~uT% zKEC;F`1MivKUuWrx_wLsKCZZqs6WAfY}AF%+pZgq54o4sd-3~6dh5O&ZW3kAGwh6c zY~Ldu7nPZhTD{Ny#Xk~1sh0Kk*ZUVA{hxm8+uc`o)_;Zj>T7tMuPvX2yr2HT<9Ixp zfTvvG2)`bL*FWURqJDqo%D;E#*CBZAxs_j^!E0ZWtm^tN<=>m}YqRg&dPa`LwNv+=}?j&EhP-yUB^ z>s@L7+x1xAsQJq<&#*H3rC4sN%sjz!l~KP{<~k>$GWxw(HiphR3I2{gl~4~sXMLn1 z>M|@(y8;Jv<@#oy^xJeno#hN1(;4_=1#v$s{{eq|MxxDak%!Bc;W_+)IZq8F$2;SonOXN*k0C&v={4*zVV{)MW&W^sn z%y}}y_OoLAvjCqpWn8sWX4JbTT%T^uq!Xatb+=c>I_B3IBhT9i04P(p@-hn^xBMf#{%Dtg>E_)x@j#po6jp2^VV44 zt(tzF_a6uSd>rzB;(&w3VZIlK>lFvyPx|~C)yH9?9&~%ss|3MC!SCzU_PHdKbwyuJszp3%Xgefz&IoTCr$wFt?9U#PnZb( zXCjU((ZJtj9$_MU%+l+*`T3M&@G)cDR?D~HJS0um&AC6CuAA?xB-~F)hWR+-s7aW| zr`LDOoO#KI6q9=~!%v1!LNfG@TCO(dv}dgI=Deb0@Lx4Pr1XVmUxXCuKWgy6m3K#x zq6RG!I-1_C88B_!oH11Vx_PL-+gR#eXX(xn(tHsNEE5wERN&flX5>cZ$!%Ume^j(WIydopYy?oomh?eSI2T z_)y6wX4iDuA9;GR&UXeq73k2N#WP8-$a81UqAa%?Z`e9{HpRGaFWuQ~4l%!ME(sIt zT|fRZkA!I3YtF3s#B%Bdq}o5O@t}T7mqdhZSV$6oeDOpvAY2T+t0y%P?tgm|J?UXo z4zJMZTJB}VVPDQQ^IA%ZtKjNFUKF1<&}Kof7Zts~cIUnF-qh58g>Yi`#`90)Tq-t& zr~wdwiSQjywIf4;VUEj2b#l)mf0GhIhx z&s-c~QfEC)JYBlR((~(S+{i*XqssYGe+3R5?@J4+x-R~B)R)2qS#!I&A5Bz)4gJt} z60e0?n^OJ21N8^r&Y!LwO%Yg~Kk%ghQd|pnZwsLFLS>#mS0J78fAzNCh(N0FlgG`r zHv-{{8AJ*j@Q08fy0%^koD3#mLbz|w!eF}Ir1`UVW*exuDu~}e`}Zsq4vr!4#SEdo zB7LA^lTZ>QOsgR=p)^gfYFBUANE3P-?p<~0Ci>Ft?4pIb&D2~KRBxfPw&o(bU@IwZ z{>e_;=&JIu(qXi_q2d@S^w+9yd^o9aa>ebWq?YC}iXfBixAxP62vY8L>nl4*->l2* zYBzVn&wUr|7U*Zw(tAja1DL4!KB_F$@dq&ehu|ZBgz~Eb?W5F34H!5^1LpP>RK?@a z&7YvAf@SzA;Utx^$gwkc!fEKE&qDWnjs_$?70g&I_cDhP@386$xhS@%*CT0_Ss`KN zc#Zh|>)8KITHSH|rY*N`;X2--yh_Yv;60kNK{1^F6}s^#DkJWSUz$7upYbu>5pI%2 z^F77){TZI$FW~$83OL~#iYLN_bLR(x9zg09*ncF>kYC37heU&a1^;f!9IQ{k z-@gElG(tU-3H6H!d}mD2C(WYcK9re`eQUF$-)auMM=tK`ZnK0xwiW!gt+|eRng{hy zKIpa!z%Q~OaL>ZUO>xwj@E7-y`kT^Rw{|Ye_~8Jl5%_tt;aET={(ay7Krx$9$tN^i~hx|KCO9J@9;>JnHarJPu=>us?YnHQklUyBHvS zK1=d>yG#Gi61Z=RvoF%sVyy2^b>Qulb-?{-&wK`7JK*BBc)uw0QAOYjPzd~ng5dYs z@c9)hzw56K^@e&?=3H{0R`Z*ex+|{Fw0fI;zGAT-&2LHi zF-g7y`%J`u@2&9|IA1avyn$%+tD?cfh{k*=+K}JD=cWCfpKscHh41%h@a47r$ax5# zhc*w9ya?7M#b6$w>BhL;jUnk9#k!~%=wxD1hszw}Sj+=s(P!8A5Q-brvn#PU|5()B zap+%ZdMxh$$H6yA(_^uZe;oF!@l)6*K4YKyw0bPo5$Vxa(}RDYhhM)Q{CYj~LVECR z^w0_E@w=_%7DyhA^e<*!hV&6h0M8%+_g4aRbO{)T1nBP)p~p+a{hf%qDG}Er5%qf_ z=0}N`pCuCOm=bY(TD~UFlQdq0^p)cNU&g!$zMsYQYbBdItsd9o`iIG)0gKb z=WQD|hN=`D8h&r!Si0ynBzwPc4E)8qj`?*G_79kDVaaJ(}C?dvfR2qjq13)yE^;$bZR#Fedbh=KO^~% zJw@6^?bWlWX}s(FXUk_3(-P;<_1za3IcqY8f)QQ$^3u!L%=27;b+^=E~txrBadmwn&Cz$Ii{dFRkA6_z5`aVf3Ici?5& zCSIh%kk>TbHRm{bg9o;Z)HuqI%iwdjoSs@_SvSc-^L-57v+?bI2Q6dM8=Lj?p<`L=si9iVCHq~9yi1Q9BDuzw7AtX(UxW{&YVhbs4xbW)gPrPypqdQ&A*=29n~==+jT+%qaA^vw>8o z#qnq>mmuQn7eo#9H;;7677QF&=&a)k3M0l~YI!qc&Y&?HD7$-%NHpC*7QZO(gdiU# zl+Gw;eK?d}XKP-|cj!jyJMmarM)LZgjM8 z?On9BpOO@`n?8J2cDRSeD6-`Ddods0Pbyt8#KTqZY4R71@B285TJ1OUlwYA!j=o0MS1Exv z*Wp)s6F!l*fivDkpW!}yB_F_-H46KCL_tnUQqE&i?L@mjrGR1zLGl^BR%n%*Ur;W^ zesk_C+R;TJSiXTD>pN^W+K|u2{XD5xh{yaxZy7f43YjGfCbfbl1~edA*mw9|u&% zdQx`{Uv}>rjLR(n|1qKt<4IF=jC1aW|6|trjE9bBz{eHWke6PK`TaIc`MkJW*<(=7^pe__7gf(tP&_)|gfUTygE)&+pC=YwB-UM%zQ z_@=<`)XEzCh}_7{v;wce5_&KT_J^vPi~XnWm;)Eg!PmQOcHH;bfH#`q`* z!yDOeKN{x~4O~zAyIf!5klc6C_z-eGQm3WT7?Pt6{UFK9;ODNE$N5Kj5N%XoRU0qv z|HtC|V}ZNH;d;iw7d;OC`Ek%6#o_lM&fx#ge*SUD-HQkRLgTG)KR+HgZan(<@$fT> zhaNzW`$mtxupWE^J@jaL;GcT3!~* zUy^L#Co#V!891tjKXP9n8G4XpLk=D1$)@0YpJMpFr^O#{gD0r|9{h`cBwjSAGS6@R z#VUWxx4s?zXjkj6FdzRa{#b+0Lf%jR;Ey~We;52w;%07D_`F{_^70SiW|p&b-w|KD z9-mRhxS8vB=-*>mosT-Bhq(N{`ZoFf^)mYW|LXf0;g54`{&t+c75?Zuf%oh7l>v9} zqX?%*(S4_$PUcHSQ#KEM&KASRkZPOPXDoTQUOdcZ#5kI7@-p$$>hYB2VAa`1QEv3Q zi{-i0Y7^0Co+?x}QYNY5Kx%DIyYJ7t|l$0^bXei=*~IzLb0}7zRVDY#r6IjHWnOT6 z9&&%@L#Mm|xR3{pG^ry#yNE=nOk`-;#i(;U>4(S0{o8N#q#loYlz&`P^Ll#M4PK@05F;i{`5OdWR`@;cpRlq1@L*Ed zi#47GQ=w^Yg2A|fD!K30O@F+BdNm5ae|2yOWmSdBA>=gW<@A*0p_qqkBoigZ`u#@W zVgh%h(1cfRo8gDJg%WG#F->W(m3p6f-RW}EZK%t`=&DD_mNbQW;eMzYFuv-IR%qC*jMvk4C5l1^Y>15gwj$ z5d4P2;I$k9pW!G?QDn_~HQz@8UYnVfRUpCk12j0rIe;z=wQ9&MktoH!AT2 z{MM()qj?TJ_Y3eZUctBH4S4eJab2R}zY=5M;j@oJJmwd2o+tSo$(aA80w?%HJpV8P zerOE8nM|AmST-~Ks!dtPGA1kha-<$42Y6jMpsxnSyTAly?qy~6=wZKCp;G;U=vvqmDy88V0&A=ZkHe$T$c4I!C zRZW3gHs|fmXvzAYZLJwUHHPn_t{vlSE7~)@mbD}QeMu*NzbbOCjk@xFqq^~a-}b=q z_2%=g-UoVZ7d{R*@I8eulZx9!R0Q7ByK4F}J$v*z!lel8ApV+cOqwjz(O z@R?^n9?kDb#h2E&@bTMY>E{eRzccW>3Vb{j;m=tLeAQx3xISgE)O?@R<11eZcqsH& zEgZpjErH`Gu46u3FJan4^M_|g~D zac+_geCP|{yz_wcIHJTA*;h%!8|7=sgJir&(`7M^ z8ckBqCH2EOMS|B?O9V=1?4=oJf}bB+Hf`J&82 z)cB9g2i5qG>iz#i9Pq#Y9{*A1W-{)o@gJohJ^Q}@`+oGS1Jd#{gIAxh3mcVy`!50a zO9HM(0&vg-=$H}=xHunABKU)e&=n-2uKf4)S29nN`NkUV$k!(cb=ZFocjO#WjrW)q zcl@(>kBp6Q+ zKO0Asczo}^yq_@a?+-m!!oL1o8GqpH&yij2S4o{bjEEAS#`ejz-HK3a!A>! zzxK;Gs(fYgrC+y>r;D3vY%)!7qY2?_< z2xbm3jyIPS^ki(N`E=v*>iHcCEFhC*F&`?H_W(|}kn%3+BapI1RAjMDh{rFB$w&>l z_C(%_mU}HizOPR)T1uzdv=R|DOQ|Xw0a89ib{*kGa}GNSq)PA|6&UimH>vT?{g%;v zC59$`87VG=3uZ2-c20^z;R@t*uR!j}N(!F(phMuXm9%k+LQwRfZIhS3IQpv(*{uvX z{bATD5@bZrsi~`|^zv?9bIx0h9OgC1@m@nBR9YAo3cT^fgX1MmucbKQR@lDtI=Wh8 z<0`w?>rmgXryV0tbe)`CD=lE;5V^uW(#Si%_esoWXrGDy1YAj1N zf7I9hlylxB0Ral#^{-t-v`+v%ZKWWl0aQyRYKpuW)d(|?20P~zk>r7teU@3ZnPq~g zr5acrM3u@HHanXsnC8acyESceFn9st^;*S1Z@JvAtO zBPC2sJU!{gM(S03$FuJ9H<7(6tlvx{yGHwOv)e+gRiXJ-D%06bNTat>p~jm}ZZHa? zg+D6Jj$!m_iW0aJP6JEM2zYuU9KN30=}@3c*Tx+q=%Qe4K6TnbtY_be{PJDEt9QdM za}RCotvE041wUXvsdD$J2dIh)v>u{MLT%sa?P2(79w8xi7m?CO$!(&-Fg%X=!3ppJ zPSVXzinHQr8}>?hNC` zcS(rJ1rzf=^x6+eg?mp&LHG2S-U>9f*`z1n!#<@b;c{Bh|2ZkC+SLZWq(usyv(0Px zR=!1^%zI)UOtgU?#Pi)a_?*P!d=m^j4W2)x0B`(=dF^NLJ&mCIGzPya6Zlb?q3_JX zzBt#j8vL-?=Q;=b;XKTVJUvUD>Sxl;it(JCxq;i{fu1!l^U((9*Qx#|HEh7EEQFlF zBJkO<<-e!cf%oRXxrAGbfj?M+@wN+&jPuMd1-!EimQKv)^9KGn!kO`+F!1n9fy0dk zuTSJUa(|#I<2Zwmd)>Mw<9S_b^Kr}};7&Tmd0gu8{uUs2=5qr+E{{fxA69Lm<0=KY z*RPv1?v~V&@v3}n_&6K1<^9ZS$GFh5_IzGlJM!{%C*IzQAAqwV_qu&|-hOZ7&a~*w z`=8v0$4U5Is`-0&TreKU{kE?N{7L#X0ap}!P|mG{fBd70jPo7T)>qF*R}tHH<#AXd z@l98(@50C3%!U6R3BRY#&cJVhJ4Tep>vC8+VObV9X&D}`J*C0pD~0PW^M)K5ht`+i z^UG5LxMp$I_4g?Te^Lj&ug(B>G__|x(5#)hCf%H4g4PK-b|J~LKIHVxbL z&}WJ<_`tKjm8Of9c%#G_<#UpKrJ~`l9u2-`G;lrbHRGt!@D-0XJZB|7DRE56hm?3E z>u945e)p1>8L!xHImQ70iUE!rW9S=6KPbMwG3YnN;JQdY``2+usl%4O^vzU&RLjMb zIit+Kj6;7q4*j+`@Z#bO*NJ(3@xZ6!p|6iO5&`uF|l)9S9-7edRy zls*N_zfGTm$@gs%_`gZOOOxU6oQ(TCJ>T(O@>KCto(w&^>?eMm@5sMH^7lWz-df_0 z?EjxatBZslid!&>s$aD!Frmw6%Ia8k{^rVKD0OtCXH2QF)W+!KnWfdok>c{cX3%&_ z4R1R2#5Omo({+u@g=`b)&9m{VF1SsiUcEb&y83A{sWF)=rc%(aFZ$Y$8#oq zbf@Rf!crGKnntYmnoiXeTcRT~XqO_B**lXa`Q|OKecvqj-Or}|H%1GJ!W^nB-0XW^ zolEl+`<^HBX!k@Vm~uWnSDk%4=zZ<(qwbeph`#tDx;sjl$Sfvh7I3?sC$$+7?w{qF zCy5Zp>6Q8}A>ZSZ1w~>BSv{QBrNV5@cb@&Pg#Y|t>yn8zy=nU_yR0QHcvCSYUbFi$ z%5>+=ueKkSkuZN3oqtVtC5m$ICjJ@EKMMOa7S2;Xq{_fXXns%ZU$vSZXHk+G*HC+h zc|9A2uOU}aEn7EOO95k*nbKPNAiC&Ve$w(SZ92s?dcI^m{iGTi37u7FjOe`i(#g-; zMUtkbw>ov=xp2VpgMW`7-D-OybK68ee9!!;LZw?j1qS)kmXz+pPJZ^Mm5Qxa*8qyX zKWWd?Jpr^!8E%_EdgWZ2_C-6i+nZh~#2I}}*;7#A5S4xcK zr@Qcv{}s8S58+D|g*?s2bk*oVrfl<{;P>)6Lc_D?f&on@Cr$G@*xd0wzD z8|tAP@U6*-`pS~~-F>Vu-^k7Nm~$TXdpepIdaL~Kf3iV6REX=SRz;9wZp;4mpY6Eb zY~jFquZUu(3rnCLbVNT{`T>>U`gw#C*WEtl!IN-C-H5t4yXMQP_8&7<;dw_$Rjz-B zSLb@RLrw12_pFWm5WgP}{Z-X^yg$$SJboq(QI9ubo<^-ET<4oMLtWpTxA(av*XIS1 zd)cHd*X;}2@o~RukNv`T{zE4ohc(*#L#^|=bjN(8C(lFL^yZ~|AKlmbHJ$?)Pm}oX zKm8gWkH1U5=G)=hy@&9~{I34o2akgr9v2z;&bRUU?RxU*qSiIj zotb|*5xmbDu3X1lhA(`Lij3<`M{cF?!<4>`D$j6hMXozMDso-Y1xuTXT)&)iMZM(8 z>zM=J^wa$2RlWBa7pkU50*64e`=lk z9K1(U_&=5}&OF>s#ef?-a6Ng*o^kb$cBnt?_`Gavf#(%r9B)`*;O2$kGhhQB#R80% zZ^;k5J|B3JdGR_Ac$e0^-_yB)3&QuYuodHpouxm41-6?L{9<$PA#=c=J{xfVuj7xb z4>ds_z=X%At;~@!=DPfm5&T?@P)C1(p7b;HpC7@)OU3IH_yVRFa1ov_BpLkj7)R0a z3mGreaxWQ&i8uJ0^WWnP^A(;~!~&;`h5uZvAs|7kjG&ZpG;=(&#+2Oabu_oHVWdU_m^d6;_e4)xH1>(LL?qmPz8ACq~Y z+Wp1%Ujp#qjQNm!UuDdP9IXQ8iSQLjgkN$ZaJ@w61QMZBPsH&h;`^cbL9%`z3I2&m zxPOx{zfJKc4WB=zlnS8&e_k-kd)p(J7UnL`NAQ?Hdnja+lT7KORlJg%&QR2&- ziA%bTrs7S4Zbw!dLj{)8!+cI-k@Gl?9+-^jb!q5$@-p_FUud@*S-ih=cUb<3q(3-2 zYLCYxsz37d>W}%RQ0!&thKE1aym607t}xS!3=e~K>C@-oc zT#ho2_C}uLGWZ%TqtNwL^M*QWx~qW}J2KVpw1T$xEoQmx%?etw`jJ2qSCTM^7sl(t z=Si?7@&@`)ImLFTistw9di%=Tle@2`%2~~xzl;%imm(!{=gc+K+pF?x`+{q!&iOdu zoW2%#+d8W6IV1OgyX)wqQDBvkqt=s^V&|Sk<2^{dRbczh;-kKF@5I?pxf%+dgDU?L zeos-B8?V0=IHYjZ>Qvt!_?JH^F6%E7{Hg6+ccBampoe*ne(AJ5fPxgdfOQ}#=w$4; zK=hpgX+{O5b00(kGi)*|JctVEEf>DG3nq0lOErJ_;8?{le*?8s;7;QZgU^$aV!ASS zC@Cq6JA*^1K>g~GTkCCv5Bo;iBh*=^S8k#~N(@2A%~a#Uiu}E8w;=Cx3mqN(;nC73 zTS;;47tUF9HMH#dXA{EcLMeqv5>78FkDK>;OE~EYxCuylJ8~!^sKSvtHO4-Rpw_Ao zZU?EcraN}hht0o^^V_?Nl0_cn}eU*u!ugbqySx~Q-p}(3Pc|GRPZNa~$izWKNR^Uycd%N>?uJz>C^T2;N&_|aMU(m>n=PT-bK>YJ(^97}Us55*#J>l0WeLU0Z z`m15RJ!#fU%VXAIz25L`l-oHh08{&x6L)GvG`{#v+Xfr-C=|41BR#N^*!?_ZDp|L(ir?!K~{{a3iJzJ^Qo zUc_f1@27uoNgfaReE(n1P0a{z92CssAaTizo*3MhuE6!iOO5}j>NQ3Fj;e1w=*snu z?8jCE-q-?s$A-Wqg>GA2|C6gu-QN*c^mSdKrx1H~2mZA5QjntANjG zx@*=|JAuCl|IT`4(0?w?{oL-d&s-8XrX%|1B~YgoXZ-F%G47Wa0spbB1J|_+?AZtL zf*pJufkPfG3ZKU!IIhC%lNePHxTg(xxdnhv=7*1BKHg7{yvVuCgL>Cm$Nan8$j`Lm zzI%)%Z?C+}htCC{#+<+%&4E{D2OgS@$J57*b>DNc>X^Tl1v+h0=(wd%f(bsKiLZO9 zOgiQb8e@A#7=I(I_Zj@RPsnNch}^7H@JCYM(~xY)uPUt)+L8>uvdqKOazps|^w3kp zW8M)@oVyo?ypK5WDJ5S*%U6-}8P;*fV15z<-E0i_Y%$=CX*n=5A4ck?CGSz&yNTeFCW6PR z25k;z6oycHgh# zkHZ(Z77`hmwD+N(VBl%K^NMOGTN^LnR9@iwc~hlXmxjE}t@%EkFSlj(iQ3C4|MbG% z&exWM54wW3mQjGr74QRENw;^Eim22ibRFeYXnUF0Q;1Q4%f5b^&-{zfTzhSX`$E^_OGQ7g+T7N{4?Isl z>TmP-hy1(!NVPf2=}+kp&f%s8NK%BgK0>U`+Z;4-#{Cc!#c8o7XGq+ zJpq{9NFV4nu{MX)`@g z(BqmeZ%($^ik#1FRHS1|%dxg$#PrE9_*;d89~({#CvS(Ze*~R6e0k3ZyB$VRlnU&DKmT6%-tNQm=K$S!F<4L%4I5txl5BlBuaRMw~)_?KJT3v-CxwskS*!Kl{I8_OtR_DsHHNhEBl<-g z#ihBAvE3*1X^tY4dq$=z!1)4tz?bmddQEElrrA4EQZfg(`~ZDKwBh%N{U2ohvL5-q z2^fbY==xHSH~kUMt6}c#WCaH)lZ>=sC=w8_BL?e;0GqTe(o@Si%R& z3U!V(_>6f_59LE$m!JEvdu^a6Da5&bcZ;wOPHsEKD_h&6zH|V7Sse9P3C8v6l?2XM z8uhO9e}ayudv$$6UHN_0e>9R0-tNe^?Uy|Tt}}$?&UN1KQ->a=Y6~*@4p*- z=dHWo_<%p&>CVTU4E@!b-oPU>#vk3mtB~`SKO29PxS9JDo+tIj{{9edHsX82&3b$D znf_4yr0|H-yizj+4J?^os7=+C3uPQ`S@p_uiS1%OXe?@hmHdH zqce2a*JU3T^-zE->K#|;G_<9PQ`|?6b_95n6M;Wg#^;|PXJ!uau8T>ZO=sYTQh!nb zIAMA0uN?ZdPS|f*_;;28E?Ne48TgOF_fh3_in@>S6G!kn(T@%&4t%i~c#aP2$LQ+7 z_}g}9dCtI59n8%l$_2YioupKk@9~hn${smdUmo!Cv zo*6i)33N)C;KP~;<75n8rV;c_M&MO`CcaNT0l)eP-c%}l9#X)oNXC342|UImgO48T zof8bW5c3uESU(=Tka+ml#u4)vD2i1LPvku1Xy^^2iFK#iYx(yBW4sDv?i7vV*L2$|pLe3>8!35~l6NWj zkdG!RNP9H!zi8;HK}xblR+o*5m%v11Hz=vQ?jiL_KtUQs^l`t5R*7!CjRF?7Ar*czVtF;wc>piwSa#?h)Bq5B$F z8Bbddw(jUR&5d3j88y@V=>%$eD0h>2Jtk4dxs4w`do`Jclv!}B{QRl3{6hGFO-0@5 zeb4t^0Y=lPR*TfuxORhpnsXP@gJ%whtRohYAWI6R z^kTC4Qs>FBX0C zv`LNOT!lQx)!@~wrh0CQgVP#HeR+M^<=8c3KQ8#ngoSIVv1&N9j)r+QZFK3_Ix32Y^N<%OHl%k{$dNfloElEVJ%*~pJ}Mm6kJca_MsRDI6y~ufjX%%oEs=pF280Mi-yqQ-LEcB4Gf`9 ztGuTVuMkR~>no1%p`^HGCH}AxxYtIq?9t|->xNDAT)BKbH`9ifilA8d%>R&b#Z=X-{cN>hywqirG$^Ws8*Kd#Izn6ukSfY^B-JljrX13w1d z-4H>&FB(s;K5++)9p_rDSR&5%|@Q)S^UnP2VeOj z_>q^{aAZUZZ_?72~e!qs3+9`uLvVY>x*JD+X1zA~12m!iy@tZm23DfaNGci_6UadGHwO6b(O z+r1>-FKy_Xv(HC4{2lzqXz6#3I(vomU$4w~UNG>-F4Y+CD_eu>Nc&n`-_}6xWo;ef zd!y@eU4N(^*O3klcz?bPc^s-E_cFQ(>g{H{y`wGoa}Qd9AK8Z2Kiihq%io^s$f+H8 z`5FFCtAIbY@4|Ji6MW~L;5*-<7q$cZ(d0+nx5G`MLU_iPF&;0dP{4M_X+uc`o+x`mo)z|Pi-~D_R@_zaUkK^(9yWnxMAJZg|&-)B; zsXv5^8O_msKRo8%JNeAM@8^F;e8S#G`RLv7^v(!RtcG7X`H=s!@x+XdZ{_vh9$!Z5 zU3u}_^;8@svK;!S&^uq2d_))EZ!YNbf(JR@74;DO95*39+ehO&s^>3qwV4kIowe}Q zRCzz0<#wG>A3Ad%wU{&dvlW0BYPxIIi8*my6(MuW%b?CHject>;F2ZL*GArXMMvzn z1h!k8``jVL*oX8U@~*8NxPEPG552S7Z&B?wJ4%f@u;(f&^Is0x}d%`&}$b! zo=kqm2krAg2b355#XLIBqp-&L=0@FY#r~$JEYUBwM7^8~dgz?EPC0-hW=EZ!4LnOT z^#8N69;js&&ei$BlyTb;nQ>kw&=+OW@qL;J^|3MPdZ}~zg8Yup(3^gOzu!mbP*aKV zyA2k#fcbI)bcKn) zzY}r1TAnuhYihYRj3>+7w?yEmn!jXPo}~O;EyL$N2Wd-4PEpYYH%#^ zbC!2w$tBXxw6*e1nDR4e}1El!aWDC+LKrJhYDQS-2BYm#qFrm16IpBp$~ zDt(^ZEv!R+cgo}FF`&QTKaMDVrFZ)m)9Cn=r#A!dWsE(@E4y8JbxZ=nfYX? z&@ekMfNz}#%@;0?qx=_AQP??puquOOeCu4m75SqVIBC3tZ@z)M%r31K3C_2?>^qS(-PSxo^7ycfTk zs$8ro9NyPZci}=m$w~M;nt0wlaaPN@l)T5hsvvefDeCCH#e6Ag#MzM>#`seI5#9%C zoc5(`N{nV9KPo6(_t%f~qcZLK47ESwN25fVWvs0~IX)aZy6;4PYN7&E{-naGl>=yi z7@aH2wS3F-_Y{NuK=M1(Ur;pz>FL42{f|`$BJVqPULI?L=;ivT9~#M{^gz)$Kdy_`Og2M z5)V(p2lF&3s`CBI&(Nu1N&@IP>T$o3K$tHeck&`$U!jGi-sL>x90|SjRf<|;6?E|E zHJs-S%BKcu-Xztwe#~vUCD@Y<8{b7A<39QCsG4-F-verRJ6bR$qo4+ku~xF^XOFm z{nC8c4}82U7DWA382#mPDtIKudGx*OpZ@~5A z`G#EY4Qvct61kV3nxTGf!N*a!HR|m)JdSVM^7+(3?&XFKd^}}30axtI_3Ui$9|v?p zecJ=?1Alzgn_oNrhzxLh?@GJ1_XCtp6&HaW2Q>Io1i=Da+%$t_;SfH1GFx zDIT}`xZWv_JT5kle4T5Tz<3mAKL9WIKAm;|zU{#C4V^vr|7Y9ryusfVxd%ltA1jP} zg+hGaPbi3b--gGld;#n?Kllpy_`c2!|9RUy;0Ig7XFfOIC$p@;r?7;dlm&EGxsY#} zlh?nK13psO!FR}J;2pDHO;*-(Q5K#jH8ll)A~W<^CVaj3WWxCv!^gmwb7vPC!B^o6 z_zs_;|M`SI`bY2@QsMWVg8DBRbz~BF42kIDCt{wG0KJYLIu9-Pl6|`4(a(=VeHn*3 zC>C{UEan5Tc)rD;UW>teNUPVSo=N6UO5TCwJ;-?h`!8$yDy~Ddc?Q>Yl0U93`FNx8 z{MP0nk`EzuTxs=KQuif!7+>Q-$b3xhr^le)j=_9T<3W^D12q409t8KtW8t$A3qDFL zp7*f^{Tts`ak%bUPA2CF#G(JE`9nz^9qTCL(RYi-{4pN)O}rs@fahiL247;nZtehydL+H9(f6R!~FM#aQk;L)AU(L(=BRMM3w=xJLSaCBFXh0OMfk*Z6zB^X>XIzQ=jwzi%A)YyBF# zD|{C6e)^|h!{hOH>DNgAo;L8?F@t-w^wCMHtN8)zIj31KEf2ak*7Jqyi`-t?zR)17 z7rlYUU9OjO5cg%8KE(I>RFi$Lw8#C2`d)43=)Rx6SJYX)BH#D(E~9>y8J^bi{`pq@ ztWs}z)MUR+?mz9)XJ(EGnX8VX+vPI#onkVYUMh0aUq{pZJtsfjzcPm2ciUpU;>lRL zH~6N_!~ElEuwTDXg9o}Hr(*(r{FoTEv-u>N8K0+mgZqBIk8=g>~Z` z>e+Wi$b*7&X<(n$H9uCKM+zIVbEo-K?(&TN5#tuniSbGzjt6og7m|Wv)k<7Mt{t7r zgj#!&5bY`fm!#7B>Mx;lN{q{cB^2Ez&r9nGODUg9nDnC1IfKSz4fmqUBGe?jxi{(k za=h;L+?(b$UsN+_#xnREE=MlTa=KntQ8o*`wE|nltw8?bO0pAsFIwJ*B6cc)IzDu# zo?_g%iiWBL!qxO;*)qo<-_^8~6obMwwA54~Sc;`U*A7ovOG}qTgl#CYj=Va*DByWe z<2_bg^uvPI#=aD|u$Z9!37(^HT^tweOK(C3PY+2I`7`b4=Q8d5DCZ~Z?wdpWXu)xx zUKfr1;e+T;ebhh~f7(0u!->uL1L&8)x#pYPG`;mx!D@U)fuzcRLjs{64x+8OopKGF z8bs%td9}OpE{HtJWv*VTPcZFsa;#!|E0{cPDuFf|==_@U3+7$iK+jeW8{VR|$d^&t zP1i$6S@~VBP!S#l!{~%^n$yF9vu>x7YEa8|s;CObBXB);P_jr1N+`CIGQaQ; z2;VLegLJf#`EKwu_fTKqI@+v*(kvp2?>x*60`Kg{~wY<9*%*INxtlLEt8ZfzK3$PmdkEj6S};B5<$Dz$dFRUU#_~_EQ7PTD+Zebr@eR^K;n7zB?kM@7z-8CCfR`!r zL6K`|1>8~S*17-c0$kSx=PiBhU3k2N&ykxFmy(ykIh(*8vpaz& zQ5JY9_z!I*u3U=8VSY(m7e|ao3E*tS`S^<#XFRZ7F~;ZSIWXRM3VD}i_Iw|lPd_8Yirj_+Fz;EmaJ+>gu#eBTV)&4S~}qGNrCDYlat`;oa(vX5Yl&l|J; ztEUnC622JnZ}~Vs8FF#irzaIUn-uV*li{nA1bt8<^fa2@g>@%-1D?eGOY!ipkH_;! z^L=7mMAHv3K_J$kJCeKy#>Zly+lc{RI~sUsv>}H}>Z~NsLE?z=dCAYKXz=Ev!6Qh& zpa3UedQC4!W?f^C48&?V;um#X6#R_#pgvnD?UjM)CcVV8GKQuSe<& zWzHtoQ5oZsd_BL;k6^u9dVU1^ZzX~+l-}>2@zo?lt~K*KGS+P|PM(DCNfLCGNrrv` zpH~vt*!$|JC<1!XM|}`t3MTeoN zI~V*EJZbG1a;$OQsb2V4+EII=pe~N1Sv~U9j&^aQqC>;)4O}*X9*jAkE5>3H@W9EW zsFABRn@Z2U@*clo>`vKQO|hHs!kvou-I@H$jcHW*+QC+@&rhd?EAPB;IX8oB{Ub%9 zv6eq0_1A)|c5;K!Tq@qM-w!7X&7-VJOmwaJ;LR;SKC%b;ybCF8b0v|Ky@;l&hK`<8 zRiJ}a{XD71qaNiS*IYs~6#C-LB@~*f1i37wOLMP2h|1wbGWVKsAa5%8Q|N&rkGz4u zEu*>zw)P4uByh+6E`ln#oMi3{>s~eAN9M2j0GAcZl>w(e3|mFQ3{pg}#>?qThRW{#x2$TiW4xnRR5Z3YfLL8O0Uxd=8Oot;Fi|@}-K3 zi)Dl_)jwJ77whbP)IlX2`q9jxdK@Oc~-QsBkU{&a4rBINd`E{dGFTmUJq zesPNeNR8Wx3xH2znD)nZ zS(kPE2Izk`(C!}<=3fZ%fRc3ZI^jFPH+y0bV> zIK}Q9xIA-+SWa5~`EBFvq@>$4jo(hShV1S!Xln%JO8V$5H10HiT;6t5+wCOPPP5J~ z_(<-iVPDP(WOWajszlkn;7#m9Ui1M{<<9F4g8z4zRQdHUN2s!Duy~YusKWPS@LxPm z50v=uYbTITb&7_lLDr|~iAb^OW_Omh3H9{4i|0r=+qdg3fERR$wt4rT+qcIR3Rqf0 zK$wwqSEPLpJ9(8nmG~Lk>m*D;54Kx=1AfT2NQ7M{jE%YtJp3;85^3Y7_uZ$#D)ILL z@W?3mL_VUeyOay_gl?Wx2$)YXzR$s9d`ZbJ%9*~R^-6sC^Eb%3d5`&BG<+vwFmI6h zg?RXN=neUF%+;U|*~xJM4)9y!5F zv@rNru8@GhebwUg%-+A)lrI{JaYSk1PzGcTxE9*uf9dp7D}u$h{UBSF9I+ z?@vle;83N3LzZP;-J^1h$5;XXY6f233h*C|D(Te6uX|{4*;I8S!=b;jaK?F8zIagZl(L?j!K1RNxyac+Mt+*Yg?`#3%BDDg|lmy|rpw0ua(yOcak=}Ry5VVuVpjlNg3K}U9WoZ?8H z-VciLDUAooymXBRX{7!a3w%`Lk1`$_3mh#LcvCEReX;Q2NbgI(?!$&t&8x;iKNpAJ z3oR#;eevU<2aCh+N1TCo&%WyM;El$EpO@aBo^eo3kHtDVO^?Mnk9zo~OCG--{WCrM z(zX0d)~RX!P~2D3gGZ~!eVs8Ml6kV}`H;-p{JJiS?{}#)NW^g`f(M*v@JVCbG!eRk z^#1j%H%yO|@o)`yWIQzqbyX7ZXbpGd{MID;cDR`@7#ZL9eEe&; z*$=OHJ}Kwn|KMgk9)CC7EbJMd_aNX4e+V}Vn=9%jc}MXRKkdKY?t2;)%V+j|e^1lm zW=&r5QKua@`C5*y@9W=RPpPV&Rp`*WZkz8kcXc7+TAXK74sH zGh4s}8fF{2e3R`Yy3~4PVYi)=DQS4zsiu9Vl9|JTN-??IsrtLp)k`M0la);;5%n>R z76(}f$G_>wo1Q^G9y(x@`cmURa-B7YstYxDVY|6hSPjUY2R`9^TE5*}P|_BV3Wx3T z0B*97tcngR9G-76l`pI?=RB2glY%Xdd(w+`-8&}qSV9v&K2VacNl^vQUAYuGWH0i~ zt1$7j+-sRTQ>l5T>({q0BPA6^06O^)$FPWLM4 zj5Xc$Yqtx!{vTHZe_BH)YcH=ertVrC|5}<*^Vm;E7p$WWHGU9K+dMYh~tPa~_v zZK|&Gg^t&kgcw=`gKIh0T?9MQd7a=tD)GrlepI3D!OCGB{b^2{paB*;{K4}KpxkqB z>2r+Jc#myeER&hu08GlP&<5=3>^pYaMDB66;s z6a{iHZS8lukzLOXR9p>I-T+=;2suaJpS0&`2%Wh)r+moIp)_LhJD(E9BHy~FVuZPo z4hXffkj~R`g$8%@ax)=U zCNuP)robh$GEOug8}yzzz?aMk{+0!B5G(fmo}8Pv`_@{g`UH>93%n&ia`y@Vk1UAS zg&B7%WeZ%&4tSmee71{$?^ql-kt1-XQow1XPq`C#ZRPp+8anILdchsIStNXmYF7eY z3IE3dRe=Lm2d+~Scvfxbw2A+I3jD_`^?>I9e>~rSal(#`c>kZEzdqI!e7)wtC0p`- zAGc=Qv~XKK{+{iCr?uz(m+8p3-R@3&-o24~?bwyKW8Iz4%MQ8MrJ=j-)Q531pC56( zO7V7XX}RF6t1gfIRRBIH^D)6&d;{DzJH}1u*Hv6HtHyI=JW`IYGsX#c<1O$kh2EOy z-Q~f%)cocbAJdoWZlUE}vj21$T(8m?H<@c*lE+u?i0kbL99r{zQgNJZ#dNBV%}WPd zPY2{$+Cx`u$J-bA>MFk~xF~eeMVObEU(3Bz@ur7@4)~kK%VVBmES^^}#5z@t2PktRrH_)#nUpwRTHI0c9vKhQa7N~h zMFS6w#_#e6{GNWm@68ABH8ozO#3kkScpNn!DTzZ${-w;_lzMEb4`-kAXy|#<`$4ge zS37U^>5oCbC_Vo%qg>34_>X)X8vl{`h8q8oaZru_$oYtI;LFD$rz{TlNqS#;=9k73 zkH2>PnHL&w_+t$658#Sod zdTVJ`N)zu<9!w zZxl-oN~CPbz5^p(dr|ho*DtT0?@ickZW)aq_-Z)Y0-TOE2#x9G+IwayQ)_@3L#qCtpK* zglp3@x3y%X7WC`jU$u@F3)iNrKd&bT;X+g>r!Oh4>1+G?(nR6HK779~sb#FSA1SJ< zK0`IXr+k%H&VE$PpN1b%P`kQ&VH zD3}d_G*@)(4?GE^pA~vY+aU1LgJ|D?*o#%FYCiKZYn1?i4dmQ!?4}oi8%QnZ9Yg5K zR7KDgLN3=5wr#EyN|i;rXU$`w(93NkWwf_{*hnMZ3}5%!Q_MSxDT+Gb^Hk@2T-5u` z#EUJskGE3h(eX(KTW+KO$KH2$Y1*jp^v zyJEqLN>i|7@4ffl8+K!1hCYDezt36kp7R7Q*YEq1>z~}j=ee0X%$YssoY`~E+V6Uc zw?dzAjwZjn#~L4B7)`sBSW)LKBu>KRZjoEyr=l12LEbL-tyIZp{;*}sRzmsEsXd%^eLhrZka@DmQA?{gTr9!IFS zYLI^f>x5&}Tn#QgPUeWoz(?=&zDG*3yLt% zE(#6i!xgN9u3;T?ofOyp>K-?dTW||LO?RkY$1#H1a1Y}>pjmtRimCjFgvd)UDIUZ3 z{s|3A%`cp+p2A=1IX>?N{KsD5yuZf0c?&qCLTWDw-V6bO2qm_`tTWXUroh* z^*ye?8MywMnd%hIH?}~&jum(ivfjx7-AGP6=0;tV7yVT`?&CJGXMg#S0?0RaM2=5E zQ*Mx2U${7g*a^rO8{hm}PA=Z*fj)a&@*@4l?( z>FLM)@lffDD)TS>xgL&%{%T%T)Zx{!eyNH2wl>DY`s0NT^OXzHc@>iPuQ0DZbshG0;-irB>7VQH-|aeVWu|z{$nW3I z%uc;N-1g>qF#=bM?0n~2m;dc{^5VjLEN|2uW$-9{7NrilJa9@su6qtZmu>Vzy;Xth z8aMDD9c3K_eDbX3GtW2ya7;sau4C$z2VU&U&yT|IF-hvJeYjp}Q5HC58Q^`Tu|MAY z`HyAJc`2@wd`klV^}_g`?2CBFgYoVZcOCQ9+<||)>D2Rb*p>N*d8Pk+apvs~bb)_- zG4L0QfY;~@9JDZaxlZ8i7Q$me_?kL$-5TitpVR{E-xzBTpL%=FrToec_Lxl78BFTDr1Z<@?<)@HHO}PY8-Mi+v1uH5hjCP1C6dRP`b_;) z!FL>d4&(6s#RC_P2mYk#u2p=0Zaj3hpT-?sRDx;(d_59OdU^I+OhErC0rMmQ>q#vS zQ~G}}|MJtk$Is#0|xVI5}S0nHNBYq!RJ|@pYEgzHn7Do758iB8*!e2iXzDxrt zphs##zaxVv&-q*p_pTaDF0~w%c`h14>+(G9Z?{p?UmXlJ+^JDb<3BX+-2V8lp1;t< zBbA3I9vV$kor|=x8aS5DMog(wx0%G!F2fD%%CgXBIhkSJCj_7H_P$n<1FAD zb4YkS#V`1AE(x<7A*l+4?{*;dpIK2+EK&b9y(hM)DDo~VDa3~P)TEH#_^!hj&`zVH z*;D6*z*QEKqVAd3BM9?;5jEVGt2C`$L?!lyD9-FA-zUYzYU`3E=tnOlMJ=@I`BD;4 zlAvBJqrz{e^qX06Ien8uaqwAAk?sXg7Mc(YTxSBg+CKPYHVfI)yO+sP3mbaCio6b zOTS8>ot|%ew5m>9m$6FWot=*Xp&T zq-rjxybgM!bu{v;L*1+Xw4T~2G!%PHZ#CZP#M}zQHtlz8Yj8<0Nw1U1YsVcpzAsN zxc_t*eDNbBOy0#?kJ4TR?)&~2aJ=J`)J$b8P|C9&!l3FDsj;Ndr{R~Y`OZgMDn?Wn zpj*3yKFk$b{=!8dn^&RRx<+GFK=C>$E>RuF+=L$MHr-R=FrVF_IwL!a2+n)(HG2TO zI)sn&Rs!fthc~uf>{N zjlA^8@05MLc<|8^(5FnoeLdNvm*9R_n#o_9`*IoJft#VuGDrPoi9WRzbR#z41K6S- z$_brSZuFt^aX+?}9oKgO_RygeU|mZ)NA{I}SrGm@;6L|@Oe6T9sUmf*t zO^jQc>+n0o^{`7_uA{%L$H#lPK7U@-hW!51jTj#t(FC|)GrZn{&tLPF{JHg8Ge2W! z8{ma)`LS4ge&3=FynWeD{J9U{|FoeCe{Kly$30*3`$l)?zej`rkov7IJHDWqBd=G? z@b8c23rhdc0r2q*gkPuh@yx92AA#+5XWA|^k2wI_b%$@G94|93aT>OZ0smQU_sWWo zJI3L+$1l&rpY2idE;H}<@8VsWP1k8F-G6<=pASEZDazl(UkjHkTUFfOR`tgc}H?rOluTO^GV++Zb1P^i)c$K$&Q73A7 zGrSJ>0nfE8_ji-ZV7oHt`<4bC=?y-otoNkvrx&*OLjTzlIGzW1h3@=lw*cdb zC+y+FX~%V8H9Pn?=0na*UhH2U)Y-YgJI;xmCtKi%Ik3GA>QZa;;U!Pm5_|zml@6Xm8g#a)ro24Hf?hc*&oQ&kn)!iA!0VEL$7=qLd|r}Gd>rOsCW8<7>D)`kyOV*- zX}Oo5%9~-IffV>srofjn1^8_WzDJGM$n(z#zfmLf3!0xJ&udLr&3z@!&yjsbH9tpV zI|Vq`{2UqQH4-0>hBGp+I2C&FRLp}^;3=sjKnxMYIFMdFJSLJF2a%$dNgFwsa?VQ1 z+oJyvs@kUc;Ifm3(vx9*I?viWjGDjb{IEm*5mckAu21dJBPs9WCB0f%{6bBejVjz_ z#b}CM^eo`3FUHcv2b&hJu??WnH!F9^C-{#ljPzayn(z&o5saeban+hLqU z4U=vj?wE55@R6zDk4+=bg?KPd&=M0Or44eTT*i7nUJ!M1xq*?GynnPwa&M$WA zK9>ZT=%3gskj&P85qw`S9)DJlu218SGWYVwWL;Um?}D&D0(Vs4pG}J>E#Bg7c)P_^ zH=p8!znG?%p4Xs!_!96lmr~*GC06W>UrOKn(z|KEvSs9`8XhgDt`}GDUiWr6*(tQn z#hUKw#XQA`eg)aScop}{@|DPWTt$1%3C!i;h1eG8J(T- zP5MscU8;GWTF#|;;Y%T*3-t()V6`Z9qnqid$oTJ1qgS1muivZQ}&Byb$3P5=-tnDx2qxi z<-aXg$NI3~KdSuHwYbl$rA{RkNBniv$ZM#@GTZeuMm2I;PsbNF30vG|1I<{F?lQw- zBV8D(IBjht5h}23;e<_8P_h4Sukjvdf2$y=(WKgV*=+$od<%`Z(kZaF&sM6Z5?HsA z`gIN6MwUTw`bxgr=?hgrww=7@zv|_9ZU-G(In3C1>rNV>8u0IeU(#+8;G+;W?V%B) z6lK{ydh%bGx(9YSu}Vek%*0RKOVzR@xGR~-jleUelfW3N-V4xa|E z@GP;<|9RZ6F5)_Hnbf$<%2%jtVFl^D3V!W1>MB^NjxIMSL!gZU(ZuiJHmNr9x$XkL zyhppPn2D&+hu}%Z(9TJUvHWA?2|OXy-mSnhMh);?l;n#{Fm96B%V&VDo(`-Cf>Tt@8bKA%*RT@`FW4~cLwg?X3%Gtqd#hiKD8C< zDjViAy4s??$%Q&859*wJj9)gh1CP=k{ni5Lt2?sKd^+;UH#>1%JK34*urWm$Z(ITX z|fyvoKgB5!JnvMCDd*HsB^0@ z9+*&7r`GX@s{?dn0ij=Tn!rA6yT0d3`<~%^CtHY{c)M(}e5eubXil-MR&T z-uEq0F9Uy^jNHqMZTb9_NABgi4*dDLPF!y$K!0_z3)ka&y77KogZ^rIckD0l$DBR0 z#UBH}t5AW zeBST6@9h5ceJ8u)eFa{kygvTX$1BIp?onM|t}My*g9q|?s+C0_*$4bYU#@Ffl;`>+ z2XMq@eyDSh-!lRH$T5DX>!7>VX}BZ%GDxX%#+>jmu!SBe2jioCY&cJTkTvjDE6#V?UvuI=RQf+M9%O*;q5*s}gNgsh=OqrfPn^luSMnbx9zGk| zaA(%s8OBHBfw#s3XVZKiv&+Bc^O*piTLRXdnm)d$`oRgn&k~67&jg$=EpH~X-kSNK ziO}sOVtt+n{-x&kD0z>J!zN)rH2jfq=OpkzWsX`B=26z%Yu2G>#UC^0%P>x@;g8J2 zNhZm6WPV^)z9Z*6Y4{_5Un$7xNipH^%6HPx}(pwV>Tc;_|WxR0g04?8`t_k0{#JsBz#&;iuB=8VDDuZ*WQNo7~$zchjB z*-Wav2p)p27KIS!iRenHLn%&)7gS^XrO8= zHJA3xwlNfH5=eX6DMm`-(YgQOms95f@10NP>94K_U7An*A6#hXGH3xcx!?2G`c4}E zF*E)+%T6(t(tPJPl~I^=i>c?g2?P5@Ey4Z?+))K?my+YVG7;}1mQh#RL9LIrSPov^ za;mVw;Qs>U#~PHV8z^DBWn z-e0mZ`ncdhs>IR=_{2ug&d_gz59M4EA4eG_$GZzZBTH*E=z9cabWiPuUIM zo8q;Cpe=VX3a68cQZ(5V~Y1D%HZ!F#-(f%#?zexkX_znbs!R;bf# z;2UEL|9R<)od-F6`E=}mV#j{l!Lr|50KQF*z$*(uAL9g{9B0nAoL7{`-{JzCvV@M0 z%Z+pUX1N3Z^FaOSg?hRa>S)xbS2TYkzP^@6-Rp;X7CuI8Dxv@F&-i7hD(L@LL%muZ z_-jqZIj`47U9RK(s0QEp@%4CrV(N1}`ej4L9b+5u-$R=4cmtd9_`O;%J~^f(KYrDk z>+^YS_&DxCe_f|N@Wl@NdYevMH`~B>{to<~u65&j{Vnv@i@KwJNB(7@p1RM6o5VEu z6mC-aPpGersrB3Suvw;m5aFrHTybyyj$6KBXAbEz9I1-uVALoG`3xB*_M z?>yl%ihOi$5AIk0;EwzwN<`)h?d+7fv)7O0~opTHcio1tI-5p{nC@SP9H33(6vD;+wiG^`&}f%h4K zGp2y&kb?DSGS*`nkB#-miQuCpf)Aqc?PTt?%t>M1VLW(Zal}57n(mtU1O}|P3|Pk) zfL|J*V>3XXs^!N>+>w2y^kh@Okxt&%i~sEqOb|VFQv=uZq@<6nyQC+@HEY}*JvD5s zIAiIlmTJ7KhYr?&b*Ywv&HOqI|CBsTnSU+y;nJ@%k4gkJfQM$ld5lB;R~&qTv+A$^ zxA-ITAsa}KNlRcPvD{+rihEUtQ>9x1C97-d) zn?0^SeHiKP{dm*)(QxqIM$*)%qpKcY7)8hIBig?0Gn!P|ThXyJKlb8Pf8%|h-vsu-DUGggiAg=U28u0f%EB>U|SZN zx`324!dgBHDfO-*%w7mQE{LYt9}S=Fv4}4DvAp^M>*zl7dhi(4}O ztmZr4ss5AV%}XpJ5z=UEd43rwN7;7da`b0{skvfrc_Wzax+)IxE9mCNl?xtLT}j^+ zPn|gaDCZXG?yp%`B=Oq}FZy!B2}Qb)Vi-bGf$>IE&Uy&HJn9=f5(sz>YvpLQQ9sP4d` z2dKR&R6a=ib}K;kVd(e|qknY-Ig>|m-_U&Lxi57RzWk?1kUxcE{TW<`&(VHs<;HZL zq7?i3Ef;bBy$l}w74QYGq91l0Ih!{~l})GL1ke38?uU1gn|Ys9x%AM7q_CLhb&J7$ z_%Zak?%y`iV|leF9-K6 zlF(mEhECgv{ZE6R#e2N}BXCeN;DZ*x3oYS)ZH0cY4f|+!w`ClzaW3?2^FW`HkMX^s zcHkk}Ll+};D30)PECgPp6YxK0=u?VvfA_Tu@&b{2*~Lw#)(xB8F`g&%(Nb?C>(bJ| z56hyiMy_Jx^1u_Nk5NUg14mQ>P6+?`3E)3gs)liD0PmFk^K}^iE2(20O_#d7-RgS4 z1sgD4IiVrHUZgSOwwIe=yJlS12e&{S+LCd?(XCNGx8XX~tQ~LPt3B7DPdo5_j_t(T zRr-?Om!~T}_bcqzH~hF0_~TpnKi2BW@89GFo&)OnzGbi;@qx~~9L}pR@4wJZv0e*4 zPJVv)-l4Y=e*Vl~(DE(SKH~xKC&YPYUvf=%#eVnYFh6{7yqfPk*PGB^twi4C6>n_k zjr}bJK1E5am%K2KJeen(fxOEaTJELVpFijZe^NKby*s*M{+7UT7DwG)4C{iT@S`sR z|0rk7%fiTgbu!`UD(~37ApD&i`S@x(fHz!#*Cm1W*iSo?Pb&8d^1<&ZFMe;i;VYjD z$CnfMzb$@$IdojF+kgjQ4c~h!tXnLR17X3qeI5&*|82~n-!jAc=c9@L%)IFj=vTi- z-JcF#K^l0~so36#yu%da{ia~MWMW^UB={I<{0HU>{LlFhoPVL|j|QtmgE;7gWX`Vv z{t^c8Gz_>78j!oFtq-JrO6sZPdSu&c#Rymr-Hx8*bNRa5Uiv^~<~_*#OX>f_x*h{^ zTQpy)%1`Y3 z7oC80n9MiP^mXh%ln7l@BJPJ-{pHUI7DvK|MDRY6P^Tne-Iav-mxTLZ67*kL`3~8w zH?q@PF;5^F`<0CQUb3lA$9#-r)C1c3n(Oiu=#o;fK2O1ZrcidiPMlMkVp^~B`AdOr z%}6}2jHo~V?>vV;N@u0!b@WLE?uYd!8s$b*!6CZ_~Pyh65{$BkW>E9CwA01n`M@t`_%(|K-*v>E0cA0t5A=oYi zt}k-D%zdFKY-gy?^H6SQ{1WprQy=2bdR3Esugv@XyZT;+PxHY)-}Nr0*I(g!mt8;0 z7FTOIe?C_~>-J_oYqFmuKR@%MyGXl>2_8sePj}rk_NPH~s%ejhPg@M8swbX?b!jk! zCTxi8_{~>CDeB{f)VRgN$ah}ui!u7)w4~C#f@$3a{&+96M}^m;hz9k&+Hd-3I+#+m z&*nN~sa^ERJ438A{dL;6`V&s?#?#NuMsA!GJAp=z|1z{mist{gNvK_06`w-$l$69e zQ<1AUjdJS;**}^-oyG`NY0{n2(*w0lW@3PXNWtLXq^i?5;<#YRnBiA#W zil|1D5oG>_!k`oQV`y-nPHwA7eY$Wp^t@}xX_bXYlw3m{mDtITYpA+NU-S=%q_#J# z+N79AQA0I2G>RVRTMLM9EfpT4D7drwJ=Rl!%=O5j+(2qPm@f42S08?Uu!d+ZLcr}qv0bFP5q(@zx=u07V05TpDVeza2cj9i-A>AMT(9os<*3lb+wGZu8ydT~tYN0o}HnT-AxO2e{r| z`biaF?+5Ot`98AG@L{T2W5?^%T(y(DLB|xk$+owUD{}|y znY+LaY6Mf^Avr^XTXoALy;kJr8-Arq$G7hkt6z#khm0KU`^_+ewoRK}Ty%!%( zesAEAnhzAOpXK=iUm>78a8Bs0YWp!x*&ex;oirR$@*sG9T^=|z{On&yT^DkI!pq_N z^8uciRe!}kQ>FR*nw7?O-uV7Y0hcQY9McQq0hjjn)KyRgKpyPN9*+FW7jDcG@O5Lq zfL~lOk4u>5or>F7y5M^(3Vv=89)Ex{_y&c67dkPImkP0tsX;;DnU2t1Ibc5v@aOHb zhhM6lPVGqWPLj{SWg4 zH2-;tuQ{s*uo@3S>XW1ni*+TMzdQS^8%W}S5*L*EDCrw7{hRnWG+%l7T)r;1mpG&J zm16yY0eEfpc%$4u_Te|+`Wpw_HV(R-IPl@)fcI#=`|OvM)n{J%WHH}79{BI4c@EO& ziSr>6i18-PUtZ#k(x;30A_*q`3ZIum_}eF<&!**Ba^GFkSFyiWR(~g%W68hMB=q-^ zz!ONq{7W+7*}NY~xW6UCA0-($v*zn0b1QisB%Az?nfH+lzmjC!?~>7f%c`eh|NRvB zn56)ZO92j_0{vGC>Y^0vXNn1zSMMWcpT-w?9vSidW%Y~a{*BSpKjb`FqsfPjb!(~M z&!l2rY5WB~j#L~+Dt?!#z;#nix=Q}uQ*k`0IG$Aauw}&`Z-Xbu$C>rN5-;l0kJmR@ zxA=Sh<@2q_U5ES?*5jYTAD0Z^qmc9IAN=v}h(B7G+2V3>8~oqwt{!rpymDclaCY1M z-TwZm-&xF}e|~4mobU$T+v#64--F$YVItCcAWgs4bm!jSK@>aefPce)!Bo9$ zSjn`}L+C)qdc&Ir52d?Sg%{DIVYK9K+Z-cnkD#&Za^*d~btKIgLXocY3;ojS`S!?X zqiMdUZ6{smSehRD<*h!|187XG#0MLF#?$cRpd7!JoxIt#D`wM-=ZiYl ze=>(w4ScL?QYa8P(Sg+d=e$1!b)ScPmieU81GmnnL50+W6e`s+cDQ%0g>-N7iyE`H zFC?kE7Ghc}fBQvLbYBDENV$mCiBy@912o=a<4-wVth9=( zRD$O!@YF&`m?FA7-X226DoPTLrni>3Bl9@JXy)__f-xCJJ$`aKT{mYq^yJ~R<^I(l zo7@klZ&jc!f;es^f^to^tv0F5YBE=Ya)i!Wr11(fKR?inkQ0x zR?Uf|#{%WtVjo4Evl9hBIW=khzVKkp_mTOPXTd)>k9_M3@cp=i_2L!GpR4qpa9y+=#M0-VgcCVBeQc`BpYdk@Y&QlU3%+lxV1n+V38G-P=plWJ> z&MWGw5`SMq@BWtZ4%{&FUY}SK&xiR_ao{=1b*R)kB*RBV^1oBDzDvj7KVUs)23?2r zhp}M4nj%)f7p=j!$^rd#PUvfLGfvYuFYuH6oF8Lp4?pe#&@Ve+{DSOP6JLmR)q4tq zuT=#6zhdA&76<<3irhdq=({}_4?FK^;=idltFt%or_#Vd%Yv8Yi~W>->d0%{Q4zSH zKR&-Q2k)>3zyDP&#tH3-KPOtp$Eyebv0;7ee*?zHYBl2hd)yeu(UkXV zW^>+d0dlVox8lF&Zo}_u(U$SO2=E^ZcHqwo0shzoxifj-`EH6_J?)9@K6RJ*=k-7P8R*r&*P!o5nwk0eRZw@;&#xjLE8)=}kCpLQ1&>wnSPhTW z`LTi@9x+}8j8_5URls-^FkS_WR{`Tyz<3ofUPX*o5#v?Fcoi{TMT}Pw<5k3X6)|2# zj8_rkRl<0cFkU5$R|(@)!g!T1UL}lI3FB45c$F}oKgRRNc>WmAALIFBJb#SmkMaC5 zo;r0cvUf8Rg6~^<5k6YRWV*wj8_%oRmFH!Fqgf`N*=*9s4u*wPgGKPyEk* z|8n}Ox)9NCXJ1Wk^haerxDWIj={o)_wLFZ7o^ahx9L zzq-T6(j7jQZs;q!!Y`@>a>t9qchiOaFmo2;e(}vB>?6O?nRP333bQW#7bn(%3@(Iz zc|q>`PH^PD{Za?4QwnfD`X}(1&~=?%$?^FOv?QeHwHIsnE+C zp({u+_2anDnr!k{WPL^w@&V+!G7;;@1n4#rz_*FV`aB-%>3FP*wfr2JtHXK%xo$O> zatzpi(Ey%~0s2x+UoUgbx$kN~A2jQud|htOx(v-HlywjW@OBLFeKeTzT)A(q`EyF0 zitK;0zEJCnvwkRRJ~`_%;!M7#(kD&&4X|%&)_fq=VZ@_9ngCzM1d_SrtP@Kx`5CY- zKLI>}1n7AZ@VQxa@vO^F#PKIW2a<^IArU--L{p9gA9q%L3hQJvKhAPnSLh>8CZTVc z1e_)rI-O+XP$%PilexH>4=4MSCPQbH416aUIYr5s-zm_|X#TV6$2Qmc#f{Vx`1||C ztfMi)SJr6C@#XK$2>%Bo`rJmGMKEU=uozCc7rnOly7vg0zC#KA9!cdcP29I_*e_&!GBbIE+Zf=vW0}s{ zEr71yaGBY!?RcuWVZgb@Z6{F5tGp@mx=uts(IiSz;%cT$rrRsOED*A03jN$zK{TgQ z4&lPt`u#L&n``fZhzc{1gFO?z!Lw-O&^hLJ-pnT7!Fzp5R+&qj_Z>(j2dD~jx)=Gh zf@RP=n)~RUNW_^>TPjVy*!S&xx;E7}>gS~k;7_`cR2VgRA@aL}NR0>TvFTyR1Kj$N-X%25ad>ekiz2a)HM|R+fXW0 zdC8Q=9wL`~x)Q(>Mn}^~D91IQ&T&)2bgNE>Q~B`D{eP$&K@)#afY%7hchGNXnZm2d zrhHnitFu-k=VlG5_Mv0e(AK>-2478ILqTQtpKCZel8QFoa3azyid37)DN!WE?jl%z zEj?E0vuo*a$-dX?`>%sfz&g6Ib;rRbeb!T+9E!7n(8n+IyOz9p0}UNkv0AgQH{$-X ziB4>As$c!eCMx5y;p5;Xn<;GEgqZ~^M-#^xMbo>TxrG9L3pG)LhPIHkYOuPMJhwmZ zHeC!zw&e!Ma>!~S_`{rvJ$J4 zq~!%MPjo->^bU}cre4nN5cM3VB>Eht*$SNPcLdj`qohv9!pGpZaGX?|f_5k9{;lyM zdHp1OdQXA3bA~pib?bK`<1F~Q=ds;IQd~LBzqm|_8|Sp1S8)HlN)Bp(_%-AS-2h&F z6TIHrz+>;yMTOq__8yMs0VyoiwGJ`h$3CX|8-I8>aK;njob;#QFFhv(E$^H2CGKOd zXmOxI6n{;Asxj$X=n|1;ov5ofxuTsW`%OT=|f=C>KacTL0oy@wxh2K;W!bZKK1 z#i%*>br#^?$$G{HdS1z!%c)~OYpL_i%X;G+b~^R`(FnTvl?B)@$lj52he8U%7t{$l zWYlx{in4E#mkW57C4k$yGB2-+JN!UBfctuZw^$NnbKu%7c|TlR^JD8acwbu{FQFZ8{{wQ%(>wBhuImgwY8RX*j10|hQe>aUdtm@d8y(&vi{xAbY4}SSS#T3!pEzd z@`wA#EA3Ps-;*!zw=;5_dP|f2yk8}AVjW_O5k6I}VKW*K?{^Dt->jvj*rs8^G zH0gz<&pPYVli~A~gt|%NIZ8ex`@tu`cQ_vFgLtfe;=!AX!}wZm0PC%_`ksBkv~`8# zr?TI=0dbX^aAo}Sd(_7*+a)?VIW)p|X2;(Ai;x_0SFjfFd- zC&jHLZ;T#&MZIZUsiS9K`mDZPl1DpIHP$!4uf%|Ln&#KVISX;{osR>rP+NzvzkD3( zfq3|m#hd(6WbP~T9JO3h{yw!lQn}uc{?6=kkbrR$F>WIKVl=;h)@3K6{!KLHi>kl# zZknGz=L#g@{+dLbZ>y~nSkJHd^YeN++2sGm^>YgNl_{omE$?Rv_S1;{G-5wBz9;(= z7%{JmCO)UE%lY_a|5U5HId32p^+Ou*JW2!qISuQpH1N99u#QQ?`04Q3PX|9V9sJ{T z)GO&&&!wBz^L$?36R*?XV;%n0e@L{y_u73uA6<6a{oVeaT_36muGaE={Ly{L?0lZ>j`8<1LVj>Ik2}AJ z+Z|PCASETg40C%rkd8I8F4*DFAR4-PLE6^sgUKSG=cSeBhR~T)u@+v|!)RW;FO6wk zhEu>U-GnEnM$jU`*1Xqz6b+t~=h>a-zfj>T!&*ED8bc)&x?z`bl#xHWro#wu((;`fT`m&830W64qDO1tLFM;E`2I+?q0D z9+_9(@zcig^GT%{-V#2ZQxosq8oz)Vgx8$5qVz)Qt;R$zgx)HMYE7Jyk<)h(i4ddP zdG9Tvca3M9j-IiY@~Z(oOK7EF*>-xl1UjLmI1kHc{g^T~F(Savr*VX+4!z9YQz2=U^jMbp7Q( z`qPb+@Z9=#fW1omJa?ZrBDANZpCX=LZ9$`@*Cxk2K~`z1d5FiltO7LL%k^cn*$PCH7G zBTtpCG5;9yhK?ie`~-5|PXWI>ja;9zSSOrAf8YZ3EvqC2UBZ03Ou}?Cqkh^IQm3E) zHR{n`Nmjp3dDTFo8`N|~K*^(1Zjq8wWaWQ{4hnbHcGmZ(UY%EWHl*E0zvU73CkE@Z z$H*an3jFgK_^>a)pM42m>tE>yGeyz=h7O3d^fS-jp)X}H<=nAuF&^u_M65%SOnGY3 z7nt>v>F^=@fc4Tx^f}F;54HfFVhOy^TE~4j8^)`S+CtBp3)@M(Z+`CQ?yv)HQ-J%n z-#egx>&X7=Qwr&LU07JhxJD7~&z362{oS_38J}tAiaxd*<4v*dz?(GvyxIp^sp;o= zU0fD=XNhzD=k)X3=d8zgUXupU;WuP{!S{{%e7QGe+%%&Z<5nM9=+w)+Yb)j*>;MjF zXv4=>w;khq>)SK#S-vAbUh2d+)-3pU{?wJ9|MV4b&~JEL18_*6Z~1wEh{de5q`w#tmZ#Uqt zuHbthKVVmJ*0KNW!oCp|i@^u92=>?6#J5(`{GP6Mf{wiqf3GVGGXA&T5qO^i@X7+f z{h*((Y0r5B!|dRXn;$-)`EXo$kVl%E=Sl5c$mz<79Dp3?57+=VwFck88o0a__~e$r zZ!IvcInM(#bMPI^-~;;6gh#Lr_X9B=lMcKo&C~}~e`m#0fzKFm|4jidlZ@+;rkiJ- z@BbculzMUYbI|Zdsh4NGQ{y*CpZ@Id$L|%p>tsD8HB*dE^w2fvaedUopG1$`Ha!Uu z!KuBwv*M21A=;K7N&o3$KL z&iT~*IQe)IfsbiEoD!ep{8P<;lYLo}a6FpNKkM=}yi)4m8E4MQXJ9^nhF>x+mjYZ) z^VQ_OLkjTa6!=@G5cfwlT$A%xjmUr1_zLX9V8r<~qHfS~K{*FP)3ZxIeu>vJzMP8v zN=2VB73W{mud`2thKq8)BNe~LR8t>-@yj&y4K%!z`7j!8%JWadPq{wOa8%xJ4Nql! zKMmib^w&uT-zl9wA8yut+h1Wl{wdt7`xZV5xeosaH~V|xX3}>u8hrXd_&iFU{fPcN zKVE&!kGrv*vACs~@=tD;nYVlx+wIOYUS@pmG`8ywUqCtDfDQb4-kI``RO+-ao;Qqj2Ys#Z!9_~V#oHzV#1qWM;jb9rAMOb^~f9Q1iNgd!^W z#cwS+j6}Fkr=T&zsYucCATO)+ub&SeMZ&zYMos6@bnA=Kn}aTop)nT*-FX!} zj;c-VyJPBs0NUx`U`KTgXJnp{sw zfSCb&YbJE*vuVRd#rSg$3GuW*rsk518pIt4{rNmnW$gRsQR4JkP51VmPiv3(=P6+? zd^=Np1aor%jr-ze)YLu;DKu0e#QV`ucU(FEOxS5MMA_b1pTYv7Zrj!Gz9g1C@C(TM}G*Vn$E?%HeU>-d;OFE zrZ9T-@R--B6=9UvYQUB-n{Zm)x8$Rr28UAzg-#h0PHVpizOQc`LHy zzS?T|ldh(vw?}s?T4oLSxoaqH#ge3Ny(4MFo@x5y8zMFeQdumRuCMjEKlIuCCow-SjzbsV#a4hVOE zn1-9_&BtOd&gB-oN5ie}W{--dVusWnlMK-`Or+gM_uGQ=x`jkYy9jF9O1ZyIEEwUu z4Y}dl$iw)k*|49slR~!iFTDfx^bT^f$QRn|!cOo_cEOKeH+(YpfakXt>*M`2|J=AH zhsGR$pXfp8&kq9!Jpvr?2>1d=NwvE)KTdvXaL)&#P_4y6}lz9m4=P4V%>0!wh33wnfI<^eWvN>RhV$@9psDO zBNcw^_5ePskI3%VU7Iam#?Ztz3S#+$#JLthc~7aLV0D&Ae1_bG7dXCG#6A(P$z3Jl zyhZ+ctSKLZ*LQKI^(L=_6HWYe#$!@U>mKH1OPH1-5U+U}x}`9U__`SnWRKMwvD=c6a^Hpvszc#zBs z%8Ea#>-lZI;77_FQsB6!;OluFIi*qX>Fiw|{Lb>gjeYT4@+!+=e|&(K`2bHY3m*gU zSMQewZdn@Nvp4WGiJO+h_vD3fy!iZe@`R4cgCDQD^WUA^84vu%jd_0?T#+|gg6HLi z;@~~HfNxlg@xjC**k5PlpB4rW*9rW^Lf`=-Hz?E*c%K92Z2=Pw&-jQva85hq{^SRb zF(39L4T1Q zX6vE1(35CBy?b+54?UP3IGq8y0WGIU=9tR;VjNA&S(W;*swzOG@ge#AYRAhw(Kzr) zHT@a$4C8Qpj{`0hk3L#FbV=HIW&AE4x*jdJl<{UQN0#+Rny)JBbrOKnCV-ckfccPs z<4yz)mI!^3hEwwACISylgbpeZ_vb|T(j-9_mINQuB-8w1{5c8zz$EZilh7wj!hUG@ zCG%c2KTkgY$9yu z2d)?S$o|~F)6BVN)4=z_&nC-*>Gyhqk1opwf73sFzUzPY>wkrLl^u>~hr5@YCVw=J zD6cCaclj(CPV(dLx~`1)^mT=Eb_SAf&ExdbuLEiL{xd&cIWvf?y6m0M@AzOk+rM{W z_~Ri|+NO#Bc=ut{Z_~1u(?$;`=NiLWPk%FlnxAWOAac+s>d|l33PXX>;8l&GLp#T& zU0ODd7R`U|x$s~B9rx^Z+GF>4TH>Stb`$8^UjFeTPfVn14vR+U?o6Wl_ALd(G?_Bz zm%m%87&lHQ*5A)S{>e<5(nV1+%_bH8`*IG|eAZhq^|bsTnq?=VbwqAZq!JiC4}SFX z>8nbqy_XjixZ_ksue^Zr8Q=TW8?g|0QV<>7Z`i);sULN1~XjL z;0jXdm;*KcP9c_^^DKT9y?IhaB-MmaaiP}!>X62J+~eH;@XM*8^rcW$d&Y*68t>CF zjMhFZa=XltFnTLc+YV*Jp(_t3!=WJIBpLzV_z0?%Qrx$CYy^c)TDo&wuhlfz_e6(Y zk5<#x#L(QYyRHGha}B95X}3u7SBb5W6m(q)_>Q8b*LsO0`zWeA=3KDv%(dVnuA^;V z=Xu^>pLq1teNnFKdYa>L^GQ3i4OFk|#nrplZ2&&Dk(#T4KAY&KPT^O+w$ zJNBG6)T;peYLFk)tswk8o#0p$WYeAyHojjzR+LysQ`SaBHrf@9WwHRnpFkfQyu)e8jRx@YJrbOjA!lA zL0?;!w`*RX_j_*x#`zjH!uye59^I7Rx41duZJ}TAxR+b;emFpX-JvbxX`9;d>#iLb z|Ju-zajA}-b?SZ175ZzNZu~tte9ey@-TC#_z#kU?e|*~$yhKmlZkyx}dgFX(Ip&OC zmxI0;xj*N9F&{LZBkQos19t{KSzO|hzW6&H@5>x{$w&3U_gohEBK%folmXtW#@8;nvyZH!JN#!g{89B^$tZz&TO2%H7wDLa z0oN;n`R0sy3chZb6Z_jPD+C^7LF8sRa{kXDjsIwfJlVWzPL2Pl@`#7qfd?snFZtka zkOzOytz#T37xJ}o^7m?Hi+N`QJkc8bN^9_lt>BYu30&U-ep=Zqi zUh#j|Uo(F!tNxmOloCz&)u;5=lK&|CDpH>;_1CNi*6=*`x6<;;`Fdu6Ue`dc1p9IE z13hpd!Cw?9Z>2)?RJ_oSUnI=Yqo1UwMfWInwf_dz|b=Xz4q-1lzj(eL^+ zA5!u&B_EP~&KV8EXfx}fbadJn3-3n5$h}=1s}AAADThaL&XB?*X^=6(A?KP=boAlz zz~C06soJ3)VRdtjrQO5xrd_=^jxOg6o#^{GfQlZRJoM><@s#^oN|6aqCy)p)9h@s( z%P;-5ndg;r-czW=-jIX6T27^1-zr8t)5yEQVYl{cr_+$HdoGT8I0OFlv*0f@o64v! z%ptDh=TcS0em*pi-po`A(|Pzk&!h7Gw|_cEN< zx?R= zJw3kHcn?h!`BzmfH=x$)iAm$~g_C=$`J0xG4kw*(gR*!VPUr3^3%Lk7+Cmk!QK`Ef znxr<>^j1Hs23Bj3kFbXP_fEXMv|c2sHvXqYUa5Lxjw096N>V`-oxZ9VX00WMQYkeZ zt=Hjqw2my_hPUffXFUl~l29nE$M0+dZ6Bs2GHj%Fn+(2AaT`gHVgzwx6R9+TVVg;D z$O^>P`Og=w9niTfQkQ`fZo!&y_m9pA;D?MJEHnQEktyDlYTG~eU?k`yxeS8}Y zz3^;#zy8}P^}rY7l09~iy8AD8&~;^*w0kFwj*o8LciApd=>W5KQ?Z@p&i)j*hnoE| zv3!d)dy((C4|Tql8^H7D5b*!QxSt$Bf8!|bE60#KdYqn3RD^;jNZH#0j;Cci+8=o{W7)xIm}HuME^ z|Di@btSjpC`*Jtrx_Vh7=&_pMyfnk-w!rh2Tt|Af#<~KzrNM1cm$&2X2Xz2%p%Xvu z=*-(s>B8%Q!QJp2>yMt`KP>3M>z4aif7JR;_o;r(+>>n(g4XMJ1_{6$-Y&!0GdI-Mcj}^w4=w zFXz@VE|3#Ay{(RUb2(5)+u*r1`U6(He@`v>xbs=U-@t;8YqB}^!;JaJo@S`?KLQv0 z0G`@=`0k|xCrUHH2Lr`E|>!U#$*#OP5O*;A2QLzlaqWp*(YINL@lqJbMNEe zhpy#%GfyuL>pcV3c?MH{n#>tz0||o(ALR9do?5e zqaOYkdi00%=ws>87t+&5#pa{69(^l4sco@YdQxpTqV=TG*zf2~xF_SW2Jiz7;K>`{ z%WFWN%V6^HmAESVA{yX_5eK{?4t^PN@EO$nF&i*36uM$fr_BRo#UmLHjmLS6$2v6L zRWH468f~fbN>7U;GqfNWokNZJ`b9Iy~Lwg*R189vrb*ZC8d5};*!h{ zO#)9p3Fjk;q|WQ^8Yy{qFL?6`% zyvS(EjmVB)$-m32KKRw&m9AbYc>tBOeLkkxg@Kgsj&ASm?VA5n=NB9I=DRV3Iu9y1 z^O55)`m#bd7qfxGY5eOF4JtkxLB4D6_Mh-`R{lfx^;R>FEgeVG#%~&9{x9@b+rAmT zH{p0z{sZ@~r;_5TeYwFj3KL!W7el5)-!y|9N6sH|;n_@bv`%ZV(sMSQu}~c6=g?TQ zw#%#SnM+fODngz>x>%*^no>UVh;u*Zk^Q6TBH?mA_@WEwX!vZ=v0nguXCWyr_gxwX z(avVk)q+!lh~+|yNSH$@2q&rVXOSh~r7of8rEb)5nY)y{b1BNMWpqcRm!?@SCq<>S z=jd{ZbT4?a(1c*B*rjm?hXyNX|Gbfkw2T^`SuY&ug%5po1*lv_wjGq@)DWsUdwctb zb3*9uXnl!>EA@7;3t!0@H3K}Z9 zQIsasP<@_8;ry>9&)6-3F|iIfo_MUgYq5VLfjcVnhd1l#&hUnUda;344Kw!L+GryU zRSoVp(t=Je3kM$9M7|xbcP}z!Gttwd;{$!7sqXbL;v0)56)v{hLJQhne&;oN3uTma zbdRyyO6M0VM47GlzP6D{Te-FkyoK$gpqFNqci{WlK{oq(+zUIulgwNcS=TP`RCWXB z+k?K)Uib#@BPFF)M1rEPe~?rg;hcv_op!emBd7HU@YbW$rth-h!C}X!fFqr}zvDQr zhbKrhyV?!$Jcaw^Y52jOflt&q$|Jg8ZJJ)dc9+mEx(xpP6*~NOWi6lUS83nw**1nk z*GYhg+g=a8L6$jZl;|0I6FC64>102JnR1uTD{?WH`!q3OFxNp z_(Wv@A2kEsXb#^R3-n2?STCZt20obsebt<(%W?x3%nN-;ejV2z_NWh~{=^Z_3ql{_ zq*ME0xt-x_Q-t*_4leM2DuMlQWxb3K@{8ts0KfA>om>(+6K~YLW$@_3_})t*YV#g)Z@>aRiEolvxZzB z&S}KsRd0g2wi$R7&9Ple#uTORLiJKnFJ9r$ z`}p~A57!hvvcDFdW@q5N{_R=Qp2@S@C;s1Wr@iCv@&7*Gyz2hpuQ0DZg_9Yr8E2RC z=^vcz?}d|Pci-8a^xNyof9k$7B7r|=2|n+4-FGhkPwqRGs&~%_Tn;5)zO^m?4hH1n z$KSOdezSC+y8mUq8gpKq8|oR22g&_p^RL4)~bVWowTrA4%lP zu#cR~vndB$5RWrZmnD@2ZdVp~8uDfYe^uoJ)hi7=ROWP+!Z@W+mz4yrCi~EysIxqo z57@+m@wPec%pbh%23@rqc)YH_Q%e9(EY3RWf-a~#i=w_P!uc+N&Ujy89sBz^0dFjX z9G8NqhaI8Eb^xzb%f00DV~@Jp4s~#T?#JKDi`XP3Hu`^ns{?^ox=L#c;IpICjK7h^2LEqq2X^bPg3T&@O;*AJ(&k{ zV}ycu8BBhUJ=EYYJ$gk=zsOl+3IPDP+?E* zqHWK-J3Z+l9v#dVEVfs9?RxNfvf_>s7iAux0l1Hr$I1At!NenByv+bUivf6O9Pp|* zoYy#FJUpu&oBaZ{oEknK@!za{|p)O;gljt%qo z60i2q)_CZO(_n878<`n47Q}BC90j`?@ zpOh5vrc&^GGn&@-{CyjNcmMDCk=)t1rlKD)6UkUzWPN8;5%Qc8R_Sd#GPaQ*HWr(WjH!^HM`8p-avOUIT~Gn<1`m*4`LSiraam)+1?Nz?J709*?4~3-7ot zm^GTd2>aUbL(8!=vDM&scZUF~yxshEfbDpCJ85yu^&AsuS@ehRX62tq`dV?p$}eXx^)`$jO`*2lIhfQ)X@U@y=TJDeHQq!v+07l!X%tS z0(^WF>K#Z2W_`P7^^HLA>E==YHoZl}rSO{P^C`9E`B4=XE}(CX)0Pxyx)A)( zh2-B{aXJbj)h_2J&G#uoxVu+;yqHuv--;#l4I8D?=v)DDd5SEfWr{rPj_{pV;l<^o z+Q@eg20pq1Ih`x$;dA$c4%=2@UaTVH?9H{ed4|x%0hV=WmhgQNY{GL18t#~Q%=Yn> zlcCuEFzTQNXoivGJqGrzf1=vBa1x>|*Sc}xBz@+2-bPTRHpP!uKh0 zl2`H8YbYi`8F&qSpMSeW{f?0|@5aWJ3m!(2_wLSZCjJmbJsaj-)5ECgtrT~P>K^Mz zwU0j_9_uPh$@RoJpBw0fYA3&eRJi$@jWj`#KRF4$0i>TBO+5FW*XaRAJXP=;XGM;_`c<-*!^YmR<23q{gn^+d=y~ZERs& zy^~z#I*X{wUC2cd@9Sd@{k?vv-@kAY*; zAJP`V_8cA@gMQ;<Cb@&;nbkYJZ;D7uQz9hfWT!CI*{rL^4ah#Lh!H-S$>*7rJ z6~4|&-h2}3g%sRhjOcHs;rV;K{t?$XGxTRIP+wW1?y*80YJxu0C35c15OOnK()J6;rhUKik!uACFt*bO=tchsMr*dH&h@2Zs& zb-41cG}nV7w_Wu!GWamQ=#BjMqkdf1<*10du@d_3{=hG*Fh1#44ezhc{r9Ie!AGpk z+ZWUE>#gg8=U9*H$Pdt8jcUl}$-Xgv-l-<2bDJ?98q|Vc-vaz`RBJqM!`o%F<7*a(Wy!~b|0wJm z%rg5F+{SjUa08axW!4?XU^{Q%i*mcnc%$U~4FLO1ZkKs|sP6xt_&=Wye+tRXE7k0A z&8mOGT%=c4yw}-%g%XF-<@op8W%vI7*1vzgc@<;-SD06y!ZrPz`6%Rk`Ulti2iH`t z4S~S-yyy;HjXUdXesE)aaK9_-a~xb*kNvPX{2X22 z7f=lKZBg(Oi$LdG7&xC3^AuwWv0uTHg3#$WqJDM+&(Z-p=mNkc?K#JNr=6)!&w9*! zTrZc;%b))|H+0;&OnrXVC)vWUQTiX)0LQfE&+l)=IrH-@k$+Kk2%-XGtI!4 z{0JN>1Gv@)@TA^@N0JWziZtMILVu|e(2OR0MB*-tdn9AMoMgg}I1fhieU!K(>sht@ zX4aW%cpB?h@Htg4Kh^*|P4ivkb&sC%wc5O}*EBu+IfR~C&GXj7Z#R|-rJsvE zb1aswJye9&vEZ}BLVp*FJTdLL8uPX&7VEuOn z$Z^O!%U-7~d6BG>jt8!+;gihE)beaNUnK#@oq&0y>9xzN0b^Re4d>1zKp&lzADJ1a zWSl<{>-|LVZ8Sego=1tm%@Z+SH2pT?ei~1bb^l4kez!@`JthJ7&~)78)DxNnyid#X z&Wu~CuxL5WZ<2YP$-vW-p@U8ak0}{AYgS#i{2ejxG}*LnXFt~z@N_laWM+LgA5RL7 zCk6arEk8VVv@)cYyTf_vDVPtR#xa=>YNTRI?t5>&Ie=!yj4OL*%Rp-Mx^~dDm4oQ) zlMIh*p@Zp1zr4p9AJ_6P&rPWu)Ud~JYSVmh*-1A>&{qYcPQ>&WMS*v|Ol)aAnwo@L zl)86#4E@;JKY#am<7kv>z#c#aORNf9v1>ea@NJ*5WB&wtIKNo*`ZE(rL662hoJ5L> z`EJH!8obv>L{?6v=R#%MqSZ9`Xiq1OIh+Ch+DsbrYC_tg>a(fhi%nk7CeEQF#cGfJ z`Py8HTHCAdn0bM8_Cvmgw5^CA7%&c-&OW_;4l!|@xOK;&#Pmzl@CN-?L9JpLC zsq*F1!Q?h<&E=7^SJ0FfH3Y+PC3RL}FN?3DGQ!=x&nwOM>Bxy0MOqvac%;hP3?)@= zyC{?diS(Nb=3%%_htZc#yRMi$3?ub&^hG$CM^qU&=ukMNI+{Io_K%>i!$$S(zCHr_ z@On{Xy)j5YHlyfJ3+?UWJ))^` zUM-&T;)?;$~q{vd1Q zUJ_ZQx5~wm|He=6S}l$x@oa6)k0lGYjT073je|~J@te5IiE8|NMv3sXPo(A|ytp_CJk|ZwuYs5_noPQ4Q%)uMD0!D%MY_D-A?T+M!)Nvg z?r+DCTW}n?0w=&PJc;McDasaOLra~8udU)cFU3vJ^5xW#`CJz0Uxq1mh18N@4x~}f{r&I_ zC#P@W8x8)1xS5k3xBAO@o4hRJ9Mj7D{(AEIf0x(q*RKXu`YZISZ{cQXwRtb({`3!S z_V>cgWIkMAS?&jxz@z>UAMV_@`EcLwIt{J*SGZ0K!V!Db=hlA&f@|?}c;T zZTs)-D`-C~2mbqdl7HSTM;^EBbphU})NxstsPG^q9%D}rtXGwBtRo8kDEmaR{;?W( zi`97iV^K}NK5qv(Gfx!WBlD)JU_1pJax(H}Qry7*a|2JZGOxF#5|68%RMfX$YWI&7 z7}tw)^_J$_A6$5R=Hr5#7>pxdIDz-)1fNGouA9GhK;66?=hDn73w*B(Z_mpf{7F0H zX_rR3ZIRnv3fr~8c-9*DVM*{it$?RmVmp=?51S+JsRZ(!iUaQ~>dpKrGv0orDR`A8 zdOiT>dlIENOzJuSYUrRT%7l!#QBz*jQ$euT^u)PR?v@cY>RFN0*z;67%T?8sc4L3=%s?cpR&xl zHWlp_wsPi^3jSScdL^(*e5iJon97v(G*^!tjAuqZk%wcvxxb4N`4LJ zOlzS}*P>lo=nJ*TThk&}NQ-`~1um-vukdS}k@>Sa=$LizE0cZ9bkMCTy6jF;19iZ& zb$UK9w_67tt`75c9dLqz{Ue!gnhm@|&W+2~=gqT^fr2kGU-;YjBKvG8xi^{2_&W`+Pt1fx2AXd_^Z`q@)%nr*{Sao za$V?fcKflZ)Km(*oKB0PPHug2c?NYpeBpk?G=JK5>%9HqMziUW>P3@=MFVK_uw573 z3(cjWEvL=2G@M7Xmj~I7EdDdCs3kHD75<|HC-ztPkDB6TK2%N)L=NIFWcP02PfKbq zA<5ov>Qai_vg1?W1jiKI0U#{2yMB3;sY&OPirgf2z}6Y11*~o z*mA1nM$)_~XB2-&@qIje(Z|2?h|MI?7He-Iku7Tfc?-RIcE3}tD_coK3$r?gQga6C zNJRP8R}7>2`S*fsg2PBuEkDi=Bje85g?xWfaK~pqUae}@DI9)?;Z*eD!Htn#+i6F( zNT}RSQ^O8)aILn3l18pA92KqPT*luyM2~kxzy~mrq!`Nsk|P&IjkUXhiwS=74T}uh zJ9RIe_}n9YsB0`q^6Q{j_*=%oe^&6DFX~Rwx;UD)&+l{}|9F~}aCzBpW(oAX!*7G~ zwk4~M|m8)!sEb|Pe5mWlFpel-q?NXDH7e{Peh$Y zzQP&GwGbU9Q{aDaj;5q-vf6RvJdFq(+W%q8i+H|W!t?bC)=Pyi|25=+UZ*_qF%*A; z9*z=w>@DETx1pcD10TwJ;P*cu5k2hL_Yri}zfx*~7_6EGKa{7y(Vs!r{hTIA#_}&o zvcD|)8a^h!QDP~vaQBw@`TAa;x8@)PRb}X(8#{&ctRa?J`unVWALBY;F8uxT@Epm9 zFaKxMqYQu_8Uk-K!uZTsulL~bjwy87MNw}p4&I_U@+>VeuCel#^cO9xd0cwZ2L9i+ zjEC9V0Y9{dzkFGY=gPCrrGXRUanqdjKH{v)seo}7>fbXe>-9Q3Uh&Y6gQe$gKn?I2 zYXZls%{<0Ub$DD`+LJ$zt;hR4v;o%h0uK8FkM}w@VV*!6Z{GgAru@BB_&?Tf0UXqa z$IabZVI1C?zxSpM^9NqF1CO&KzwYeB>p$7(`E?L- zF9-F<``|ymg#V-K5FYPN8Oooh4TH|T9P4xzI%9laf!o~xKAHw@jEny0j&W`kEJKfF z0pIu;%6x?VpQ>_uPgdpgyS^%L*Qz-F9%v_C4Ltb$@l}9RyW@B(x+~Uk!EfHRGTQMq z|3U5-oZIHg^M<=F>=#hc1%B?%=%-HLCpa-L;bVEslN^|DyQrKu`(l*Ee4vcCkI1#mL!IIS z{AhBa*U5oCD;xEmZ2fqQb$nXX=e5XH$wHk~$yMZBT@85O8sq?K^nU8>gOh=}Z-(BV zUG{C~@sW~u$@jfFYTSR-s6(kqvOg}SCebbCZn}yZNruQO+<#T@KT_fO zs(dcbQ~18Grb3Sm1;-6F>O*Se91DDODK}dUKDnA6EY2UEEzE~_!j+EwRDAN~d`wwK z#=b)7cn+mwy#2@ZSO(JHe?I?U-JAxz0*!vY_$A+gc{!Qjy?pIYFZ1!)_ahU>Aq(|B zB^Q;CLzce3NIb1oS@2iN0$)E1{ore!!+9}wrG^%{j#@m|wCKlQ`$5U`WNu%1{}>-5X}e=6!U1>Lpf>vd2o-n)X<`@6kg5HH>r zcWe20e6M=esG)p*(+|?dRkJee-T2Xf>w(l)5;`v?PsuQF30W4|GSgz+Qt--_0iO<{1EPJN?+Wt$G$`#r_6oW^ z?oevKNFmt4Zknobzm*hyqHb|Vt5sC;#|(Fav#Y3kd&|j=0jnvbMvdc5yw)Ipa}CF4 z#;v8D9-@MH9eEDDHfc)j5IVNOsPM$B5ZbSL8Et+*;XTg1YT-J+)kb3d*fW@QPUU_z(PTR9z)d&H*^~uv77u}_7s?%d+4LXV#8T3d+Ex~t3p!a zUJ6>~eR$8nSejD5M$a2Ve|LTx2r@fgi7ArkD5(=xaBC63lSK_a`<(Cj35gePgG z_;c@1p}ugM1kXspdH5{q2q`3hhk}9dIq)Sf&>MjT=@)a6lIHsh(4gY`$o%tE;CR=- zyT6Xy%p35DyoGtAhJWN6;Eh7=jFe}iLj5Wo^S%tdZ!p&b<(xUW?j!q6-V-G`;Ogaef*37>Ck;Eb{_ zjxF+OkbCJ_26f|d&~KN=?*b><=FIp|z6bp`gDGkaa_Hj$$?7E68UoR}1@B z8}HZQ{c7Whx-|6HVZa|}cme-J?&bO>jHmf|^Y>$#qFv1xR~*@b-+$-BuS;9;YrEEr zn|ZVa&$2xqkM14$I9~7ME#2oWW!-gG#-FZrUJC_Dx zJJ4Ns0{$2=lyN=l;qW&qi@ZiB=!{%(T;Qi!2Rf`MH{RcC?!Z-LUwGLs-UE0saLC4r z&Wh`7z#p%9FrGU@#xIdex*C4>MHSuyOZL259$Z_>X@AUXu@9(?>j~^KhT}06ZiY_)re9-*~njSCM_Y zSx=@#omZ)A%eouZjbs8>Q+%Je-mKBlLM@ z*Xd$;!V6PXht0s}XzQI({VeJ)E7+Wr@fD@@`tQZHDpu+P(1>ay5cmOIAOriuO zg9>#o73xoFu7N!9S_Nk=_h!A<4;V4oo+&y#(4(t(4fBX2Ps zKIR$l`6$>Aig`sD@a@Wgzn2EMpW^q=IPSN7=(&EC37jkwz9yN_F=YbpRdiOIx1jJI z`21!8f6YR_%0hmCf;)13>uY_LoTtXT6|J7%FXtR^9Zumpa89VAt74o^3x9qsj*Aw& z94(%&Ivk&Z^;G{U&w=?m-_}uayR-2;&PJVA@quDKOE&mPiVqauClw#4FLN?E|5fpU z;&DL^>IAY5;%j~b`;o~$EjjSj&p|)Tq3<^zAJp-$FdzRGZZ@br?}a=M{|7hwd*Nn` z*O(Zj!=EM)xj?e-%$I(kIau#C`~&3mzT`<87)c{WgPOqMKE&c_vL=+ z2E4-(>*aj0UV1-XFRBCjG1d#k_vGIVox-1|58+oiPtOVKb8G+S|H^#vFWdcx@W)<% zCj2q9J0H0}cb(u%{IOFzZgoLtR)62?`}^w^^!@+V_Y1-w&*3_g_xpbvf0VcTKYiWR z%qVW`%kk9p>by>mQ~aovgF{c(LlbDo@Vc7mXC~4{!}Xhe)RU-_!I^U_8&09fialDo zZk zR)nd_29ack=e2?kboJ`>`PB+aO!FDobVD%3{UjorD``<35kXu<{d21d)`6?2t^_Eq z248RuRSx|nR*=w=k3`5@OG9oi3EMPk9f_#a`YItbO^jE07XtieJvFOj->}$BMRz^j zHS?Tf@lBL0xK@VTRq)5zLaNKi>04-B50UA(m4bFw3Or~LN@fk_SMi(~iuQ(5Xub## zh7t3u!|1_Jr8m5-yNxz=5(B%pQGY3bC7hPjE-OHr;Uu=^uBni7J^I9wqw}@{AKOme zx*6FiGk1{d$iW>OecVA4vvP!_XuV_*FibPUMz&oufD3aD>sOwZO7e#^y-MU{) z6qOUzy1BcB@Ky~d4B#C#)(`fM?oI`VxI)t+Fh+jnX|txs>8e>gfB zd_g7eT6A$NbNmq1mVns9@KHTVQf$n+W5{amzmfpD3sKikNV<%=Kc!021oat-u9eNpy#R0f zB}s8MeO^=CF){Gw4S1jLsDlLP3iD%WLX{4kM23Do&pyXldfy7>gULMZT=3HKFmKE! z=7D@B_9H0-A8kY6AV$EYj9D*jX@d7nfnO8_Ppdd^Aq(I#a;{%V;49YP-PwSrWy{;? zYX^L$408I)v3|y{Jm>QbbAs-~8GJKW;8=3bp{%=xFZp73J3|=AQ#Il3O-1fZTvLAEs5yUsTnoneGQodb z-HMmHwq~AT-M0Mw`t5nUgE}&9d8ZTOY^9*P9^Dn~?#9P;0CH!Hkb8Z$H*iPzKgRTD zzTrLaA8nz#?lFYlkB0u*emHU-%P_80&k4uDh1+9L5z9(0ro>Yd^iY!T_h1<>^Z+jC z0o>Dr@zJ-+tHirak#S(;Y1Wa~uY%)V1%6V%HybFvPt1?24E$EnU9qocMf4llx2gj8 zj=)hXxdOLyVL$it&dj?l?~M1IkfY>?{#_n;rvvMyK0$YN7r6K#=&mB{(0@zAkJJ{v z?xpxVC)nV4ScC5g-eb9v$jO8s>T*l;YYX&ybNCn(hwoD{V%_?{_pD@~x^ zD#E{8$Jm>%`@;C15&Ekk^j(GUy+ZIeFaSUGGxRr~fM?|cANvTLD-X*bfIH;^_sh}e z^U40(%s4J`w}s4F#~==8G799*^Z5;onq6W&q;@F zCtc4g6st~ekE>~J;WI(CrmC?&YVh{ddcP*d^;Gm;j1k+Q_&rIsz;jgKxvOaD1Cija zA`|IBp@MI(iWZBbj(8OX&(8B2e?^7dF%{}JYT&kNI{2e_$5-RIr3QapP35Hrle$10 zQr49*4wnwUUIm97BpG0R?Mu%*#0=!Z zq(Oa8gZ)%+$VIkd!eqfXq>MYWt}_!jXu&un?|&BRtY7mV*?&smKXQ($7X4ETpE51* zJgwf3jD4sI)?J;r5GE)}v}m6W`Y;{FA37W-9j+H0c)>d0_XYbpabAKB{rGF%Bl9-1 zk>mM)&wJz?2*sD4d8dM}Jbc~QUo8j6KL_I=1&{oG_+uIv8Gr8i__y%KkU>1}*3ZM& zNh1maUw$!2ea!zEh2^w5jOYYn*>ol^N6DXG<>hl&PPJvg>b3m&kGyOOU??@7m))?O zX2O7wFP7~(@$x7v_u9_Of%50?csWY`+`F*!OXuXz19|zi{P{y(HU*AmSAp?HH!Sy> z_V>acW!&sb9Pba|X2<_bxS7+KZ{cPQ|Aam}fdhXZ57S?-gMWWLTy}q(m+yD~A2j~2 z(60)@5iRlbk~_x#HjXIYSH8sk|ImG<=5p_E@qyW&aXig6^?UJdvmf0Yyr6HBl@q8# zqV0&V%@dKAtK?sshdWL4pE;FU-*XvV|HCwTui0(!cG(O{E+QsJ`%|<{qcV#=%pxbZ z{qJYqoCAJe02!G&w%PZ5E|u>jDyHYrwO8RwlMUw6Yu(DTqZ}5{#cI13o^HGlxZfh= zy#xXe`-S$Je%im%VF@k1oRSzeWGM+@EorKlWfbN0d_;1gAethu3e&2sATb5{+5HvB zQx2w&c}t6#G+Rl-ceHjFehYqrt7uO9+fj=~t)`PTw3!huYiMHiGu?;(x(5D;YiZB0 zl$K5d)=@3L&FeE*%BTjRfpVP%3XAuNfa7N6<$47XB!ZCj}sI zD}6kBXG`yrp%n9U*(KLGp(M$d-z&K@S3Zt0x4aZay@fOwyC&PHjG)pUAGeJJu&@2d z%HcGnwwPcoZ`3Gh`r56wiWJlLGzmd1@yaI$ogm5<%t?_yw1#p^%zWH{dD_biZhs zaxj%7`f18FlHkF&*C{MVG#I%Fp295>z(*lS?KXI=cfqT?4<6LLN|F70iE(I@?x= zl*@wehCKhu*84{@4=N9QrhM=(KSK{zh;_;R41q5ifv0H9emMC>;74N$K3q}YEycl) zv|t|NAxp-6%w*n|HS-`dZ5W4JZHv4?JKj!%GRUz}@W&C-pA+Zc>~vj|F={fBXaR zr6%}&Z(jdkQ^u{#oAZ85YXLr_4{vu%D{Q|tzcy*hI9}8Ce7weVzkg?~&t2mAeo5w0{$vGw z(bAiJeJp^7ntL-}sRZ&Z75*dpC7IzkeCbexC;0&A{(v==pw}ld13nW!B)&^$6&@t>?p5?^sYtL_LHDadeMhDDi<0Q-f{vU0&6T`NK3{6eo-7)C zsL5J-Kq$GGe4Z8lBcH!?9EWuH2Pyh%_E{-dfBm20jtsdkNy-yhHe3cwb z+3$(_Sr+imuX8Z@IB4-))`E|z1y5H?%m-C`o@Bg{kBfpg^7X1iztduik^BAsef}l$Ide#t+N4MNgYndFQvA&s$NXsT z<+E)rB}|~es@G39IzEvez1@Da>U)L%;L^28;qKv6X~wQS%{?nlrzD#dIyydsrv5x? z_o#{fbTqsEsJ%^Q)Bei7W2agKQ04_~()yxvY5vXk?>sE#QQ0={efA0ZE0ap~7sq(c zM^57cO0(Q~^WEHq)I~Bcd_s0{=lAKGzRJzZU$S#yz^+)nOZnvzol%Z6wK+%);qx?nZ$L5l$iDDe9j-gp<_F zDch<2(R;!#ZKs-|jBN4_n!|yR^uq{Isip89K1p``kZIhg{7>5>rek*d~!%>pSg^-b*5NcQHA2KUqi<$z(hq6x|i` zr4_$W?1 z;b%4u=g-hxaXP0v3%<=cb^deX$< zCj9hnQMBM{Xg&B2_!@WNLvzHBuS`78s67a>eK>oKC{5MNt9Au69Zz<+O zg<`I=px0c7NRd~E^EazTU=W)GP zO{`yw$E6o)^Rj1M9`_#cM18+LkAGboVm{S~$JJJiF+L`I-<#|G#hUT>b4YWZ|J-cB zOi4@7;&T z-&OnZ=M4wobr8Rf9?YM|fd61NjN273-1}Sgn$+oxI_mM?f9f^TBi>i8=N#wy%_zB^ zV^c)>JW&3;A1_B?dBq-HK8NK{BR;;b<Xg9 zpfe?3H+D0Bf4zdf|KIxl_v=?_^ZyF{>c90o|Fd6z?jyiDMp^&vz~h~v&hVpmaL+36x0LfSfiJdF_>O!uu$&;{me6s(L|*v_cOL&dlzs2rz(cK! z@myt$&t$!QMZ8~;$4fmcu-{>{E92jJF5Iq;E{rE`m-YKjtiSH%guF;c@CVC-_gIec z_8VoHZx~mGeFfIq^Y1ONLyl!>_|w}W*S!>Ykv2R&-fxZlDT#4pN%kf1w&LHJZHXL8 z3ylBFF|I8Re6Se&2a3Xv)eQKgDSQr0;2&88JV;~U_l2P&H^O<8eH048S5oFT8vu9x z44mZ?aI}2jL?2O)$iwmne4dMWOpe|MTlUwMahzI`F}fDIO?e)Yh52$Owv!3p3Wa~i z{5U1IQTA8oJiv7D!j*hT#);CwS4*eWix%{`aahqm%ew2Ju9GUP`>gmo%KSxlNhqNr z(dFagA^}%SbrCElRhYLa{72C>_|;MsiR$gLTU6j9Dn60iJ{9Is3f?LE-b-)AjzBtUs3Ldl|rqGvKqH0o*M^kK;1`I|Dl7488w6 z^XE0d*AyR4=9y~rejbebX|R8p;FT&kGW!x{0xwhWN6uHw)aMTTR!Qs`3Llnn*DTDB zzves2xt6l-I<$<)U{rkOxsIkq9qntMNA?H!Hts0rwlaFZf4`uv^l2io9x`yeGtu zHabKf&0I2pO8I%6@3C$o#n{_FuYPh84KD3t;a_|T)fscNO_M1K|KWN2*-JXCok4eDgn=%Kqq%;$+A$VFUFbDKwXNif+!)yz5xR_Gf@WD5(|7;z4y zfmpQ5cm!eZ|IWZy4E1z}z-! zA0-)dMy$hXY4FKs?w@SVRO`K*@F4hn3$ywQ%IcaZtW z*`6k*5oEa4v88EH1g#fo2KEZ?LC(3{@3X!{?ekGIKIuTM#)Ac)`R3A{PwzL+ypCOz z?7GSJ@atXh-HM@R&W7e;ZFbW_0YyDtcn{qd<3P^rA#w<^k6OByf|FCOFRC6(m6l!e z+PNW?W^@fMI<#0EiASx^+&K8^$00XV@tdzG3Ct3xt>CUYYSwU%WSsG~Q3cMS9Ae{Up%~_9r9%QPEu$tKc?!>48JwPaG!6uA}Tx3VJRE zOCF;&H_b-5j8%M}IFIrqu9uV4Q9uDt-8e<6KFylEzIPfvOlPREz_NeokOI8>9Q^9f zgD-KBy4S2CSP@^s^?8N7B;%!2@Gq{>V#lGvCa=R!{stx1&pA14=S}2z+@@iId%e-L zJH+*{d-~iix|RX_WeNdr zG{m^3FzVRG%tIJs0vyf^zTCyYk0^ohmj!qaR$SlhUy||3i`Kw5OJSU6i#oU+ey>B_H9Dlk4b1LM&;ZWss4`k<;9S626y#=qY1ou5&Q*SlI9 z_+DM$fu1}L9917aO%1WVMm&zQZ_Mp&Mfkoq?e`?yD+n?Hl-}i_9s%0PSUqAl6mID}X`~kU_V+Uh? QFoeHvIgHm^INbaH0UNexG5`Po diff --git a/src/material.cpp b/src/material.cpp index 13b80ac97..277a568ea 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -509,8 +509,7 @@ void Material::collision_stopping_power(double* s_col, bool positron) double r_e = PLANCK_C / (2.0e8 * PI * FINE_STRUCTURE * MASS_ELECTRON_EV); // Constant in expression for collision stopping power - double c = 2.0e24 * PI * r_e * r_e * MASS_ELECTRON_EV * N_AVOGADRO * - electron_density / mass_density; + double c = 2.0e24 * PI * r_e * r_e * MASS_ELECTRON_EV * electron_density; // Loop over incident charged particle energies for (int i = 0; i < data::ttb_e_grid.size(); ++i) { @@ -530,8 +529,8 @@ void Material::collision_stopping_power(double* s_col, bool positron) double F; if (positron) { double t = tau + 2.0; - F = 2.0 * std::log(2.0) - (beta_sq / 12.0) * (23.0 + 14.0 / t + 10.0 / - (t * t) + 4.0 / (t * t * t)); + F = std::log(4.0) - (beta_sq / 12.0) * (23.0 + 14.0 / t + 10.0 / (t * t) + + 4.0 / (t * t * t)); } else { F = (1.0 - beta_sq) * (1.0 + tau * tau / 8.0 - (2.0 * tau + 1.0) * std::log(2.0)); @@ -573,16 +572,11 @@ void Material::init_bremsstrahlung() double Z_eq_sq = 0.0; double sum_density = 0.0; - // Calculate the molecular DCS and the molecular total stopping power using + // Get the collision stopping power of the material + this->collision_stopping_power(&stopping_power_collision(0), positron); + + // Calculate the molecular DCS and the molecular radiative stopping power using // Bragg's additivity rule. - // TODO: The collision stopping power cannot be accurately calculated using - // Bragg's additivity rule since the mean excitation energies and the - // density effect corrections cannot simply be summed together. Bragg's - // additivity rule fails especially when a higher-density compound is - // composed of elements that are in lower-density form at normal temperature - // and pressure (at which the NIST stopping powers are given). It will be - // used to approximate the collision stopping powers for now, but should be - // fixed in the future. for (int i = 0; i < n; ++i) { // Get pointer to current element const auto& elm = data::elements[element_[i]]; @@ -591,7 +585,6 @@ void Material::init_bremsstrahlung() // Get atomic density and mass density of nuclide given atom/weight percent double atom_density = (atom_density_[0] > 0.0) ? atom_density_[i] : -atom_density_[i] / awr; - double mass_density = atom_density * awr; // Calculate the "equivalent" atomic number Zeq of the material Z_eq_sq += atom_density * elm.Z_ * elm.Z_; @@ -600,13 +593,8 @@ void Material::init_bremsstrahlung() // Accumulate material DCS dcs += (atom_density * elm.Z_ * elm.Z_) * elm.dcs_; - // Accumulate material collision stopping power - stopping_power_collision += (mass_density * MASS_NEUTRON / N_AVOGADRO) - * elm.stopping_power_collision_; - // Accumulate material radiative stopping power - stopping_power_radiative += (mass_density * MASS_NEUTRON / N_AVOGADRO) - * elm.stopping_power_radiative_; + stopping_power_radiative += atom_density * elm.stopping_power_radiative_; } Z_eq_sq /= sum_density; @@ -661,12 +649,13 @@ void Material::init_bremsstrahlung() // photon energy k double x = x_l + (k - k_l)*(x_r - x_l)/(k_r - k_l); - // Ratio of the velocity of the charged particle to the speed of light - double beta = std::sqrt(e*(e + 2.0*MASS_ELECTRON_EV)) / - (e + MASS_ELECTRON_EV); + // Square of the ratio of the speed of light to the velocity of the + // charged particle + double beta_sq = e * (e + 2.0 * MASS_ELECTRON_EV) / ((e + + MASS_ELECTRON_EV) * (e + MASS_ELECTRON_EV)); // Compute the integrand of the PDF - f(j) = x / (beta*beta * stopping_power(j) * w); + f(j) = x / (beta_sq * stopping_power(j) * w); } // Number of points to integrate diff --git a/src/photon.cpp b/src/photon.cpp index 49b050c61..07753ce79 100644 --- a/src/photon.cpp +++ b/src/photon.cpp @@ -219,15 +219,6 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) read_attribute(rgroup, "I", I_); close_group(rgroup); - // Read stopping power data - if (Z_ < 99) { - rgroup = open_group(group, "stopping_powers"); - read_dataset(rgroup, "s_collision", stopping_power_collision_); - read_dataset(rgroup, "s_radiative", stopping_power_radiative_); - //read_attribute(rgroup, "I", I_); - close_group(rgroup); - } - // Truncate the bremsstrahlung data at the cutoff energy int photon = static_cast(ParticleType::photon); const auto& E {electron_energy}; @@ -240,26 +231,10 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) double f = (std::log(cutoff) - std::log(E(i_grid))) / (std::log(E(i_grid+1)) - std::log(E(i_grid))); - // Interpolate collision stopping power at the cutoff energy and truncate - auto& s_col {stopping_power_collision_}; - double y = std::exp(std::log(s_col(i_grid)) + f*(std::log(s_col(i_grid+1)) - - std::log(s_col(i_grid)))); - xt::xtensor frst {y}; - stopping_power_collision_ = xt::concatenate(xt::xtuple( - frst, xt::view(s_col, xt::range(i_grid+1, n_e)))); - - // Interpolate radiative stopping power at the cutoff energy and truncate - auto& s_rad {stopping_power_radiative_}; - y = std::exp(std::log(s_rad(i_grid)) + f*(std::log(s_rad(i_grid+1)) - - std::log(s_rad(i_grid)))); - frst(0) = y; - stopping_power_radiative_ = xt::concatenate(xt::xtuple( - frst, xt::view(s_rad, xt::range(i_grid+1, n_e)))); - // Interpolate bremsstrahlung DCS at the cutoff energy and truncate xt::xtensor dcs({n_e - i_grid, n_k}); for (int i = 0; i < n_k; ++i) { - y = std::exp(std::log(dcs_(i_grid,i)) + + double y = std::exp(std::log(dcs_(i_grid,i)) + f*(std::log(dcs_(i_grid+1,i)) - std::log(dcs_(i_grid,i)))); auto col_i = xt::view(dcs, xt::all(), i); col_i(0) = y; @@ -269,7 +244,7 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) } dcs_ = dcs; - frst(0) = cutoff; + xt::xtensor frst {cutoff}; electron_energy = xt::concatenate(xt::xtuple( frst, xt::view(electron_energy, xt::range(i_grid+1, n_e)))); } @@ -279,6 +254,25 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) if (data::ttb_e_grid.size() == 1) { data::ttb_e_grid = electron_energy; } + + // Calculate the radiative stopping power + stopping_power_radiative_ = xt::empty({data::ttb_e_grid.size()}); + for (int i = 0; i < data::ttb_e_grid.size(); ++i) { + // Integrate over reduced photon energy + double c = 0.0; + for (int j = 0; j < data::ttb_k_grid.size() - 1; ++j) { + c += 0.5 * (dcs_(i, j+1) + dcs_(i, j)) * (data::ttb_k_grid(j+1) - + data::ttb_k_grid(j)); + } + double e = data::ttb_e_grid(i); + + // Square of the ratio of the speed of light to the velocity of the + // charged particle + double beta_sq = e * (e + 2.0 * MASS_ELECTRON_EV) / ((e + + MASS_ELECTRON_EV) * (e + MASS_ELECTRON_EV)); + + stopping_power_radiative_(i) = Z_ * Z_ / beta_sq * e * c; + } } // Take logarithm of energies and cross sections since they are log-log From 9e8e5a08b52108eb58008eca4179cbed813db847 Mon Sep 17 00:00:00 2001 From: amandalund Date: Tue, 5 Mar 2019 09:05:09 -0600 Subject: [PATCH 005/165] Address @paulromano comments on #1186 --- include/openmc/material.h | 14 +++++++------- src/material.cpp | 14 +++++++------- src/physics.cpp | 6 ++---- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/include/openmc/material.h b/include/openmc/material.h index 3497d0f38..6a3461e0b 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -95,7 +95,7 @@ public: std::unique_ptr ttb_; private: - //! Calculate density effect correction + //! Calculate the collision stopping power void collision_stopping_power(double* s_col, bool positron); //! Initialize bremsstrahlung data @@ -113,14 +113,14 @@ private: //============================================================================== //! Calculate Sternheimer adjustment factor -double sternheimer_adjustment(std::vector& f, std::vector& - e_b_sq, double e_p_sq, double n_conduction, double log_I, double tol, int - max_iter); +double sternheimer_adjustment(const std::vector& f, const + std::vector& e_b_sq, double e_p_sq, double n_conduction, double + log_I, double tol, int max_iter); //! Calculate density effect correction -double density_effect(std::vector& f, std::vector& e_b_sq, - double e_p_sq, double n_conduction, double rho, double E, double tol, int - max_iter); +double density_effect(const std::vector& f, const std::vector& + e_b_sq, double e_p_sq, double n_conduction, double rho, double E, double tol, + int max_iter); //! Read material data from materials.xml void read_materials_xml(); diff --git a/src/material.cpp b/src/material.cpp index 277a568ea..7b000db7d 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -573,7 +573,7 @@ void Material::init_bremsstrahlung() double sum_density = 0.0; // Get the collision stopping power of the material - this->collision_stopping_power(&stopping_power_collision(0), positron); + this->collision_stopping_power(stopping_power_collision.data(), positron); // Calculate the molecular DCS and the molecular radiative stopping power using // Bragg's additivity rule. @@ -948,9 +948,9 @@ void Material::to_hdf5(hid_t group) const // Non-method functions //============================================================================== -double sternheimer_adjustment(std::vector& f, std::vector& - e_b_sq, double e_p_sq, double n_conduction, double log_I, double tol, int - max_iter) +double sternheimer_adjustment(const std::vector& f, const + std::vector& e_b_sq, double e_p_sq, double n_conduction, double + log_I, double tol, int max_iter) { // Get the total number of oscillators int n = f.size(); @@ -993,9 +993,9 @@ double sternheimer_adjustment(std::vector& f, std::vector& return rho; } -double density_effect(std::vector& f, std::vector& e_b_sq, - double e_p_sq, double n_conduction, double rho, double E, double tol, int - max_iter) +double density_effect(const std::vector& f, const std::vector& + e_b_sq, double e_p_sq, double n_conduction, double rho, double E, double tol, + int max_iter) { // Get the total number of oscillators int n = f.size(); diff --git a/src/physics.cpp b/src/physics.cpp index 6e7620020..8a16c2ae6 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -271,10 +271,8 @@ void sample_photon_reaction(Particle* p) if (E_electron >= settings::energy_cutoff[electron]) { double mu_electron = (alpha - alpha_out*mu) / std::sqrt(alpha*alpha + alpha_out*alpha_out - 2.0*alpha*alpha_out*mu); - double uvw[3]; - std::copy(p->coord[0].uvw, p->coord[0].uvw + 3, uvw); - rotate_angle_c(uvw, mu_electron, &phi); - p->create_secondary(uvw, E_electron, electron, true); + Direction u = rotate_angle(p->u(), mu_electron, &phi); + p->create_secondary(u, E_electron, Particle::Type::electron, true); } // TODO: Compton subshell data does not match atomic relaxation data From 4f69e3474e9366993f02e894d05cfb80015713dd Mon Sep 17 00:00:00 2001 From: amandalund Date: Tue, 5 Mar 2019 19:16:38 -0600 Subject: [PATCH 006/165] Update photon physics documentation --- docs/source/methods/photon_physics.rst | 170 +++++++++++++++++++++++-- 1 file changed, 158 insertions(+), 12 deletions(-) diff --git a/docs/source/methods/photon_physics.rst b/docs/source/methods/photon_physics.rst index 028a71de7..bde6d2a99 100644 --- a/docs/source/methods/photon_physics.rst +++ b/docs/source/methods/photon_physics.rst @@ -728,10 +728,18 @@ the cross section differential in energy loss. The total stopping power power :math:`S_{\text{rad}}(T)`, which refers to energy loss due to bremsstrahlung, and the collision stopping power :math:`S_{\text{col}}(T)`, which refers to the energy loss due to inelastic collisions with bound -electrons in the material that result in ionization and excitation. To obtain -the radiative stopping power for positrons, the radiative stopping power for -electrons is multiplied by :eq:`positron-factor`. Currently, the collision -stopping power for electrons is also used for positrons. +electrons in the material that result in ionization and excitation. The +radiative stopping power for electrons is given by + +.. math:: + :label: radiative-stopping-power + + S_{\text{rad}}(T) = n \frac{Z^2}{\beta^2} T \int_0^1 \chi(Z,T,\kappa) + d\kappa. + + +To obtain the radiative stopping power for positrons, +:eq:`radiative-stopping-power` is multiplied by :eq:`positron-factor`. While the models for photon interactions with matter described above can safely assume interactions occur with free atoms, sampling the target atom based on @@ -754,14 +762,97 @@ power is calculated using Bragg's additivity rule as S_{\text{rad}}(T) = \sum_i w_i S_{\text{rad},i}(T), -where :math:`w_i` is the mass fraction of the :math:`i`-th element. The -collision stopping power, however, is a function of certain quantities such as -the mean excitation energy :math:`I` and the density effect correction -:math:`\delta_F` that depend on molecular properties. These quantities cannot -simply be summed over constituent elements in a compound, but should instead be -calculated for the material. Currently, we use Bragg's additivity rule to -calculate the collision stopping power as well, but this is not a good -approximation and should be fixed in the future. +where :math:`w_i` is the mass fraction of the :math:`i`-th element and +:math:`S_{\text{rad},i}(T)` is found for element :math:`i` using +:eq:`radiative-stopping-power`. The collision stopping power, however, is a +function of certain quantities such as the mean excitation energy :math:`I` and +the density effect correction :math:`\delta_F` that depend on molecular +properties. These quantities cannot simply be summed over constituent elements +in a compound, but should instead be calculated for the material. The Bethe +formula can be used to find the collision stopping power of the material: + +.. math:: + :label: material-collision-stopping-power + + S_{\text{col}}(T) = \frac{2 \pi r_e^2 m_e c^2}{\beta^2} N_A \frac{Z}{A_M} + [\ln(T^2/I^2) + ln(1 + \tau/2) + F(\tau) - \delta_F(T)], + +where :math:`N_A` is Avogadro's number, :math:`A_M` is the molar mass, +:math:`\tau = T/m_e`, and :math:`F(\tau)` depends on the particle type. For +electrons, + +.. math:: + :label: F-electron + + F_{-}(\tau) = (1 - \beta^2)[1 + \tau^2/8 - (2\tau + 1) \ln2], + +while for positrons + +.. math:: + :label: F-positron + + F_{+}(\tau) = 2\ln2 - (\beta^2/12)[23 + 14/(\tau + 2) + 10/(\tau + 2)^2 + + 4/(\tau + 2)^3]. + +The density effect correction :math:`\delta_F` takes into account the reduction +of the collision stopping power due to the polarization of the material the +charged particle is passing through by the electric field of the particle. +It can be evaluated using the method described by [Sternheimer]_, where the +equation for :math:`\delta_F` is + +.. math:: + :label: density-effect-correction + + \delta_F(\beta) = \sum_{i=1}^n f_i \ln[(l_i^2 + l^2)/l_i^2] - + l^2(1-\beta^2). + +Here, :math:`f_i` is the oscillator strength of the :math:`i`-th transition, +given by :math:`f_i = n_i/Z`, where :math:`n_i` is the number of electrons in +the :math:`i`-th subshell. The frequency :math:`l` is the solution of the +equation + +.. math:: + :label: density-effect-l + + \frac{1}{\beta^2} - 1 = \sum_{i=1}^{n} \frac{f_i}{\bar{\nu}_i^2 + l^2}, + +where :math:`\bar{v}_i` is defined as + +.. math:: + :label: density-effect-nubar + + \bar{\nu}_i = \nu_i \rho / \nu_p. + +The plasma energy :math:`h\nu_p` of the medium is given by + +.. math:: + :label: plasma-frequency + + h\nu_p = \sqrt{(hc)^2/\pi r_e \rho_m N_A Z / A}, + +where :math:`A` is the atomic weight and :math:`\rho_m` is the density of the +material. In :eq:`density-effect-nubar`, :math:`h\nu_i` is the oscillator +energy, and :math:`\rho` is an adjustment factor introduced to give agreement +between the experimental values of the oscillator energies and the mean +excitation energy. The :math:`l_i` in :eq:`density-effect-correction` are +defined as + +.. math:: + :label: density-effect-li + + l_i &= (\bar{v}_i^2 + 2/3f_i)^{1/2} ~~~~&\text{for}~~ \bar{v}_i > 0 \\ + l_n &= f_n^{1/2} ~~~~&\text{for}~~ \bar{v}_n = 0, + +where the second case applies to conduction electrons. For a conductor, +:math:`f_n` is given by :math:`n_c/Z`, where :math:`n_c` is the effective +number of conduction electrons, and :math:`v_n = 0`. The adjustment factor +:math:`\rho` is determined using the equation for the mean excitation energy: + +.. math:: + :label: mean-excitation-energy + + \ln I = \sum_{i=1}^{n-1} f_i \ln[(h\nu_i\rho)^2 + 2/3f_i(h\nu_p)^2]^{1/2} + + f_n \ln (h\nu_pf_n^{1/2}). .. _ttb: @@ -891,6 +982,55 @@ direction of the incident charged particle, which is a reasonable approximation at higher energies when the bremsstrahlung radiation is emitted at small angles. +----------------- +Photon Production +----------------- + +In coupled neutron-photon transport, a source neutron is tracked, and photons +produced from neutron reactions are transported after the neutron's history has +terminated. Since these secondary photons form the photon source for the +problem, it is important to correctly describe their energy and angular +distributions as the accuracy of the calculation relies on the accuracy of this +source. The photon production cross section for a particular reaction :math:`i` +and incident neutron energy :math:`E` is defined as + +.. math:: + :label: photon-production-xs + + \sigma_{\gamma, i}(E) = y_i(E)\sigma_i(E), + +where :math:`y_i(E)` is the photon yield corresponding to an incident neutron +reaction having cross section :math:`\sigma_i(E)`. + +The yield of photons during neutron transport is determined as the sum of the +photon yields from each individual reaction. In OpenMC, production of photons +is treated in an average sense. That is, the total photon production cross +section is used at a collision site to determine how many photons to produce +rather than the photon production from the reaction that actually took place. +This is partly done for convenience but also because the use of variance +reduction techniques such as implicit capture make it difficult in practice to +directly sample photon production from individual reactions. + +In OpenMC, secondary photons are created after a nuclide has been sampled in a +neutron collision. The expected number of photons produced is + +.. math:: + :label: expected-number-photons + + n = w\frac{\sigma_{\gamma}(E)}{\sigma_T(E)}, + +where :math:`w` is the weight of the neutron, :math:`\sigma_{\gamma}` is the +photon production cross section for the sampled nuclide, and :math:`\sigma_T` +is the total cross section for the nuclide. :math:`\lfloor n \rfloor` photons +are created with an additional photon produced with probability :math:`n - +\lfloor n \rfloor`. Next, a reaction is sampled for each secondary photon. The +probability of sampling the :math:`i`-th reaction is given by +:math:`\sigma_{\gamma, i}(E)/\sum_j\sigma_{\gamma, j}(E)`, where +:math:`\sum_j\sigma_{\gamma, j} = \sigma_{\gamma}` is the total photon +production cross section. The secondary angle and energy distributions +associated with the reaction are used to sample the angle and energy of the +emitted photon. + .. _Koblinger: https://doi.org/10.13182/NSE75-A26663 .. _anomalous scattering: http://pd.chem.ucl.ac.uk/pdnn/diff1/anomscat.htm @@ -906,3 +1046,9 @@ angles. .. _Kaltiaisenaho: https://aaltodoc.aalto.fi/bitstream/handle/123456789/21004/master_Kaltiaisenaho_Toni_2016.pdf .. _Salvat: http://www.oecd-nea.org/globalsearch/download.php?doc=77434 + +.. _Sternheimer: https://journals.aps.org/prb/pdf/10.1103/PhysRevB.26.6067 + +.. [Sternheimer] R. M. Sternheimer, S.M.Seltzer, and M.J.Berger, *Density + effect for the ionization loss of charged particles in various substances*, + Phys. Rev. B, 26, 6067–6076 (1982). From 9a861db193060a9aaaafb9385d135f9cc7076c0a Mon Sep 17 00:00:00 2001 From: amandalund Date: Wed, 6 Mar 2019 10:03:40 -0600 Subject: [PATCH 007/165] Update photon data --- docs/source/io_formats/nuclear_data.rst | 13 ++++++------- docs/source/usersguide/cross_sections.rst | 10 +++++----- tools/ci/download-xs.sh | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/source/io_formats/nuclear_data.rst b/docs/source/io_formats/nuclear_data.rst index 5595f2061..81e4f4bcd 100644 --- a/docs/source/io_formats/nuclear_data.rst +++ b/docs/source/io_formats/nuclear_data.rst @@ -133,11 +133,17 @@ Incident Photon Data **//bremsstrahlung/** +:Attributes: - **I** (*double*) -- Mean excitation energy in [eV] + :Datasets: - **electron_energy** (*double[]*) -- Incident electron energy in [eV] - **photon_energy** (*double[]*) -- Outgoing photon energy as fraction of incident electron energy - **dcs** (*double[][]*) -- Bremsstrahlung differential cross section at each incident energy in [mb/eV] + - **ionization_energy** (*double[]*) -- Ionization potential of each + subshell in [eV] + - **num_electrons** (*int[]*) -- Number of electrons per subshell, + with conduction electrons indicated by a negative value **//coherent/** @@ -176,13 +182,6 @@ Incident Photon Data :Datasets: - **xs** (*double[]*) -- Total photoionization cross section in [b] -**//stopping_powers/** - -:Datasets: - **I** (*double*) -- Mean excitation energy in [eV] - - **energy** (*double[]*) -- Energies in [eV] - - **s_collision** (*double[]*) -- Collision stopping power in [eV-cm\ :sup:`2`\ /g] - - **s_radiative** (*double[]*) -- Radiative stopping power in [eV-cm\ :sup:`2`\ /g] - **//subshells/** :Attributes: - **designators** (*char[][]*) -- Designator for each shell, e.g. 'M2' diff --git a/docs/source/usersguide/cross_sections.rst b/docs/source/usersguide/cross_sections.rst index dc0e9092a..e6a79815f 100644 --- a/docs/source/usersguide/cross_sections.rst +++ b/docs/source/usersguide/cross_sections.rst @@ -192,11 +192,11 @@ Photon Cross Sections Photon interaction data is needed to run OpenMC with photon transport enabled. Some of this data, namely bremsstrahlung cross sections from `Seltzer and -Berger`_, stopping powers from the `NIST ESTAR database`_, and Compton profiles -calculated by `Biggs et al.`_ and available in the Geant4 G4EMLOW data file, is -distributed with OpenMC. The rest is available from the NNDC_, which provides -ENDF data from the photo-atomic and atomic relaxation sublibraries of the -ENDF/B-VII.1 library. +Berger`_, mean excitation energy from the `NIST ESTAR database`_, and Compton +profiles calculated by `Biggs et al.`_ and available in the Geant4 G4EMLOW data +file, is distributed with OpenMC. The rest is available from the NNDC_, which +provides ENDF data from the photo-atomic and atomic relaxation sublibraries of +the ENDF/B-VII.1 library. Most of the pregenerated HDF5 libraries available at https://openmc.mcs.anl.gov already have photon interaction data included. If you are building a data diff --git a/tools/ci/download-xs.sh b/tools/ci/download-xs.sh index 5fbe93c71..b2068ceca 100755 --- a/tools/ci/download-xs.sh +++ b/tools/ci/download-xs.sh @@ -3,7 +3,7 @@ set -ex # Download HDF5 data if [[ ! -e $HOME/nndc_hdf5/cross_sections.xml ]]; then - wget -q -O - https://anl.box.com/shared/static/snrluuy79o2fffpvpng9bsuis5kl811d.xz | tar -C $HOME -xJ + wget -q -O - https://anl.box.com/shared/static/9jmb8v2cx6kx03s6mbr2ai0mnvx5j79p.xz | tar -C $HOME -xJ fi # Download ENDF/B-VII.1 distribution From 64e617ed0934d2ec48571faf9152cc83d3650510 Mon Sep 17 00:00:00 2001 From: amandalund Date: Wed, 6 Mar 2019 14:15:06 -0600 Subject: [PATCH 008/165] Fix particle type --- src/physics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/physics.cpp b/src/physics.cpp index 01cae9cb9..85b6e2417 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -266,7 +266,7 @@ void sample_photon_reaction(Particle* p) // Create Compton electron double phi = 2.0*PI*prn(); double E_electron = (alpha - alpha_out)*MASS_ELECTRON_EV - e_b; - int electron = static_cast(ParticleType::electron); + int electron = static_cast(Particle::Type::electron); if (E_electron >= settings::energy_cutoff[electron]) { double mu_electron = (alpha - alpha_out*mu) / std::sqrt(alpha*alpha + alpha_out*alpha_out - 2.0*alpha*alpha_out*mu); From 2943e38a81bcba35cc90f9b141fc90d575dd3c64 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 4 Mar 2019 08:14:52 -0600 Subject: [PATCH 009/165] Add Plane.from_points and cylinder_from_points convenience functions --- docs/source/pythonapi/model.rst | 1 + openmc/model/funcs.py | 50 +++++++++++++++++++++++++++++++- openmc/surface.py | 32 ++++++++++++++++++++ tests/unit_tests/test_surface.py | 28 ++++++++++++++++++ 4 files changed, 110 insertions(+), 1 deletion(-) diff --git a/docs/source/pythonapi/model.rst b/docs/source/pythonapi/model.rst index 90e8b779d..14f4a4beb 100644 --- a/docs/source/pythonapi/model.rst +++ b/docs/source/pythonapi/model.rst @@ -11,6 +11,7 @@ Convenience Functions :template: myfunction.rst openmc.model.borated_water + openmc.model.cylinder_from_points openmc.model.get_hexagonal_prism openmc.model.get_rectangular_prism openmc.model.subdivide diff --git a/openmc/model/funcs.py b/openmc/model/funcs.py index e974f93b1..44e7f95f1 100644 --- a/openmc/model/funcs.py +++ b/openmc/model/funcs.py @@ -3,7 +3,7 @@ from collections.abc import Iterable from math import sqrt from numbers import Real -from openmc import XPlane, YPlane, Plane, ZCylinder +from openmc import XPlane, YPlane, Plane, ZCylinder, Quadric from openmc.checkvalue import check_type, check_value import openmc.data @@ -345,6 +345,54 @@ def get_hexagonal_prism(edge_length=1., orientation='y', origin=(0., 0.), return prism +def cylinder_from_points(p1, p2, r, **kwargs): + """Return cylinder defined by two points passing through its center. + + Parameters + ---------- + p1, p2 : 3-tuples + Coordinates of two points that pass through the center of the cylinder + r : float + Radius of the cylinder + kwargs : dict + Keyword arguments passed to the :class:`openmc.Quadric` constructor + + Returns + ------- + openmc.Quadric + Quadric surface representing the cylinder. + + """ + # Get x, y, z coordinates of two points + x1, y1, z1 = p1 + x2, y2, z2 = p2 + + # Define intermediate terms + dx = x2 - x1 + dy = y2 - y1 + dz = z2 - z1 + cx = y1*z2 + y2*z1 + cy = -(x1*z2 + x2*z1) + cz = x1*y2 + x2*y1 + + # Given p=(x,y,z), p1=(x1, y1, z1), p2=(x2, y2, z2), the equation for the + # cylinder can be derived as r = |(p - p1) ⨯ (p - p2)| / |p2 - p1|. + # Expanding out all terms and grouping according to what Quadric expects + # gives the following coefficients. + kwargs['a'] = dy*dy + dz*dz + kwargs['b'] = dx*dx + dz*dz + kwargs['c'] = dx*dx + dy*dy + kwargs['d'] = -2*dx*dy + kwargs['e'] = -2*dy*dz + kwargs['f'] = -2*dx*dz + kwargs['g'] = cy*dz - cz*dy + kwargs['h'] = cz*dx - cx*dz + kwargs['j'] = cx*dy - cy*dx + kwargs['k'] = -(dx*dx + dy*dy + dz*dz)*r*r + + return openmc.Quadric(**kwargs) + + def subdivide(surfaces): """Create regions separated by a series of surfaces. diff --git a/openmc/surface.py b/openmc/surface.py index c861880c5..7efa04e38 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -456,6 +456,38 @@ class Plane(Surface): element.set("periodic_surface_id", str(self.periodic_surface.id)) return element + @classmethod + def from_points(cls, p1, p2, p3, **kwargs): + """Return a plane given three points that pass through it. + + Parameters + ---------- + p1, p2, p3 : 3-tuples + Points that pass through the plane + kwargs : dict + Keyword arguments passed to the :class:`Plane` constructor + + Returns + ------- + Plane + Plane that passes through the three points + + """ + # Convert to numpy arrays + p1 = np.asarray(p1) + p2 = np.asarray(p2) + p3 = np.asarray(p3) + + # Find normal vector to plane by taking cross product of two vectors + # connecting p1->p2 and p1->p3 + n = np.cross(p2 - p1, p3 - p1) + + # The equation of the plane will by n·( - p1) = 0. Determine + # coefficients A, B, C, and D based on that + A, B, C = n + D = np.dot(n, p1) + return cls(A=A, B=B, C=C, D=D, **kwargs) + class XPlane(Plane): """A plane perpendicular to the x axis of the form :math:`x - x_0 = 0` diff --git a/tests/unit_tests/test_surface.py b/tests/unit_tests/test_surface.py index 3db84cc05..01a7cf710 100644 --- a/tests/unit_tests/test_surface.py +++ b/tests/unit_tests/test_surface.py @@ -33,6 +33,20 @@ def test_plane(): repr(s) +def test_plane_from_points(): + # Generate the plane x - y = 1 given three points + p1 = (0, -1, 0) + p2 = (1, 0, 0) + p3 = (1, 0, 1) + s = openmc.Plane.from_points(p1, p2, p3) + + # Confirm correct coefficients + assert s.a == 1.0 + assert s.b == -1.0 + assert s.c == 0.0 + assert s.d == 1.0 + + def test_xplane(): s = openmc.XPlane(x0=3., boundary_type='reflective') assert s.x0 == 3. @@ -257,3 +271,17 @@ def test_quadric(): # evaluate method assert s.evaluate((0., 0., 0.)) == pytest.approx(coeffs['k']) assert s.evaluate((1., 1., 1.)) == pytest.approx(3 + coeffs['k']) + + +def test_cylinder_from_points(): + # Generate 45-degree rotated cylinder in x-y plane with radius 1 + p1 = (0, 0, 0) + p2 = (1, 1, 0) + s = openmc.model.cylinder_from_points(p1, p2, 1) + + # Points p1 and p2 need to be inside cylinder + assert p1 in -s + assert p2 in -s + assert (-1, 1, 0) in +s + assert (1, -1, 0) in +s + assert (0, 0, 1.5) in +s From 394ac75560646ac8214583a3fb581f8f66e6516f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 6 Mar 2019 14:27:40 -0600 Subject: [PATCH 010/165] Add translate methods to surfaces and regions --- openmc/region.py | 85 +++++++++- openmc/surface.py | 263 ++++++++++++++++++++++++++++++- tests/unit_tests/test_region.py | 18 +++ tests/unit_tests/test_surface.py | 55 +++++++ 4 files changed, 409 insertions(+), 12 deletions(-) diff --git a/openmc/region.py b/openmc/region.py index ceffadbe3..ffcbeea60 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -229,14 +229,27 @@ class Region(metaclass=ABCMeta): clone : openmc.Region The clone of this region - Raises - ------ - NotImplementedError - This method is not implemented for the abstract region class. + """ + pass + + @abstractmethod + def translate(self, vector, memo=None): + """Translate region in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which region should be translated + memo : dict or None + Dictionary used for memoization + + Returns + ------- + openmc.Region + Translated region """ - raise NotImplementedError('The clone method is not implemented for ' - 'the abstract region class.') + pass class Intersection(Region, MutableSequence): @@ -352,6 +365,26 @@ class Intersection(Region, MutableSequence): clone[:] = [n.clone(memo) for n in self] return clone + def translate(self, vector, memo=None): + """Translate region in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which region should be translated + memo : dict or None + Dictionary used for memoization + + Returns + ------- + openmc.Intersection + Translated region + + """ + if memo is None: + memo = {} + return type(self)(n.translate(vector, memo) for n in self) + class Union(Region, MutableSequence): r"""Union of two or more regions. @@ -464,6 +497,26 @@ class Union(Region, MutableSequence): clone[:] = [n.clone(memo) for n in self] return clone + def translate(self, vector, memo=None): + """Translate region in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which region should be translated + memo : dict or None + Dictionary used for memoization + + Returns + ------- + openmc.Union + Translated region + + """ + if memo is None: + memo = {} + return type(self)(n.translate(vector, memo) for n in self) + class Complement(Region): """Complement of a region. @@ -584,3 +637,23 @@ class Complement(Region): clone = deepcopy(self) clone.node = self.node.clone(memo) return clone + + def translate(self, vector, memo=None): + """Translate region in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which region should be translated + memo : dict or None + Dictionary used for memoization + + Returns + ------- + openmc.Complement + Translated region + + """ + if memo is None: + memo = {} + return type(self)(self.node.translate(vector, memo)) diff --git a/openmc/surface.py b/openmc/surface.py index 7efa04e38..306fb6d73 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -1,4 +1,4 @@ -from abc import ABCMeta +from abc import ABCMeta, abstractmethod from collections import OrderedDict from copy import deepcopy from functools import partial @@ -15,7 +15,7 @@ from openmc.mixin import IDManagerMixin _BOUNDARY_TYPES = ['transmission', 'vacuum', 'reflective', 'periodic'] -class Surface(IDManagerMixin): +class Surface(IDManagerMixin, metaclass=ABCMeta): """An implicit surface with an associated boundary condition. An implicit surface is defined as the set of zeros of a function of the @@ -142,7 +142,6 @@ class Surface(IDManagerMixin): desired half-space """ - return (np.array([-np.inf, -np.inf, -np.inf]), np.array([np.inf, np.inf, np.inf])) @@ -175,6 +174,14 @@ class Surface(IDManagerMixin): return memo[self] + @abstractmethod + def evaluate(self, point): + pass + + @abstractmethod + def translate(self, vector): + pass + def to_xml_element(self): """Return XML representation of the surface @@ -432,13 +439,34 @@ class Plane(Surface): Returns ------- float - :math:`Ax' + By' + Cz' - d` + :math:`Ax' + By' + Cz' - D` """ x, y, z = point return self.a*x + self.b*y + self.c*z - self.d + def translate(self, vector): + """Translate surface in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.Plane + Translated surface + + """ + vx, vy, vz = vector + d = self.d + self.a*vx + self.b*vy + self.c*vz + if d == self.d: + return self + else: + return type(self)(A=self.a, B=self.b, C=self.c, D=d) + def to_xml_element(self): """Return XML representation of the surface @@ -593,6 +621,26 @@ class XPlane(Plane): """ return point[0] - self.x0 + def translate(self, vector): + """Translate surface in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.XPlane + Translated surface + + """ + vx = vector[0] + if vx == 0: + return self + else: + return type(self)(x0=self.x0 + vx) + class YPlane(Plane): """A plane perpendicular to the y axis of the form :math:`y - y_0 = 0` @@ -699,6 +747,26 @@ class YPlane(Plane): """ return point[1] - self.y0 + def translate(self, vector): + """Translate surface in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.YPlane + Translated surface + + """ + vy = vector[1] + if vy == 0.0: + return self + else: + return type(self)(y0=self.y0 + vy) + class ZPlane(Plane): """A plane perpendicular to the z axis of the form :math:`z - z_0 = 0` @@ -805,8 +873,28 @@ class ZPlane(Plane): """ return point[2] - self.z0 + def translate(self, vector): + """Translate surface in given direction -class Cylinder(Surface, metaclass=ABCMeta): + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.ZPlane + Translated surface + + """ + vz = vector[2] + if vz == 0.0: + return self + else: + return type(self)(z0=self.z0 + vz) + + +class Cylinder(Surface): """A cylinder whose length is parallel to the x-, y-, or z-axis. Parameters @@ -977,6 +1065,28 @@ class XCylinder(Cylinder): z = point[2] - self.z0 return y**2 + z**2 - self.r**2 + def translate(self, vector): + """Translate surface in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.XCylinder + Translated surface + + """ + vx, vy, vz = vector + if vy == 0.0 and vz == 0.0: + return self + else: + y0 = self.y0 + vy + z0 = self.z0 + vz + return type(self)(y0=y0, z0=z0, R=self.r) + class YCylinder(Cylinder): """An infinite cylinder whose length is parallel to the y-axis of the form @@ -1099,6 +1209,28 @@ class YCylinder(Cylinder): z = point[2] - self.z0 return x**2 + z**2 - self.r**2 + def translate(self, vector): + """Translate surface in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.YCylinder + Translated surface + + """ + vx, vy, vz = vector + if vx == 0.0 and vz == 0.0: + return self + else: + x0 = self.x0 + vx + z0 = self.z0 + vz + return type(self)(x0=x0, z0=z0, R=self.r) + class ZCylinder(Cylinder): """An infinite cylinder whose length is parallel to the z-axis of the form @@ -1221,6 +1353,28 @@ class ZCylinder(Cylinder): y = point[1] - self.y0 return x**2 + y**2 - self.r**2 + def translate(self, vector): + """Translate surface in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.ZCylinder + Translated surface + + """ + vx, vy, vz = vector + if vx == 0.0 and vy == 0.0: + return self + else: + x0 = self.x0 + vx + y0 = self.y0 + vy + return type(self)(x0=x0, y0=y0, R=self.r) + class Sphere(Surface): """A sphere of the form :math:`(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 = R^2`. @@ -1369,8 +1523,31 @@ class Sphere(Surface): z = point[2] - self.z0 return x**2 + y**2 + z**2 - self.r**2 + def translate(self, vector): + """Translate surface in given direction -class Cone(Surface, metaclass=ABCMeta): + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.Sphere + Translated surface + + """ + vx, vy, vz = vector + if vx == 0.0 and vy == 0.0 and vz == 0.0: + return self + else: + x0 = self.x0 + vx + y0 = self.y0 + vy + z0 = self.z0 + vz + return type(self)(x0=x0, y0=y0, z0=z0, R=self.r) + + +class Cone(Surface): """A conical surface parallel to the x-, y-, or z-axis. Parameters @@ -1463,6 +1640,29 @@ class Cone(Surface, metaclass=ABCMeta): check_type('R^2 coefficient', R2, Real) self._coefficients['R2'] = R2 + def translate(self, vector): + """Translate surface in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.Cone + Translated surface + + """ + vx, vy, vz = vector + if vx == 0.0 and vy == 0.0 and vz == 0.0: + return self + else: + x0 = self.x0 + vx + y0 = self.y0 + vy + z0 = self.z0 + vz + return type(self)(x0=x0, y0=y0, z0=z0, R2=self.r2) + class XCone(Cone): """A cone parallel to the x-axis of the form :math:`(y - y_0)^2 + (z - z_0)^2 = @@ -1842,6 +2042,30 @@ class Quadric(Surface): y*(self.b*y + self.e*z + self.h) + \ z*(self.c*z + self.f*x + self.j) + self.k + def translate(self, vector): + """Translate surface in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which surface should be translated + + Returns + ------- + openmc.Quadric + Translated surface + + """ + vx, vy, vz = vector + a, b, c, d, e, f, g, h, j, k = (getattr(self, key) for key in + self._coeff_keys) + k = (k + vx*vx + vy*vy + vz*vz + d*vx*vy + e*vy*vz + f*vx*vz + - g*vx - h*vy - j*vz) + g = g - 2*a*vx - d*vy - f*vz + h = h - 2*b*vy - d*vx - e*vz + j = j - 2*c*vz - e*vy - f*vx + return type(self)(a=a, b=b, c=c, d=d, e=e, f=f, g=g, h=h, j=j, k=k) + class Halfspace(Region): """A positive or negative half-space region. @@ -1987,3 +2211,30 @@ class Halfspace(Region): clone = deepcopy(self) clone.surface = self.surface.clone(memo) return clone + + def translate(self, vector, memo=None): + """Translate half-space in given direction + + Parameters + ---------- + vector : iterable of float + Direction in which region should be translated + memo : dict or None + Dictionary used for memoization + + Returns + ------- + openmc.Halfspace + Translated half-space + + """ + if memo is None: + memo = {} + + # If translated surface not in memo, add it + key = (self.surface, tuple(vector)) + if key not in memo: + memo[key] = self.surface.translate(vector) + + # Return translated surface + return type(self)(memo[key], self.side) diff --git a/tests/unit_tests/test_region.py b/tests/unit_tests/test_region.py index 377c8fbd5..b623cd606 100644 --- a/tests/unit_tests/test_region.py +++ b/tests/unit_tests/test_region.py @@ -34,6 +34,12 @@ def test_union(reset): assert (6, -1, 0) not in reg2 assert str(reg2) == '((1 | -2) 3)' + # translate method + regt = region.translate((2.0, 0.0, 0.0)) + assert (-4, 0, 0) in regt + assert (6, 0, 0) not in regt + assert (8, 0, 0) in regt + def test_intersection(reset): s1 = openmc.XPlane(surface_id=1, x0=5) @@ -61,6 +67,12 @@ def test_intersection(reset): assert (-6, -2, 0) not in reg2 assert str(reg2) == '((-1 2) | 3)' + # translate method + regt = region.translate((2.0, 0.0, 0.0)) + assert (-4, 0, 0) not in regt + assert (6, 0, 0) in regt + assert (8, 0, 0) not in regt + def test_complement(reset): zcyl = openmc.ZCylinder(surface_id=1, R=1.) @@ -88,6 +100,12 @@ def test_complement(reset): assert (0, 0, 6) not in inside assert (0, 0, 6) in outside + # translate method + inside_t = inside.translate((1.0, 1.0, 1.0)) + ll, ur = inside_t.bounding_box + assert ll == pytest.approx((0., 0., -4.)) + assert ur == pytest.approx((2., 2., 6.)) + def test_get_surfaces(): s1 = openmc.XPlane() diff --git a/tests/unit_tests/test_surface.py b/tests/unit_tests/test_surface.py index 01a7cf710..45fecb493 100644 --- a/tests/unit_tests/test_surface.py +++ b/tests/unit_tests/test_surface.py @@ -29,6 +29,10 @@ def test_plane(): x, y, z = (4, 3, 6) assert s.evaluate((x, y, z)) == pytest.approx(s.a*x + s.b*y + s.c*z - s.d) + # translate method + st = s.translate((1.0, 0.0, 0.0)) + assert (st.a, st.b, st.c, st.d) == (s.a, s.b, s.c, 4) + # Make sure repr works repr(s) @@ -69,6 +73,10 @@ def test_xplane(): # evaluate method assert s.evaluate((5., 0., 0.)) == pytest.approx(2.) + # translate method + st = s.translate((1.0, 0.0, 0.0)) + assert st.x0 == s.x0 + 1 + # Make sure repr works repr(s) @@ -94,6 +102,10 @@ def test_yplane(): # evaluate method assert s.evaluate((0., 0., 0.)) == pytest.approx(-3.) + # translate method + st = s.translate((0.0, 1.0, 0.0)) + assert st.y0 == s.y0 + 1 + def test_zplane(): s = openmc.ZPlane(z0=3.) @@ -116,6 +128,10 @@ def test_zplane(): # evaluate method assert s.evaluate((0., 0., 10.)) == pytest.approx(7.) + # translate method + st = s.translate((0.0, 0.0, 1.0)) + assert st.z0 == s.z0 + 1 + # Make sure repr works repr(s) @@ -138,6 +154,12 @@ def test_xcylinder(): # evaluate method assert s.evaluate((0, y, z)) == pytest.approx(-r**2) + # translate method + st = s.translate((1.0, 1.0, 1.0)) + assert st.y0 == s.y0 + 1 + assert st.z0 == s.z0 + 1 + assert st.r == s.r + # Make sure repr works repr(s) @@ -169,6 +191,12 @@ def test_ycylinder(): # evaluate method assert s.evaluate((x, 0, z)) == pytest.approx(-r**2) + # translate method + st = s.translate((1.0, 1.0, 1.0)) + assert st.x0 == s.x0 + 1 + assert st.z0 == s.z0 + 1 + assert st.r == s.r + def test_zcylinder(): x, y, r = 3, 5, 2 @@ -188,6 +216,12 @@ def test_zcylinder(): # evaluate method assert s.evaluate((x, y, 0)) == pytest.approx(-r**2) + # translate method + st = s.translate((1.0, 1.0, 1.0)) + assert st.x0 == s.x0 + 1 + assert st.y0 == s.y0 + 1 + assert st.r == s.r + # Make sure repr works repr(s) @@ -211,6 +245,13 @@ def test_sphere(): # evaluate method assert s.evaluate((x, y, z)) == pytest.approx(-r**2) + # translate method + st = s.translate((1.0, 1.0, 1.0)) + assert st.x0 == s.x0 + 1 + assert st.y0 == s.y0 + 1 + assert st.z0 == s.z0 + 1 + assert st.r == s.r + # Make sure repr works repr(s) @@ -229,6 +270,13 @@ def cone_common(apex, r2, cls): # evaluate method -- should be zero at apex assert s.evaluate((x, y, z)) == pytest.approx(0.0) + # translate method + st = s.translate((1.0, 1.0, 1.0)) + assert st.x0 == s.x0 + 1 + assert st.y0 == s.y0 + 1 + assert st.z0 == s.z0 + 1 + assert st.r2 == s.r2 + # Make sure repr works repr(s) @@ -272,6 +320,13 @@ def test_quadric(): assert s.evaluate((0., 0., 0.)) == pytest.approx(coeffs['k']) assert s.evaluate((1., 1., 1.)) == pytest.approx(3 + coeffs['k']) + # translate method + st = s.translate((1.0, 1.0, 1.0)) + for coeff in 'abcdef': + assert getattr(s, coeff) == getattr(st, coeff) + assert (st.g, st.h, st.j) == (-2, -2, -2) + assert st.k == s.k + 3 + def test_cylinder_from_points(): # Generate 45-degree rotated cylinder in x-y plane with radius 1 From fd418f15b431799f25539d430631975ca46da29c Mon Sep 17 00:00:00 2001 From: amandalund Date: Wed, 6 Mar 2019 16:45:03 -0700 Subject: [PATCH 011/165] Update failing photon tests --- .../photon_source/results_true.dat | 4 +-- tests/unit_tests/test_data_photon.py | 31 +++++++------------ 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/tests/regression_tests/photon_source/results_true.dat b/tests/regression_tests/photon_source/results_true.dat index 609f887bd..1448ad6db 100644 --- a/tests/regression_tests/photon_source/results_true.dat +++ b/tests/regression_tests/photon_source/results_true.dat @@ -1,3 +1,3 @@ tally 1: -sum = 2.254985E+02 -sum_sq = 5.084955E+04 +sum = 2.275713E+02 +sum_sq = 5.178870E+04 diff --git a/tests/unit_tests/test_data_photon.py b/tests/unit_tests/test_data_photon.py index 5036d08fd..e2e737286 100644 --- a/tests/unit_tests/test_data_photon.py +++ b/tests/unit_tests/test_data_photon.py @@ -71,10 +71,20 @@ def test_transitions(element): assert sum(matrix['probability']) == pytest.approx(1.0) -@pytest.mark.parametrize('element', ['H', 'Al', 'Ag'], indirect=True) -def test_bremsstrahlung(element): +@pytest.mark.parametrize( + 'element, I, i_shell, ionization_energy, num_electrons', [ + ('H', 19.2, 0, 13.6, 1), + ('O', 95.0, 2, 13.62, 4), + ('U', 890.0, 25, 6.033, -3) + ], + indirect=['element'] +) +def test_bremsstrahlung(element, I, i_shell, ionization_energy, num_electrons): brems = element.bremsstrahlung assert isinstance(brems, Mapping) + assert brems['I'] == I + assert brems['num_electrons'][i_shell] == num_electrons + assert brems['ionization_energy'][i_shell] == ionization_energy assert np.all(np.diff(brems['electron_energy']) > 0.0) assert np.all(np.diff(brems['photon_energy']) > 0.0) assert brems['photon_energy'][0] == 0.0 @@ -114,23 +124,6 @@ def test_reactions(element, reaction): reactions[18] -@pytest.mark.parametrize( - 'element, I', [ - ('H', 19.2), - ('O', 95.0), - ('U', 890.0) - ], - indirect=['element'] -) -def test_stopping_powers(element, I): - stopping_powers = element.stopping_powers - assert isinstance(stopping_powers, Mapping) - assert stopping_powers['I'] == I - assert np.all(np.diff(stopping_powers['energy']) > 0.0) - assert len(stopping_powers['s_collision']) == 200 - assert len(stopping_powers['s_radiative']) == 200 - - @pytest.mark.parametrize('element', ['Pu'], indirect=True) def test_export_to_hdf5(tmpdir, element): filename = str(tmpdir.join('tmp.h5')) From 0f2a4f9eebad0554a5f4063c60705c991e6ab33d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 7 Mar 2019 09:43:43 -0600 Subject: [PATCH 012/165] Make clear that memo argument to Region.translate is internal --- openmc/region.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openmc/region.py b/openmc/region.py index ffcbeea60..e8e42776c 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -241,7 +241,8 @@ class Region(metaclass=ABCMeta): vector : iterable of float Direction in which region should be translated memo : dict or None - Dictionary used for memoization + Dictionary used for memoization. This parameter is used internally + and should not be specified by the user. Returns ------- @@ -373,7 +374,8 @@ class Intersection(Region, MutableSequence): vector : iterable of float Direction in which region should be translated memo : dict or None - Dictionary used for memoization + Dictionary used for memoization. This parameter is used internally + and should not be specified by the user. Returns ------- @@ -505,7 +507,8 @@ class Union(Region, MutableSequence): vector : iterable of float Direction in which region should be translated memo : dict or None - Dictionary used for memoization + Dictionary used for memoization. This parameter is used internally + and should not be specified by the user. Returns ------- @@ -646,7 +649,8 @@ class Complement(Region): vector : iterable of float Direction in which region should be translated memo : dict or None - Dictionary used for memoization + Dictionary used for memoization. This parameter is used internally + and should not be specified by the user. Returns ------- From 61000397fde3a5032cd2b2c762f339d38f103332 Mon Sep 17 00:00:00 2001 From: amandalund Date: Thu, 7 Mar 2019 09:09:01 -0700 Subject: [PATCH 013/165] Address @paulromano comments --- docs/source/methods/photon_physics.rst | 18 +++++++----------- src/material.cpp | 10 +++++++--- .../photon_production/inputs_true.dat | 2 +- .../photon_production/results_true.dat | 4 ++-- .../regression_tests/photon_production/test.py | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/source/methods/photon_physics.rst b/docs/source/methods/photon_physics.rst index bde6d2a99..23809f674 100644 --- a/docs/source/methods/photon_physics.rst +++ b/docs/source/methods/photon_physics.rst @@ -775,7 +775,7 @@ formula can be used to find the collision stopping power of the material: :label: material-collision-stopping-power S_{\text{col}}(T) = \frac{2 \pi r_e^2 m_e c^2}{\beta^2} N_A \frac{Z}{A_M} - [\ln(T^2/I^2) + ln(1 + \tau/2) + F(\tau) - \delta_F(T)], + [\ln(T^2/I^2) + \ln(1 + \tau/2) + F(\tau) - \delta_F(T)], where :math:`N_A` is Avogadro's number, :math:`A_M` is the molar mass, :math:`\tau = T/m_e`, and :math:`F(\tau)` depends on the particle type. For @@ -797,7 +797,7 @@ while for positrons The density effect correction :math:`\delta_F` takes into account the reduction of the collision stopping power due to the polarization of the material the charged particle is passing through by the electric field of the particle. -It can be evaluated using the method described by [Sternheimer]_, where the +It can be evaluated using the method described by Sternheimer_, where the equation for :math:`\delta_F` is .. math:: @@ -821,14 +821,14 @@ where :math:`\bar{v}_i` is defined as .. math:: :label: density-effect-nubar - \bar{\nu}_i = \nu_i \rho / \nu_p. + \bar{\nu}_i = h\nu_i \rho / h\nu_p. The plasma energy :math:`h\nu_p` of the medium is given by .. math:: :label: plasma-frequency - h\nu_p = \sqrt{(hc)^2/\pi r_e \rho_m N_A Z / A}, + h\nu_p = \sqrt{\frac{(hc)^2 r_e \rho_m N_A Z}{\pi A}}, where :math:`A` is the atomic weight and :math:`\rho_m` is the density of the material. In :eq:`density-effect-nubar`, :math:`h\nu_i` is the oscillator @@ -840,8 +840,8 @@ defined as .. math:: :label: density-effect-li - l_i &= (\bar{v}_i^2 + 2/3f_i)^{1/2} ~~~~&\text{for}~~ \bar{v}_i > 0 \\ - l_n &= f_n^{1/2} ~~~~&\text{for}~~ \bar{v}_n = 0, + l_i &= (\bar{\nu}_i^2 + 2/3f_i)^{1/2} ~~~~&\text{for}~~ \bar{\nu}_i > 0 \\ + l_n &= f_n^{1/2} ~~~~&\text{for}~~ \bar{\nu}_n = 0, where the second case applies to conduction electrons. For a conductor, :math:`f_n` is given by :math:`n_c/Z`, where :math:`n_c` is the effective @@ -1047,8 +1047,4 @@ emitted photon. .. _Salvat: http://www.oecd-nea.org/globalsearch/download.php?doc=77434 -.. _Sternheimer: https://journals.aps.org/prb/pdf/10.1103/PhysRevB.26.6067 - -.. [Sternheimer] R. M. Sternheimer, S.M.Seltzer, and M.J.Berger, *Density - effect for the ionization loss of charged particles in various substances*, - Phys. Rev. B, 26, 6067–6076 (1982). +.. _Sternheimer: https://doi.org/10.1103/PhysRevB.26.6067 diff --git a/src/material.cpp b/src/material.cpp index 9ad0b8f0a..da68a536d 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -505,11 +505,15 @@ void Material::collision_stopping_power(double* s_col, bool positron) double rho = sternheimer_adjustment(f, e_b_sq, e_p_sq, n_conduction, log_I, 1.0e-6, 100); - // Classical elctron radius in cm - double r_e = PLANCK_C / (2.0e8 * PI * FINE_STRUCTURE * MASS_ELECTRON_EV); + // Classical electron radius in cm + constexpr double CM_PER_ANGSTROM {1.0e-8}; + constexpr double r_e = CM_PER_ANGSTROM * PLANCK_C / (2.0 * PI * + FINE_STRUCTURE * MASS_ELECTRON_EV); // Constant in expression for collision stopping power - double c = 2.0e24 * PI * r_e * r_e * MASS_ELECTRON_EV * electron_density; + constexpr double BARN_PER_CM_SQ {1.0e24}; + double c = BARN_PER_CM_SQ * 2.0 * PI * r_e * r_e * MASS_ELECTRON_EV * + electron_density; // Loop over incident charged particle energies for (int i = 0; i < data::ttb_e_grid.size(); ++i) { diff --git a/tests/regression_tests/photon_production/inputs_true.dat b/tests/regression_tests/photon_production/inputs_true.dat index 32e3bdcf3..427078c88 100644 --- a/tests/regression_tests/photon_production/inputs_true.dat +++ b/tests/regression_tests/photon_production/inputs_true.dat @@ -26,7 +26,7 @@ - 14.0 1.0 + 14000000.0 1.0 ttb diff --git a/tests/regression_tests/photon_production/results_true.dat b/tests/regression_tests/photon_production/results_true.dat index 6f53e2d33..3d9cf68ed 100644 --- a/tests/regression_tests/photon_production/results_true.dat +++ b/tests/regression_tests/photon_production/results_true.dat @@ -1,3 +1,3 @@ tally 1: -sum = 1.550000E-02 -sum_sq = 2.402500E-04 +sum = 7.938000E-01 +sum_sq = 6.301184E-01 diff --git a/tests/regression_tests/photon_production/test.py b/tests/regression_tests/photon_production/test.py index 68992c867..1abc184a2 100644 --- a/tests/regression_tests/photon_production/test.py +++ b/tests/regression_tests/photon_production/test.py @@ -33,7 +33,7 @@ class SourceTestHarness(PyAPITestHarness): source = openmc.Source() source.space = openmc.stats.Point((0,0,0)) source.angle = openmc.stats.Monodirectional() - source.energy = openmc.stats.Discrete([14.0], [1.0]) + source.energy = openmc.stats.Discrete([14.0e6], [1.0]) source.particle = 'neutron' settings = openmc.Settings() From 4a5763bb37f9f0b1870f14bbbddaaa4ab83321e3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 7 Mar 2019 11:13:51 -0600 Subject: [PATCH 014/165] Hopefully fix doc builds on RTD --- docs/source/conf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index be7e3a8d1..22446213a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -53,9 +53,10 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', - 'sphinx.ext.imgconverter', 'sphinx_numfig', 'notebook_sphinxext'] +if not on_rtd: + extensions.append('sphinx.ext.imgconverter') # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From 758d9b45d508170f297015851c3268b54c07c20e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 7 Mar 2019 22:20:50 -0600 Subject: [PATCH 015/165] Adding functools partial to model.funcs. Adding a quick test for the hexagonal prism. --- openmc/model/funcs.py | 1 + tests/unit_tests/test_geometry.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/openmc/model/funcs.py b/openmc/model/funcs.py index e974f93b1..60fbbee90 100644 --- a/openmc/model/funcs.py +++ b/openmc/model/funcs.py @@ -2,6 +2,7 @@ from collections import OrderedDict from collections.abc import Iterable from math import sqrt from numbers import Real +from functools import partial from openmc import XPlane, YPlane, Plane, ZCylinder from openmc.checkvalue import check_type, check_value diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index b5d6076bb..2c9306cb9 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -203,6 +203,19 @@ def test_get_by_name(): assert not univs +def test_hex_prism(): + hex_prism = openmc.model.get_hexagonal_prism(edge_length=5.0, + origin=(0.0, 0.0), + boundary_type='reflective', + orientation='y', + corner_radius=0.10) + + hex_prism = openmc.model.get_hexagonal_prism(edge_length=5.0, + origin=(0.0, 0.0), + boundary_type='reflective', + orientation='y') + + def test_get_lattice_by_name(cell_with_lattice): cells, _, _, lattice = cell_with_lattice geom = openmc.Geometry([cells[-1]]) @@ -245,6 +258,7 @@ def test_determine_paths(cell_with_lattice): assert geom.get_instances(cells[0].paths[i]) == i assert geom.get_instances(mats[-1].paths[i]) == i + def test_from_xml(run_in_tmpdir, mixed_lattice_model): # Export model mixed_lattice_model.export_to_xml() From 325f9fcf72f01161186cde1a19944341cbe0b493 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 8 Mar 2019 11:25:26 -0600 Subject: [PATCH 016/165] Use lower-case argument names for surfaces consistently --- docs/source/usersguide/geometry.rst | 12 +- docs/source/usersguide/volume.rst | 2 +- examples/python/basic/build-xml.py | 6 +- .../python/lattice/hexagonal/build-xml.py | 2 +- examples/python/lattice/nested/build-xml.py | 6 +- examples/python/lattice/simple/build-xml.py | 6 +- examples/python/pincell/build-xml.py | 6 +- .../python/pincell_depletion/run_depletion.py | 6 +- .../python/pincell_multigroup/build-xml.py | 2 +- openmc/examples.py | 24 +- openmc/model/funcs.py | 20 +- openmc/model/triso.py | 2 +- openmc/region.py | 4 +- openmc/surface.py | 234 ++++++++++-------- .../deplete/example_geometry.py | 8 +- tests/regression_tests/distribmat/test.py | 2 +- tests/regression_tests/fixed_source/test.py | 2 +- tests/regression_tests/multipole/test.py | 2 +- tests/regression_tests/periodic/test.py | 2 +- .../photon_production/test.py | 2 +- tests/regression_tests/photon_source/test.py | 8 +- tests/regression_tests/source/test.py | 2 +- tests/regression_tests/surface_tally/test.py | 4 +- tests/regression_tests/triso/test.py | 2 +- tests/regression_tests/volume_calc/test.py | 6 +- tests/unit_tests/conftest.py | 4 +- tests/unit_tests/test_geometry.py | 8 +- tests/unit_tests/test_lattice.py | 4 +- tests/unit_tests/test_mesh_from_lattice.py | 8 +- tests/unit_tests/test_model_triso.py | 26 +- tests/unit_tests/test_plots.py | 2 +- tests/unit_tests/test_region.py | 2 +- tests/unit_tests/test_surface.py | 12 +- tests/unit_tests/test_universe.py | 4 +- 34 files changed, 234 insertions(+), 208 deletions(-) diff --git a/docs/source/usersguide/geometry.rst b/docs/source/usersguide/geometry.rst index 70a665c53..80e60bd34 100644 --- a/docs/source/usersguide/geometry.rst +++ b/docs/source/usersguide/geometry.rst @@ -88,7 +88,7 @@ parameters for a sphere are the :math:`x,y,z` coordinates of the center of the sphere and the radius of the sphere. All of these parameters can be set either as optional keyword arguments to the class constructor or via attributes:: - sphere = openmc.Sphere(R=10.0) + sphere = openmc.Sphere(r=10.0) # This is equivalent sphere = openmc.Sphere() @@ -98,7 +98,7 @@ Once a surface has been created, half-spaces can be obtained by applying the unary ``-`` or ``+`` operators, corresponding to the negative and positive half-spaces, respectively. For example:: - >>> sphere = openmc.Sphere(R=10.0) + >>> sphere = openmc.Sphere(r=10.0) >>> inside_sphere = -sphere >>> outside_sphere = +sphere >>> type(inside_sphere) @@ -140,10 +140,10 @@ may want to specify different behavior for particles passing through a surface. To specify a vacuum boundary condition, simply change the :attr:`Surface.boundary_type` attribute to 'vacuum':: - outer_surface = openmc.Sphere(R=100.0, boundary_type='vacuum') + outer_surface = openmc.Sphere(r=100.0, boundary_type='vacuum') # This is equivalent - outer_surface = openmc.Sphere(R=100.0) + outer_surface = openmc.Sphere(r=100.0) outer_surface.boundary_type = 'vacuum' Reflective and periodic boundary conditions can be set with the strings @@ -154,8 +154,8 @@ can be determined automatically. For non-axis-aligned planes, it is necessary to specify pairs explicitly using the :attr:`Surface.periodic_surface` attribute as in the following example:: - p1 = openmc.Plane(A=0.3, B=5.0, D=1.0, boundary_type='periodic') - p2 = openmc.Plane(A=0.3, B=5.0, D=-1.0, boundary_type='periodic') + p1 = openmc.Plane(a=0.3, b=5.0, d=1.0, boundary_type='periodic') + p2 = openmc.Plane(a=0.3, b=5.0, d=-1.0, boundary_type='periodic') p1.periodic_surface = p2 Rotationally-periodic boundary conditions can be specified for a pair of diff --git a/docs/source/usersguide/volume.rst b/docs/source/usersguide/volume.rst index 482f66fd0..e4bdbf715 100644 --- a/docs/source/usersguide/volume.rst +++ b/docs/source/usersguide/volume.rst @@ -30,7 +30,7 @@ arguments are not necessary. For example, :: - sphere = openmc.Sphere(R=10.0) + sphere = openmc.Sphere(r=10.0) cell = openm.Cell(region=-sphere) vol_calc = openmc.VolumeCalculation([cell], 1000000) diff --git a/examples/python/basic/build-xml.py b/examples/python/basic/build-xml.py index 0dc83ed44..5caed2810 100644 --- a/examples/python/basic/build-xml.py +++ b/examples/python/basic/build-xml.py @@ -36,9 +36,9 @@ materials_file.export_to_xml() ############################################################################### # Instantiate ZCylinder surfaces -surf1 = openmc.ZCylinder(surface_id=1, x0=0, y0=0, R=7, name='surf 1') -surf2 = openmc.ZCylinder(surface_id=2, x0=0, y0=0, R=9, name='surf 2') -surf3 = openmc.ZCylinder(surface_id=3, x0=0, y0=0, R=11, name='surf 3') +surf1 = openmc.ZCylinder(surface_id=1, x0=0, y0=0, r=7, name='surf 1') +surf2 = openmc.ZCylinder(surface_id=2, x0=0, y0=0, r=9, name='surf 2') +surf3 = openmc.ZCylinder(surface_id=3, x0=0, y0=0, r=11, name='surf 3') surf3.boundary_type = 'vacuum' # Instantiate Cells diff --git a/examples/python/lattice/hexagonal/build-xml.py b/examples/python/lattice/hexagonal/build-xml.py index 24087be9e..c0aa815b4 100644 --- a/examples/python/lattice/hexagonal/build-xml.py +++ b/examples/python/lattice/hexagonal/build-xml.py @@ -43,7 +43,7 @@ left = openmc.XPlane(surface_id=1, x0=-3, name='left') right = openmc.XPlane(surface_id=2, x0=3, name='right') bottom = openmc.YPlane(surface_id=3, y0=-4, name='bottom') top = openmc.YPlane(surface_id=4, y0=4, name='top') -fuel_surf = openmc.ZCylinder(surface_id=5, x0=0, y0=0, R=0.4) +fuel_surf = openmc.ZCylinder(surface_id=5, x0=0, y0=0, r=0.4) left.boundary_type = 'vacuum' right.boundary_type = 'vacuum' diff --git a/examples/python/lattice/nested/build-xml.py b/examples/python/lattice/nested/build-xml.py index ef74173f5..37483a939 100644 --- a/examples/python/lattice/nested/build-xml.py +++ b/examples/python/lattice/nested/build-xml.py @@ -39,9 +39,9 @@ left = openmc.XPlane(surface_id=1, x0=-2, name='left') right = openmc.XPlane(surface_id=2, x0=2, name='right') bottom = openmc.YPlane(surface_id=3, y0=-2, name='bottom') top = openmc.YPlane(surface_id=4, y0=2, name='top') -fuel1 = openmc.ZCylinder(surface_id=5, x0=0, y0=0, R=0.4) -fuel2 = openmc.ZCylinder(surface_id=6, x0=0, y0=0, R=0.3) -fuel3 = openmc.ZCylinder(surface_id=7, x0=0, y0=0, R=0.2) +fuel1 = openmc.ZCylinder(surface_id=5, x0=0, y0=0, r=0.4) +fuel2 = openmc.ZCylinder(surface_id=6, x0=0, y0=0, r=0.3) +fuel3 = openmc.ZCylinder(surface_id=7, x0=0, y0=0, r=0.2) left.boundary_type = 'vacuum' right.boundary_type = 'vacuum' diff --git a/examples/python/lattice/simple/build-xml.py b/examples/python/lattice/simple/build-xml.py index 6222cd366..1cdfa24f3 100644 --- a/examples/python/lattice/simple/build-xml.py +++ b/examples/python/lattice/simple/build-xml.py @@ -39,9 +39,9 @@ left = openmc.XPlane(surface_id=1, x0=-2, name='left') right = openmc.XPlane(surface_id=2, x0=2, name='right') bottom = openmc.YPlane(surface_id=3, y0=-2, name='bottom') top = openmc.YPlane(surface_id=4, y0=2, name='top') -fuel1 = openmc.ZCylinder(surface_id=5, x0=0, y0=0, R=0.4) -fuel2 = openmc.ZCylinder(surface_id=6, x0=0, y0=0, R=0.3) -fuel3 = openmc.ZCylinder(surface_id=7, x0=0, y0=0, R=0.2) +fuel1 = openmc.ZCylinder(surface_id=5, x0=0, y0=0, r=0.4) +fuel2 = openmc.ZCylinder(surface_id=6, x0=0, y0=0, r=0.3) +fuel3 = openmc.ZCylinder(surface_id=7, x0=0, y0=0, r=0.2) left.boundary_type = 'vacuum' right.boundary_type = 'vacuum' diff --git a/examples/python/pincell/build-xml.py b/examples/python/pincell/build-xml.py index a9e6a5a74..c728d5f36 100644 --- a/examples/python/pincell/build-xml.py +++ b/examples/python/pincell/build-xml.py @@ -49,9 +49,9 @@ materials_file.export_to_xml() ############################################################################### # Instantiate ZCylinder surfaces -fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, R=0.39218, name='Fuel OR') -clad_ir = openmc.ZCylinder(surface_id=2, x0=0, y0=0, R=0.40005, name='Clad IR') -clad_or = openmc.ZCylinder(surface_id=3, x0=0, y0=0, R=0.45720, name='Clad OR') +fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, r=0.39218, name='Fuel OR') +clad_ir = openmc.ZCylinder(surface_id=2, x0=0, y0=0, r=0.40005, name='Clad IR') +clad_or = openmc.ZCylinder(surface_id=3, x0=0, y0=0, r=0.45720, name='Clad OR') left = openmc.XPlane(surface_id=4, x0=-0.62992, name='left') right = openmc.XPlane(surface_id=5, x0=0.62992, name='right') bottom = openmc.YPlane(surface_id=6, y0=-0.62992, name='bottom') diff --git a/examples/python/pincell_depletion/run_depletion.py b/examples/python/pincell_depletion/run_depletion.py index a2a5e0e7f..ba34a3706 100644 --- a/examples/python/pincell_depletion/run_depletion.py +++ b/examples/python/pincell_depletion/run_depletion.py @@ -54,9 +54,9 @@ borated_water.add_s_alpha_beta('c_H_in_H2O') ############################################################################### # Instantiate ZCylinder surfaces -fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, R=0.39218, name='Fuel OR') -clad_ir = openmc.ZCylinder(surface_id=2, x0=0, y0=0, R=0.40005, name='Clad IR') -clad_or = openmc.ZCylinder(surface_id=3, x0=0, y0=0, R=0.45720, name='Clad OR') +fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, r=0.39218, name='Fuel OR') +clad_ir = openmc.ZCylinder(surface_id=2, x0=0, y0=0, r=0.40005, name='Clad IR') +clad_or = openmc.ZCylinder(surface_id=3, x0=0, y0=0, r=0.45720, name='Clad OR') left = openmc.XPlane(surface_id=4, x0=-0.62992, name='left') right = openmc.XPlane(surface_id=5, x0=0.62992, name='right') bottom = openmc.YPlane(surface_id=6, y0=-0.62992, name='bottom') diff --git a/examples/python/pincell_multigroup/build-xml.py b/examples/python/pincell_multigroup/build-xml.py index 337044508..995cd87db 100644 --- a/examples/python/pincell_multigroup/build-xml.py +++ b/examples/python/pincell_multigroup/build-xml.py @@ -98,7 +98,7 @@ materials_file.export_to_xml() ############################################################################### # Instantiate ZCylinder surfaces -fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, R=0.54, name='Fuel OR') +fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, r=0.54, name='Fuel OR') left = openmc.XPlane(surface_id=4, x0=-0.63, name='left') right = openmc.XPlane(surface_id=5, x0=0.63, name='right') bottom = openmc.YPlane(surface_id=6, y0=-0.63, name='bottom') diff --git a/openmc/examples.py b/openmc/examples.py index a5138377e..4e8c8cf92 100644 --- a/openmc/examples.py +++ b/openmc/examples.py @@ -51,8 +51,8 @@ def pwr_pin_cell(): # Instantiate ZCylinder surfaces pitch = 1.26 - fuel_or = openmc.ZCylinder(x0=0, y0=0, R=0.39218, name='Fuel OR') - clad_or = openmc.ZCylinder(x0=0, y0=0, R=0.45720, name='Clad OR') + fuel_or = openmc.ZCylinder(x0=0, y0=0, r=0.39218, name='Fuel OR') + clad_or = openmc.ZCylinder(x0=0, y0=0, r=0.45720, name='Clad OR') left = openmc.XPlane(x0=-pitch/2, name='left', boundary_type='reflective') right = openmc.XPlane(x0=pitch/2, name='right', boundary_type='reflective') bottom = openmc.YPlane(y0=-pitch/2, name='bottom', @@ -256,14 +256,14 @@ def pwr_core(): bot_nozzle, top_nozzle, top_fa, bot_fa) # Define surfaces. - s1 = openmc.ZCylinder(R=0.41, surface_id=1) - s2 = openmc.ZCylinder(R=0.475, surface_id=2) - s3 = openmc.ZCylinder(R=0.56, surface_id=3) - s4 = openmc.ZCylinder(R=0.62, surface_id=4) - s5 = openmc.ZCylinder(R=187.6, surface_id=5) - s6 = openmc.ZCylinder(R=209.0, surface_id=6) - s7 = openmc.ZCylinder(R=229.0, surface_id=7) - s8 = openmc.ZCylinder(R=249.0, surface_id=8, boundary_type='vacuum') + s1 = openmc.ZCylinder(r=0.41, surface_id=1) + s2 = openmc.ZCylinder(r=0.475, surface_id=2) + s3 = openmc.ZCylinder(r=0.56, surface_id=3) + s4 = openmc.ZCylinder(r=0.62, surface_id=4) + s5 = openmc.ZCylinder(r=187.6, surface_id=5) + s6 = openmc.ZCylinder(r=209.0, surface_id=6) + s7 = openmc.ZCylinder(r=229.0, surface_id=7) + s8 = openmc.ZCylinder(r=249.0, surface_id=8, boundary_type='vacuum') s31 = openmc.ZPlane(z0=-229.0, surface_id=31, boundary_type='vacuum') s32 = openmc.ZPlane(z0=-199.0, surface_id=32) @@ -473,8 +473,8 @@ def pwr_assembly(): model.materials = (fuel, clad, hot_water) # Instantiate ZCylinder surfaces - fuel_or = openmc.ZCylinder(x0=0, y0=0, R=0.39218, name='Fuel OR') - clad_or = openmc.ZCylinder(x0=0, y0=0, R=0.45720, name='Clad OR') + fuel_or = openmc.ZCylinder(x0=0, y0=0, r=0.39218, name='Fuel OR') + clad_or = openmc.ZCylinder(x0=0, y0=0, r=0.45720, name='Clad OR') # Create boundary planes to surround the geometry pitch = 21.42 diff --git a/openmc/model/funcs.py b/openmc/model/funcs.py index 44e7f95f1..0023a98d9 100644 --- a/openmc/model/funcs.py +++ b/openmc/model/funcs.py @@ -237,16 +237,16 @@ def get_hexagonal_prism(edge_length=1., orientation='y', origin=(0., 0.), c = sqrt(3.)/3. # y = -x/sqrt(3) + a - upper_right = Plane(A=c, B=1., D=l+x*c+y, boundary_type=boundary_type) + upper_right = Plane(a=c, b=1., d=l+x*c+y, boundary_type=boundary_type) # y = x/sqrt(3) + a - upper_left = Plane(A=-c, B=1., D=l-x*c+y, boundary_type=boundary_type) + upper_left = Plane(a=-c, b=1., d=l-x*c+y, boundary_type=boundary_type) # y = x/sqrt(3) - a - lower_right = Plane(A=-c, B=1., D=-l-x*c+y, boundary_type=boundary_type) + lower_right = Plane(a=-c, b=1., d=-l-x*c+y, boundary_type=boundary_type) # y = -x/sqrt(3) - a - lower_left = Plane(A=c, B=1., D=-l+x*c+y, boundary_type=boundary_type) + lower_left = Plane(a=c, b=1., d=-l+x*c+y, boundary_type=boundary_type) prism = -right & +left & -upper_right & -upper_left & \ +lower_right & +lower_left @@ -262,17 +262,17 @@ def get_hexagonal_prism(edge_length=1., orientation='y', origin=(0., 0.), c = sqrt(3.) # y = -sqrt(3)*(x - a) - upper_right = Plane(A=c, B=1., D=c*l+x*c+y, boundary_type=boundary_type) + upper_right = Plane(a=c, b=1., d=c*l+x*c+y, boundary_type=boundary_type) # y = sqrt(3)*(x + a) - lower_right = Plane(A=-c, B=1., D=-c*l-x*c+y, + lower_right = Plane(a=-c, b=1., d=-c*l-x*c+y, boundary_type=boundary_type) # y = -sqrt(3)*(x + a) - lower_left = Plane(A=c, B=1., D=-c*l+x*c+y, boundary_type=boundary_type) + lower_left = Plane(a=c, b=1., d=-c*l+x*c+y, boundary_type=boundary_type) # y = sqrt(3)*(x + a) - upper_left = Plane(A=-c, B=1., D=c*l-x*c+y, boundary_type=boundary_type) + upper_left = Plane(a=-c, b=1., d=c*l-x*c+y, boundary_type=boundary_type) prism = -top & +bottom & -upper_right & +lower_right & \ +lower_left & -upper_left @@ -292,8 +292,8 @@ def get_hexagonal_prism(edge_length=1., orientation='y', origin=(0., 0.), t = l - corner_radius/c # Cylinder with corner radius and boundary type pre-applied - cyl1 = partial(ZCylinder, R=corner_radius, boundary_type=boundary_type) - cyl2 = partial(ZCylinder, R=corner_radius/(2*c), + cyl1 = partial(ZCylinder, r=corner_radius, boundary_type=boundary_type) + cyl2 = partial(ZCylinder, r=corner_radius/(2*c), boundary_type=boundary_type) if orientation == 'x': diff --git a/openmc/model/triso.py b/openmc/model/triso.py index e04d7f589..2afc88d64 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -49,7 +49,7 @@ class TRISO(openmc.Cell): """ def __init__(self, outer_radius, fill, center=(0., 0., 0.)): - self._surface = openmc.Sphere(R=outer_radius) + self._surface = openmc.Sphere(r=outer_radius) super().__init__(fill=fill, region=-self._surface) self.center = np.asarray(center) diff --git a/openmc/region.py b/openmc/region.py index e8e42776c..d12ae7112 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -261,7 +261,7 @@ class Intersection(Region, MutableSequence): following example: >>> equator = openmc.ZPlane(z0=0.0) - >>> earth = openmc.Sphere(R=637.1e6) + >>> earth = openmc.Sphere(r=637.1e6) >>> northern_hemisphere = -earth & +equator >>> southern_hemisphere = -earth & -equator >>> type(northern_hemisphere) @@ -396,7 +396,7 @@ class Union(Region, MutableSequence): example: >>> s1 = openmc.ZPlane(z0=0.0) - >>> s2 = openmc.Sphere(R=637.1e6) + >>> s2 = openmc.Sphere(r=637.1e6) >>> type(-s2 | +s1) diff --git a/openmc/surface.py b/openmc/surface.py index 306fb6d73..4c44c68b6 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -4,6 +4,7 @@ from copy import deepcopy from functools import partial from numbers import Real, Integral from xml.etree import ElementTree as ET +from warnings import warn import numpy as np @@ -14,6 +15,11 @@ from openmc.mixin import IDManagerMixin _BOUNDARY_TYPES = ['transmission', 'vacuum', 'reflective', 'periodic'] +_WARNING_UPPER = """\ +"{}(...) accepts an argument named '{}', not '{}'. Future versions of OpenMC \ +will not accept the capitalized version.\ +""" + class Surface(IDManagerMixin, metaclass=ABCMeta): """An implicit surface with an associated boundary condition. @@ -287,29 +293,29 @@ class Surface(IDManagerMixin, metaclass=ABCMeta): surface = Plane(surface_id, bc, A, B, C, D, name) elif surf_type == 'x-cylinder': - y0, z0, R = coeffs - surface = XCylinder(surface_id, bc, y0, z0, R, name) + y0, z0, r = coeffs + surface = XCylinder(surface_id, bc, y0, z0, r, name) elif surf_type == 'y-cylinder': - x0, z0, R = coeffs - surface = YCylinder(surface_id, bc, x0, z0, R, name) + x0, z0, r = coeffs + surface = YCylinder(surface_id, bc, x0, z0, r, name) elif surf_type == 'z-cylinder': - x0, y0, R = coeffs - surface = ZCylinder(surface_id, bc, x0, y0, R, name) + x0, y0, r = coeffs + surface = ZCylinder(surface_id, bc, x0, y0, r, name) elif surf_type == 'sphere': - x0, y0, z0, R = coeffs - surface = Sphere(surface_id, bc, x0, y0, z0, R, name) + x0, y0, z0, r = coeffs + surface = Sphere(surface_id, bc, x0, y0, z0, r, name) elif surf_type in ['x-cone', 'y-cone', 'z-cone']: - x0, y0, z0, R2 = coeffs + x0, y0, z0, r2 = coeffs if surf_type == 'x-cone': - surface = XCone(surface_id, bc, x0, y0, z0, R2, name) + surface = XCone(surface_id, bc, x0, y0, z0, r2, name) elif surf_type == 'y-cone': - surface = YCone(surface_id, bc, x0, y0, z0, R2, name) + surface = YCone(surface_id, bc, x0, y0, z0, r2, name) elif surf_type == 'z-cone': - surface = ZCone(surface_id, bc, x0, y0, z0, R2, name) + surface = ZCone(surface_id, bc, x0, y0, z0, r2, name) elif surf_type == 'quadric': a, b, c, d, e, f, g, h, j, k = coeffs @@ -331,13 +337,13 @@ class Plane(Surface): Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - A : float, optional + a : float, optional The 'A' parameter for the plane. Defaults to 1. - B : float, optional + b : float, optional The 'B' parameter for the plane. Defaults to 0. - C : float, optional + c : float, optional The 'C' parameter for the plane. Defaults to 0. - D : float, optional + d : float, optional The 'D' parameter for the plane. Defaults to 0. name : str, optional Name of the plane. If not specified, the name will be the empty string. @@ -370,56 +376,61 @@ class Plane(Surface): """ _type = 'plane' - _coeff_keys = ('A', 'B', 'C', 'D') + _coeff_keys = ('a', 'b', 'c', 'd') def __init__(self, surface_id=None, boundary_type='transmission', - A=1., B=0., C=0., D=0., name=''): + a=1., b=0., c=0., d=0., name='', **kwargs): super().__init__(surface_id, boundary_type, name=name) self._periodic_surface = None - self.a = A - self.b = B - self.c = C - self.d = D + self.a = a + self.b = b + self.c = c + self.d = d + for k, v in kwargs.items(): + if k in 'ABCD': + warn(_WARNING_UPPER.format(type(self).__name__, k.lower(), k), + FutureWarning) + setattr(self, k.lower(), v) @property def a(self): - return self.coefficients['A'] + return self.coefficients['a'] @property def b(self): - return self.coefficients['B'] + return self.coefficients['b'] @property def c(self): - return self.coefficients['C'] + return self.coefficients['c'] @property def d(self): - return self.coefficients['D'] + return self.coefficients['d'] @property def periodic_surface(self): return self._periodic_surface @a.setter - def a(self, A): - check_type('A coefficient', A, Real) - self._coefficients['A'] = A + def a(self, a): + check_type('A coefficient', a, Real) + self._coefficients['a'] = a @b.setter - def b(self, B): - check_type('B coefficient', B, Real) - self._coefficients['B'] = B + def b(self, b): + check_type('B coefficient', b, Real) + self._coefficients['b'] = b @c.setter - def c(self, C): - check_type('C coefficient', C, Real) - self._coefficients['C'] = C + def c(self, c): + check_type('C coefficient', c, Real) + self._coefficients['c'] = c @d.setter - def d(self, D): - check_type('D coefficient', D, Real) - self._coefficients['D'] = D + def d(self, d): + check_type('D coefficient', d, Real) + self._coefficients['d'] = d @periodic_surface.setter def periodic_surface(self, periodic_surface): @@ -465,7 +476,7 @@ class Plane(Surface): if d == self.d: return self else: - return type(self)(A=self.a, B=self.b, C=self.c, D=d) + return type(self)(a=self.a, b=self.b, c=self.c, d=d) def to_xml_element(self): """Return XML representation of the surface @@ -511,10 +522,10 @@ class Plane(Surface): n = np.cross(p2 - p1, p3 - p1) # The equation of the plane will by n·( - p1) = 0. Determine - # coefficients A, B, C, and D based on that - A, B, C = n - D = np.dot(n, p1) - return cls(A=A, B=B, C=C, D=D, **kwargs) + # coefficients a, b, c, and d based on that + a, b, c = n + d = np.dot(n, p1) + return cls(a=a, b=b, c=c, d=d, **kwargs) class XPlane(Plane): @@ -906,7 +917,7 @@ class Cylinder(Surface): Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. - R : float, optional + r : float, optional Radius of the cylinder. Defaults to 1. name : str, optional Name of the cylinder. If not specified, the name will be the empty @@ -930,23 +941,23 @@ class Cylinder(Surface): """ def __init__(self, surface_id=None, boundary_type='transmission', - R=1., name=''): + r=1., name=''): super().__init__(surface_id, boundary_type, name=name) - self.r = R + self.r = r @property def r(self): - return self.coefficients['R'] + return self.coefficients['r'] @r.setter - def r(self, R): - check_type('R coefficient', R, Real) - self._coefficients['R'] = R + def r(self, r): + check_type('r coefficient', r, Real) + self._coefficients['r'] = r class XCylinder(Cylinder): """An infinite cylinder whose length is parallel to the x-axis of the form - :math:`(y - y_0)^2 + (z - z_0)^2 = R^2`. + :math:`(y - y_0)^2 + (z - z_0)^2 = r^2`. Parameters ---------- @@ -961,7 +972,7 @@ class XCylinder(Cylinder): y-coordinate of the center of the cylinder. Defaults to 0. z0 : float, optional z-coordinate of the center of the cylinder. Defaults to 0. - R : float, optional + r : float, optional Radius of the cylinder. Defaults to 0. name : str, optional Name of the cylinder. If not specified, the name will be the empty @@ -988,11 +999,14 @@ class XCylinder(Cylinder): """ _type = 'x-cylinder' - _coeff_keys = ('y0', 'z0', 'R') + _coeff_keys = ('y0', 'z0', 'r') def __init__(self, surface_id=None, boundary_type='transmission', - y0=0., z0=0., R=1., name=''): - super().__init__(surface_id, boundary_type, R, name=name) + y0=0., z0=0., r=1., name='', *, R=None): + if R is not None: + warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning) + r = R + super().__init__(surface_id, boundary_type, r, name=name) self.y0 = y0 self.z0 = z0 @@ -1058,7 +1072,7 @@ class XCylinder(Cylinder): Returns ------- float - :math:`(y' - y_0)^2 + (z' - z_0)^2 - R^2` + :math:`(y' - y_0)^2 + (z' - z_0)^2 - r^2` """ y = point[1] - self.y0 @@ -1085,12 +1099,12 @@ class XCylinder(Cylinder): else: y0 = self.y0 + vy z0 = self.z0 + vz - return type(self)(y0=y0, z0=z0, R=self.r) + return type(self)(y0=y0, z0=z0, r=self.r) class YCylinder(Cylinder): """An infinite cylinder whose length is parallel to the y-axis of the form - :math:`(x - x_0)^2 + (z - z_0)^2 = R^2`. + :math:`(x - x_0)^2 + (z - z_0)^2 = r^2`. Parameters ---------- @@ -1105,7 +1119,7 @@ class YCylinder(Cylinder): x-coordinate of the center of the cylinder. Defaults to 0. z0 : float, optional z-coordinate of the center of the cylinder. Defaults to 0. - R : float, optional + r : float, optional Radius of the cylinder. Defaults to 1. name : str, optional Name of the cylinder. If not specified, the name will be the empty @@ -1132,11 +1146,14 @@ class YCylinder(Cylinder): """ _type = 'y-cylinder' - _coeff_keys = ('x0', 'z0', 'R') + _coeff_keys = ('x0', 'z0', 'r') def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., z0=0., R=1., name=''): - super().__init__(surface_id, boundary_type, R, name=name) + x0=0., z0=0., r=1., name='', *, R=None): + if R is not None: + warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning) + r = R + super().__init__(surface_id, boundary_type, r, name=name) self.x0 = x0 self.z0 = z0 @@ -1202,7 +1219,7 @@ class YCylinder(Cylinder): Returns ------- float - :math:`(x' - x_0)^2 + (z' - z_0)^2 - R^2` + :math:`(x' - x_0)^2 + (z' - z_0)^2 - r^2` """ x = point[0] - self.x0 @@ -1229,12 +1246,12 @@ class YCylinder(Cylinder): else: x0 = self.x0 + vx z0 = self.z0 + vz - return type(self)(x0=x0, z0=z0, R=self.r) + return type(self)(x0=x0, z0=z0, r=self.r) class ZCylinder(Cylinder): """An infinite cylinder whose length is parallel to the z-axis of the form - :math:`(x - x_0)^2 + (y - y_0)^2 = R^2`. + :math:`(x - x_0)^2 + (y - y_0)^2 = r^2`. Parameters ---------- @@ -1249,7 +1266,7 @@ class ZCylinder(Cylinder): x-coordinate of the center of the cylinder. Defaults to 0. y0 : float, optional y-coordinate of the center of the cylinder. Defaults to 0. - R : float, optional + r : float, optional Radius of the cylinder. Defaults to 1. name : str, optional Name of the cylinder. If not specified, the name will be the empty @@ -1276,11 +1293,14 @@ class ZCylinder(Cylinder): """ _type = 'z-cylinder' - _coeff_keys = ('x0', 'y0', 'R') + _coeff_keys = ('x0', 'y0', 'r') def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., y0=0., R=1., name=''): - super().__init__(surface_id, boundary_type, R, name=name) + x0=0., y0=0., r=1., name='', *, R=None): + if R is not None: + warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning) + r = R + super().__init__(surface_id, boundary_type, r, name=name) self.x0 = x0 self.y0 = y0 @@ -1346,7 +1366,7 @@ class ZCylinder(Cylinder): Returns ------- float - :math:`(x' - x_0)^2 + (y' - y_0)^2 - R^2` + :math:`(x' - x_0)^2 + (y' - y_0)^2 - r^2` """ x = point[0] - self.x0 @@ -1373,11 +1393,11 @@ class ZCylinder(Cylinder): else: x0 = self.x0 + vx y0 = self.y0 + vy - return type(self)(x0=x0, y0=y0, R=self.r) + return type(self)(x0=x0, y0=y0, r=self.r) class Sphere(Surface): - """A sphere of the form :math:`(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 = R^2`. + """A sphere of the form :math:`(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 = r^2`. Parameters ---------- @@ -1394,7 +1414,7 @@ class Sphere(Surface): y-coordinate of the center of the sphere. Defaults to 0. z0 : float, optional z-coordinate of the center of the sphere. Defaults to 0. - R : float, optional + r : float, optional Radius of the sphere. Defaults to 1. name : str, optional Name of the sphere. If not specified, the name will be the empty string. @@ -1424,15 +1444,18 @@ class Sphere(Surface): """ _type = 'sphere' - _coeff_keys = ('x0', 'y0', 'z0', 'R') + _coeff_keys = ('x0', 'y0', 'z0', 'r') def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., y0=0., z0=0., R=1., name=''): + x0=0., y0=0., z0=0., r=1., name='', *, R=None): + if R is not None: + warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning) + r = R super().__init__(surface_id, boundary_type, name=name) self.x0 = x0 self.y0 = y0 self.z0 = z0 - self.r = R + self.r = r @property def x0(self): @@ -1448,7 +1471,7 @@ class Sphere(Surface): @property def r(self): - return self.coefficients['R'] + return self.coefficients['r'] @x0.setter def x0(self, x0): @@ -1466,9 +1489,9 @@ class Sphere(Surface): self._coefficients['z0'] = z0 @r.setter - def r(self, R): - check_type('R coefficient', R, Real) - self._coefficients['R'] = R + def r(self, r): + check_type('r coefficient', r, Real) + self._coefficients['r'] = r def bounding_box(self, side): """Determine an axis-aligned bounding box. @@ -1515,7 +1538,7 @@ class Sphere(Surface): Returns ------- float - :math:`(x' - x_0)^2 + (y' - y_0)^2 + (z' - z_0)^2 - R^2` + :math:`(x' - x_0)^2 + (y' - y_0)^2 + (z' - z_0)^2 - r^2` """ x = point[0] - self.x0 @@ -1544,7 +1567,7 @@ class Sphere(Surface): x0 = self.x0 + vx y0 = self.y0 + vy z0 = self.z0 + vz - return type(self)(x0=x0, y0=y0, z0=z0, R=self.r) + return type(self)(x0=x0, y0=y0, z0=z0, r=self.r) class Cone(Surface): @@ -1565,7 +1588,7 @@ class Cone(Surface): y-coordinate of the apex. Defaults to 0. z0 : float z-coordinate of the apex. Defaults to 0. - R2 : float + r2 : float Parameter related to the aperature. Defaults to 1. name : str Name of the cone. If not specified, the name will be the empty string. @@ -1594,15 +1617,18 @@ class Cone(Surface): """ - _coeff_keys = ('x0', 'y0', 'z0', 'R2') + _coeff_keys = ('x0', 'y0', 'z0', 'r2') def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., y0=0., z0=0., R2=1., name=''): + x0=0., y0=0., z0=0., r2=1., name='', *, R2=None): + if R2 is not None: + warn(_WARNING_UPPER.format(type(self).__name__, 'r2', 'R2'), FutureWarning) + r2 = R2 super().__init__(surface_id, boundary_type, name=name) self.x0 = x0 self.y0 = y0 self.z0 = z0 - self.r2 = R2 + self.r2 = r2 @property def x0(self): @@ -1618,7 +1644,7 @@ class Cone(Surface): @property def r2(self): - return self.coefficients['R2'] + return self.coefficients['r2'] @x0.setter def x0(self, x0): @@ -1636,9 +1662,9 @@ class Cone(Surface): self._coefficients['z0'] = z0 @r2.setter - def r2(self, R2): - check_type('R^2 coefficient', R2, Real) - self._coefficients['R2'] = R2 + def r2(self, r2): + check_type('r^2 coefficient', r2, Real) + self._coefficients['r2'] = r2 def translate(self, vector): """Translate surface in given direction @@ -1661,12 +1687,12 @@ class Cone(Surface): x0 = self.x0 + vx y0 = self.y0 + vy z0 = self.z0 + vz - return type(self)(x0=x0, y0=y0, z0=z0, R2=self.r2) + return type(self)(x0=x0, y0=y0, z0=z0, r2=self.r2) class XCone(Cone): """A cone parallel to the x-axis of the form :math:`(y - y_0)^2 + (z - z_0)^2 = - R^2 (x - x_0)^2`. + r^2 (x - x_0)^2`. Parameters ---------- @@ -1683,7 +1709,7 @@ class XCone(Cone): y-coordinate of the apex. Defaults to 0. z0 : float, optional z-coordinate of the apex. Defaults to 0. - R2 : float, optional + r2 : float, optional Parameter related to the aperature. Defaults to 1. name : str, optional Name of the cone. If not specified, the name will be the empty string. @@ -1696,7 +1722,7 @@ class XCone(Cone): y-coordinate of the apex z0 : float z-coordinate of the apex - R2 : float + r2 : float Parameter related to the aperature boundary_type : {'transmission, 'vacuum', 'reflective'} Boundary condition that defines the behavior for particles hitting the @@ -1726,7 +1752,7 @@ class XCone(Cone): Returns ------- float - :math:`(y' - y_0)^2 + (z' - z_0)^2 - R^2(x' - x_0)^2` + :math:`(y' - y_0)^2 + (z' - z_0)^2 - r^2(x' - x_0)^2` """ x = point[0] - self.x0 @@ -1737,7 +1763,7 @@ class XCone(Cone): class YCone(Cone): """A cone parallel to the y-axis of the form :math:`(x - x_0)^2 + (z - z_0)^2 = - R^2 (y - y_0)^2`. + r^2 (y - y_0)^2`. Parameters ---------- @@ -1754,7 +1780,7 @@ class YCone(Cone): y-coordinate of the apex. Defaults to 0. z0 : float, optional z-coordinate of the apex. Defaults to 0. - R2 : float, optional + r2 : float, optional Parameter related to the aperature. Defaults to 1. name : str, optional Name of the cone. If not specified, the name will be the empty string. @@ -1767,7 +1793,7 @@ class YCone(Cone): y-coordinate of the apex z0 : float z-coordinate of the apex - R2 : float + r2 : float Parameter related to the aperature boundary_type : {'transmission, 'vacuum', 'reflective'} Boundary condition that defines the behavior for particles hitting the @@ -1797,7 +1823,7 @@ class YCone(Cone): Returns ------- float - :math:`(x' - x_0)^2 + (z' - z_0)^2 - R^2(y' - y_0)^2` + :math:`(x' - x_0)^2 + (z' - z_0)^2 - r^2(y' - y_0)^2` """ x = point[0] - self.x0 @@ -1808,7 +1834,7 @@ class YCone(Cone): class ZCone(Cone): """A cone parallel to the x-axis of the form :math:`(x - x_0)^2 + (y - y_0)^2 = - R^2 (z - z_0)^2`. + r^2 (z - z_0)^2`. Parameters ---------- @@ -1825,7 +1851,7 @@ class ZCone(Cone): y-coordinate of the apex. Defaults to 0. z0 : float, optional z-coordinate of the apex. Defaults to 0. - R2 : float, optional + r2 : float, optional Parameter related to the aperature. Defaults to 1. name : str, optional Name of the cone. If not specified, the name will be the empty string. @@ -1838,7 +1864,7 @@ class ZCone(Cone): y-coordinate of the apex z0 : float z-coordinate of the apex - R2 : float + r2 : float Parameter related to the aperature boundary_type : {'transmission, 'vacuum', 'reflective'} Boundary condition that defines the behavior for particles hitting the @@ -1868,7 +1894,7 @@ class ZCone(Cone): Returns ------- float - :math:`(x' - x_0)^2 + (y' - y_0)^2 - R^2(z' - z_0)^2` + :math:`(x' - x_0)^2 + (y' - y_0)^2 - r^2(z' - z_0)^2` """ x = point[0] - self.x0 @@ -2080,7 +2106,7 @@ class Halfspace(Region): can be created from an existing Surface through the __neg__ and __pos__ operators, as the following example demonstrates: - >>> sphere = openmc.Sphere(surface_id=1, R=10.0) + >>> sphere = openmc.Sphere(surface_id=1, r=10.0) >>> inside_sphere = -sphere >>> outside_sphere = +sphere >>> type(inside_sphere) diff --git a/tests/regression_tests/deplete/example_geometry.py b/tests/regression_tests/deplete/example_geometry.py index e54c087f6..d4fdf585d 100644 --- a/tests/regression_tests/deplete/example_geometry.py +++ b/tests/regression_tests/deplete/example_geometry.py @@ -182,14 +182,14 @@ def segment_pin(n_rings, n_wedges, r_fuel, r_gap, r_clad): theta = np.linspace(0, 2*math.pi, n_wedges + 1) # Compute surfaces - fuel_rings = [openmc.ZCylinder(x0=0, y0=0, R=r_rings[i]) + fuel_rings = [openmc.ZCylinder(x0=0, y0=0, r=r_rings[i]) for i in range(n_rings)] - fuel_wedges = [openmc.Plane(A=math.cos(theta[i]), B=math.sin(theta[i])) + fuel_wedges = [openmc.Plane(a=math.cos(theta[i]), b=math.sin(theta[i])) for i in range(n_wedges)] - gap_ring = openmc.ZCylinder(x0=0, y0=0, R=r_gap) - clad_ring = openmc.ZCylinder(x0=0, y0=0, R=r_clad) + gap_ring = openmc.ZCylinder(x0=0, y0=0, r=r_gap) + clad_ring = openmc.ZCylinder(x0=0, y0=0, r=r_clad) # Create cells fuel_cells = [] diff --git a/tests/regression_tests/distribmat/test.py b/tests/regression_tests/distribmat/test.py index cb598b9d3..33f64ba03 100644 --- a/tests/regression_tests/distribmat/test.py +++ b/tests/regression_tests/distribmat/test.py @@ -32,7 +32,7 @@ class DistribmatTestHarness(PyAPITestHarness): c1 = openmc.Cell(cell_id=1, fill=moderator) mod_univ = openmc.Universe(universe_id=1, cells=[c1]) - r0 = openmc.ZCylinder(R=0.3) + r0 = openmc.ZCylinder(r=0.3) c11 = openmc.Cell(cell_id=11, region=-r0) c11.fill = [dense_fuel, None, light_fuel, dense_fuel] c12 = openmc.Cell(cell_id=12, region=+r0, fill=moderator) diff --git a/tests/regression_tests/fixed_source/test.py b/tests/regression_tests/fixed_source/test.py index 7d98de9fc..74908f87c 100644 --- a/tests/regression_tests/fixed_source/test.py +++ b/tests/regression_tests/fixed_source/test.py @@ -37,7 +37,7 @@ def test_fixed_source(): mat.add_nuclide('U238', 0.0001) mat.set_density('g/cc', 7.5) - surf = openmc.Sphere(R=10.0, boundary_type='vacuum') + surf = openmc.Sphere(r=10.0, boundary_type='vacuum') cell = openmc.Cell(fill=mat, region=-surf) model = openmc.model.Model() diff --git a/tests/regression_tests/multipole/test.py b/tests/regression_tests/multipole/test.py index c826ff0d7..4c4353c84 100644 --- a/tests/regression_tests/multipole/test.py +++ b/tests/regression_tests/multipole/test.py @@ -27,7 +27,7 @@ def make_model(): c1 = openmc.Cell(cell_id=1, fill=moderator) mod_univ = openmc.Universe(universe_id=1, cells=(c1,)) - r0 = openmc.ZCylinder(R=0.3) + r0 = openmc.ZCylinder(r=0.3) c11 = openmc.Cell(cell_id=11, fill=dense_fuel, region=-r0) c11.temperature = [500, 700, 0, 800] c12 = openmc.Cell(cell_id=12, fill=moderator, region=+r0) diff --git a/tests/regression_tests/periodic/test.py b/tests/regression_tests/periodic/test.py index d746ebdd5..5df935b22 100644 --- a/tests/regression_tests/periodic/test.py +++ b/tests/regression_tests/periodic/test.py @@ -30,7 +30,7 @@ class PeriodicTest(PyAPITestHarness): z_min = openmc.ZPlane(5, z0=-5., boundary_type='reflective') z_max = openmc.ZPlane(6, z0=5., boundary_type='reflective') - z_cyl = openmc.ZCylinder(7, x0=-2.5, y0=2.5, R=2.0) + z_cyl = openmc.ZCylinder(7, x0=-2.5, y0=2.5, r=2.0) outside_cyl = openmc.Cell(1, fill=water, region=( +x_min & -x_max & +y_min & -y_max & +z_min & -z_max & +z_cyl)) diff --git a/tests/regression_tests/photon_production/test.py b/tests/regression_tests/photon_production/test.py index 68992c867..df6375e13 100644 --- a/tests/regression_tests/photon_production/test.py +++ b/tests/regression_tests/photon_production/test.py @@ -14,7 +14,7 @@ class SourceTestHarness(PyAPITestHarness): materials = openmc.Materials([mat]) materials.export_to_xml() - cyl = openmc.XCylinder(boundary_type='vacuum', R=1.0e-6) + cyl = openmc.XCylinder(boundary_type='vacuum', r=1.0e-6) x_plane_left = openmc.XPlane(boundary_type='vacuum', x0=-1.0) x_plane_center = openmc.XPlane(boundary_type='transmission', x0=1.0) x_plane_right = openmc.XPlane(boundary_type='vacuum', x0=1.0e9) diff --git a/tests/regression_tests/photon_source/test.py b/tests/regression_tests/photon_source/test.py index 61367d375..94b028003 100644 --- a/tests/regression_tests/photon_source/test.py +++ b/tests/regression_tests/photon_source/test.py @@ -15,19 +15,19 @@ class SourceTestHarness(PyAPITestHarness): materials = openmc.Materials([mat]) materials.export_to_xml() - sphere = openmc.Sphere(R=1.0e9, boundary_type='reflective') + sphere = openmc.Sphere(r=1.0e9, boundary_type='reflective') inside_sphere = openmc.Cell() inside_sphere.region = -sphere inside_sphere.fill = mat geometry = openmc.Geometry([inside_sphere]) geometry.export_to_xml() - + source = openmc.Source() source.space = openmc.stats.Point((0, 0, 0)) source.angle = openmc.stats.Isotropic() source.energy = openmc.stats.Discrete([10.0e6], [1.0]) source.particle = 'photon' - + settings = openmc.Settings() settings.particles = 10000 settings.batches = 1 @@ -37,7 +37,7 @@ class SourceTestHarness(PyAPITestHarness): settings.run_mode = 'fixed source' settings.source = source settings.export_to_xml() - + particle_filter = openmc.ParticleFilter('photon') tally = openmc.Tally() tally.filters = [particle_filter] diff --git a/tests/regression_tests/source/test.py b/tests/regression_tests/source/test.py index 00171a255..cd468c5b8 100644 --- a/tests/regression_tests/source/test.py +++ b/tests/regression_tests/source/test.py @@ -14,7 +14,7 @@ class SourceTestHarness(PyAPITestHarness): materials = openmc.Materials([mat1]) materials.export_to_xml() - sphere = openmc.Sphere(surface_id=1, R=10.0, boundary_type='vacuum') + sphere = openmc.Sphere(surface_id=1, r=10.0, boundary_type='vacuum') inside_sphere = openmc.Cell(cell_id=1) inside_sphere.region = -sphere inside_sphere.fill = mat1 diff --git a/tests/regression_tests/surface_tally/test.py b/tests/regression_tests/surface_tally/test.py index 24dd66314..96199ec2a 100644 --- a/tests/regression_tests/surface_tally/test.py +++ b/tests/regression_tests/surface_tally/test.py @@ -25,8 +25,8 @@ class SurfaceTallyTestHarness(PyAPITestHarness): materials_file.export_to_xml() # Instantiate ZCylinder surfaces - fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, R=1, \ - name='Fuel OR') + fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, r=1, + name='Fuel OR') left = openmc.XPlane(surface_id=2, x0=-2, name='left') right = openmc.XPlane(surface_id=3, x0=2, name='right') bottom = openmc.YPlane(y0=-2, name='bottom') diff --git a/tests/regression_tests/triso/test.py b/tests/regression_tests/triso/test.py index 9ede6dbb0..3b858e6a7 100644 --- a/tests/regression_tests/triso/test.py +++ b/tests/regression_tests/triso/test.py @@ -44,7 +44,7 @@ class TRISOTestHarness(PyAPITestHarness): graphite.add_s_alpha_beta('c_Graphite') # Create TRISO particles - spheres = [openmc.Sphere(R=r*1e-4) + spheres = [openmc.Sphere(r=r*1e-4) for r in [212.5, 312.5, 347.5, 382.5]] c1 = openmc.Cell(fill=fuel, region=-spheres[0]) c2 = openmc.Cell(fill=porous_carbon, region=+spheres[0] & -spheres[1]) diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index fda4b3321..da8399c1f 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -25,10 +25,10 @@ class VolumeTest(PyAPITestHarness): materials = openmc.Materials((water, fuel)) materials.export_to_xml() - cyl = openmc.ZCylinder(1, R=1.0, boundary_type='vacuum') - top_sphere = openmc.Sphere(2, z0=5., R=1., boundary_type='vacuum') + cyl = openmc.ZCylinder(1, r=1.0, boundary_type='vacuum') + top_sphere = openmc.Sphere(2, z0=5., r=1., boundary_type='vacuum') top_plane = openmc.ZPlane(3, z0=5.) - bottom_sphere = openmc.Sphere(4, z0=-5., R=1., boundary_type='vacuum') + bottom_sphere = openmc.Sphere(4, z0=-5., r=1., boundary_type='vacuum') bottom_plane = openmc.ZPlane(5, z0=-5.) # Define geometry diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 94fa6abc7..aa28be9c3 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -46,7 +46,7 @@ def cell_with_lattice(): m_inside = [openmc.Material(), openmc.Material(), None, openmc.Material()] m_outside = openmc.Material() - cyl = openmc.ZCylinder(R=1.0) + cyl = openmc.ZCylinder(r=1.0) inside_cyl = openmc.Cell(fill=m_inside, region=-cyl) outside_cyl = openmc.Cell(fill=m_outside, region=+cyl) univ = openmc.Universe(cells=[inside_cyl, outside_cyl]) @@ -63,7 +63,7 @@ def cell_with_lattice(): @pytest.fixture def mixed_lattice_model(uo2, water): - cyl = openmc.ZCylinder(R=0.4) + cyl = openmc.ZCylinder(r=0.4) c1 = openmc.Cell(fill=uo2, region=-cyl) c1.temperature = 600.0 c2 = openmc.Cell(fill=water, region=+cyl) diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index b5d6076bb..4968c6fa3 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -10,8 +10,8 @@ def test_volume(run_in_tmpdir, uo2): # Create model with nested spheres model = openmc.model.Model() model.materials.append(uo2) - inner = openmc.Sphere(R=1.) - outer = openmc.Sphere(R=2., boundary_type='vacuum') + inner = openmc.Sphere(r=1.) + outer = openmc.Sphere(r=2., boundary_type='vacuum') c1 = openmc.Cell(fill=uo2, region=-inner) c2 = openmc.Cell(region=+inner & -outer) u = openmc.Universe(cells=[c1, c2]) @@ -44,8 +44,8 @@ def test_volume(run_in_tmpdir, uo2): def test_export_xml(run_in_tmpdir, uo2): - s1 = openmc.Sphere(R=1.) - s2 = openmc.Sphere(R=2., boundary_type='reflective') + s1 = openmc.Sphere(r=1.) + s2 = openmc.Sphere(r=2., boundary_type='reflective') c1 = openmc.Cell(fill=uo2, region=-s1) c2 = openmc.Cell(fill=uo2, region=+s1 & -s2) geom = openmc.Geometry([c1, c2]) diff --git a/tests/unit_tests/test_lattice.py b/tests/unit_tests/test_lattice.py index 47dc1c029..fe86e2a78 100644 --- a/tests/unit_tests/test_lattice.py +++ b/tests/unit_tests/test_lattice.py @@ -7,7 +7,7 @@ import pytest @pytest.fixture(scope='module') def pincell1(uo2, water): - cyl = openmc.ZCylinder(R=0.35) + cyl = openmc.ZCylinder(r=0.35) fuel = openmc.Cell(fill=uo2, region=-cyl) moderator = openmc.Cell(fill=water, region=+cyl) @@ -19,7 +19,7 @@ def pincell1(uo2, water): @pytest.fixture(scope='module') def pincell2(uo2, water): - cyl = openmc.ZCylinder(R=0.4) + cyl = openmc.ZCylinder(r=0.4) fuel = openmc.Cell(fill=uo2, region=-cyl) moderator = openmc.Cell(fill=water, region=+cyl) diff --git a/tests/unit_tests/test_mesh_from_lattice.py b/tests/unit_tests/test_mesh_from_lattice.py index 4d79fc579..feac87326 100644 --- a/tests/unit_tests/test_mesh_from_lattice.py +++ b/tests/unit_tests/test_mesh_from_lattice.py @@ -5,7 +5,7 @@ import pytest @pytest.fixture(scope='module') def pincell1(uo2, water): - cyl = openmc.ZCylinder(R=0.35) + cyl = openmc.ZCylinder(r=0.35) fuel = openmc.Cell(fill=uo2, region=-cyl) moderator = openmc.Cell(fill=water, region=+cyl) @@ -17,7 +17,7 @@ def pincell1(uo2, water): @pytest.fixture(scope='module') def pincell2(uo2, water): - cyl = openmc.ZCylinder(R=0.4) + cyl = openmc.ZCylinder(r=0.4) fuel = openmc.Cell(fill=uo2, region=-cyl) moderator = openmc.Cell(fill=water, region=+cyl) @@ -89,12 +89,12 @@ def rlat3(pincell1, pincell2, uo2, water, zr): def test_mesh2d(rlat2): shape = np.array(rlat2.shape) width = shape*rlat2.pitch - + mesh1 = openmc.Mesh.from_rect_lattice(rlat2) assert np.array_equal(mesh1.dimension, (3, 3)) assert np.array_equal(mesh1.lower_left, rlat2.lower_left) assert np.array_equal(mesh1.upper_right, rlat2.lower_left + width) - + mesh2 = openmc.Mesh.from_rect_lattice(rlat2, division=3) assert np.array_equal(mesh2.dimension, (9, 9)) assert np.array_equal(mesh2.lower_left, rlat2.lower_left) diff --git a/tests/unit_tests/test_model_triso.py b/tests/unit_tests/test_model_triso.py index 1d2e0905c..782373414 100644 --- a/tests/unit_tests/test_model_triso.py +++ b/tests/unit_tests/test_model_triso.py @@ -47,7 +47,7 @@ def centers_rectangular_prism(): @pytest.fixture(scope='module') def centers_x_cylinder(): - cylinder = openmc.XCylinder(R=1, y0=1, z0=2) + cylinder = openmc.XCylinder(r=1, y0=1, z0=2) min_x = openmc.XPlane(x0=0) max_x = openmc.XPlane(x0=1) region = +min_x & -max_x & -cylinder @@ -57,7 +57,7 @@ def centers_x_cylinder(): @pytest.fixture(scope='module') def centers_y_cylinder(): - cylinder = openmc.YCylinder(R=1, x0=1, z0=2) + cylinder = openmc.YCylinder(r=1, x0=1, z0=2) min_y = openmc.YPlane(y0=0) max_y = openmc.YPlane(y0=1) region = +min_y & -max_y & -cylinder @@ -67,7 +67,7 @@ def centers_y_cylinder(): @pytest.fixture(scope='module') def centers_z_cylinder(): - cylinder = openmc.ZCylinder(R=1, x0=1, y0=2) + cylinder = openmc.ZCylinder(r=1, x0=1, y0=2) min_z = openmc.ZPlane(z0=0) max_z = openmc.ZPlane(z0=1) region = +min_z & -max_z & -cylinder @@ -77,7 +77,7 @@ def centers_z_cylinder(): @pytest.fixture(scope='module') def centers_sphere(): - sphere = openmc.Sphere(R=1, x0=1, y0=2, z0=3) + sphere = openmc.Sphere(r=1, x0=1, y0=2, z0=3) region = -sphere return openmc.model.pack_spheres(radius=_RADIUS, region=region, pf=_PACKING_FRACTION, initial_pf=0.2) @@ -85,8 +85,8 @@ def centers_sphere(): @pytest.fixture(scope='module') def centers_spherical_shell(): - sphere = openmc.Sphere(R=1, x0=1, y0=2, z0=3) - inner_sphere = openmc.Sphere(R=0.5, x0=1, y0=2, z0=3) + sphere = openmc.Sphere(r=1, x0=1, y0=2, z0=3) + inner_sphere = openmc.Sphere(r=0.5, x0=1, y0=2, z0=3) region = -sphere & +inner_sphere return openmc.model.pack_spheres(radius=_RADIUS, region=region, pf=_PACKING_FRACTION, initial_pf=0.2) @@ -94,7 +94,7 @@ def centers_spherical_shell(): @pytest.fixture(scope='module') def triso_universe(): - sphere = openmc.Sphere(R=_RADIUS) + sphere = openmc.Sphere(r=_RADIUS) cell = openmc.Cell(region=-sphere) univ = openmc.Universe(cells=[cell]) return univ @@ -179,10 +179,10 @@ def test_packing_fraction(container, centers): def test_num_spheres(): """Check that the function returns the correct number of spheres""" centers = openmc.model.pack_spheres( - radius=_RADIUS, region=-openmc.Sphere(R=1), num_spheres=50 + radius=_RADIUS, region=-openmc.Sphere(r=1), num_spheres=50 ) assert len(centers) == 50 - + def test_triso_lattice(triso_universe, centers_rectangular_prism): trisos = [openmc.model.TRISO(_RADIUS, triso_universe, c) @@ -203,7 +203,7 @@ def test_container_input(triso_universe): # Invalid container shape with pytest.raises(ValueError): centers = openmc.model.pack_spheres( - radius=_RADIUS, region=+openmc.Sphere(R=1), num_spheres=100 + radius=_RADIUS, region=+openmc.Sphere(r=1), num_spheres=100 ) @@ -211,17 +211,17 @@ def test_packing_fraction_input(): # Provide neither packing fraction nor number of spheres with pytest.raises(ValueError): centers = openmc.model.pack_spheres( - radius=_RADIUS, region=-openmc.Sphere(R=1) + radius=_RADIUS, region=-openmc.Sphere(r=1) ) # Specify a packing fraction that is too high for CRP with pytest.raises(ValueError): centers = openmc.model.pack_spheres( - radius=_RADIUS, region=-openmc.Sphere(R=1), pf=1 + radius=_RADIUS, region=-openmc.Sphere(r=1), pf=1 ) # Specify a packing fraction that is too high for RSP with pytest.raises(ValueError): centers = openmc.model.pack_spheres( - radius=_RADIUS, region=-openmc.Sphere(R=1), pf=0.5, initial_pf=0.4 + radius=_RADIUS, region=-openmc.Sphere(r=1), pf=0.5, initial_pf=0.4 ) diff --git a/tests/unit_tests/test_plots.py b/tests/unit_tests/test_plots.py index d48b609c1..840e7e635 100644 --- a/tests/unit_tests/test_plots.py +++ b/tests/unit_tests/test_plots.py @@ -45,7 +45,7 @@ def test_repr(myplot): def test_from_geometry(): width = 25. - s = openmc.Sphere(R=width/2, boundary_type='vacuum') + s = openmc.Sphere(r=width/2, boundary_type='vacuum') c = openmc.Cell(region=-s) univ = openmc.Universe(cells=[c]) geom = openmc.Geometry(univ) diff --git a/tests/unit_tests/test_region.py b/tests/unit_tests/test_region.py index b623cd606..d1074fd7d 100644 --- a/tests/unit_tests/test_region.py +++ b/tests/unit_tests/test_region.py @@ -75,7 +75,7 @@ def test_intersection(reset): def test_complement(reset): - zcyl = openmc.ZCylinder(surface_id=1, R=1.) + zcyl = openmc.ZCylinder(surface_id=1, r=1.) z0 = openmc.ZPlane(surface_id=2, z0=-5.) z1 = openmc.ZPlane(surface_id=3, z0=5.) outside = +zcyl | -z0 | +z1 diff --git a/tests/unit_tests/test_surface.py b/tests/unit_tests/test_surface.py index 45fecb493..6ed657a4c 100644 --- a/tests/unit_tests/test_surface.py +++ b/tests/unit_tests/test_surface.py @@ -13,7 +13,7 @@ def assert_infinite_bb(s): def test_plane(): - s = openmc.Plane(A=1, B=2, C=-1, D=3, name='my plane') + s = openmc.Plane(a=1, b=2, c=-1, d=3, name='my plane') assert s.a == 1 assert s.b == 2 assert s.c == -1 @@ -138,7 +138,7 @@ def test_zplane(): def test_xcylinder(): y, z, r = 3, 5, 2 - s = openmc.XCylinder(y0=y, z0=z, R=r) + s = openmc.XCylinder(y0=y, z0=z, r=r) assert s.y0 == y assert s.z0 == z assert s.r == r @@ -175,7 +175,7 @@ def test_periodic(): def test_ycylinder(): x, z, r = 3, 5, 2 - s = openmc.YCylinder(x0=x, z0=z, R=r) + s = openmc.YCylinder(x0=x, z0=z, r=r) assert s.x0 == x assert s.z0 == z assert s.r == r @@ -200,7 +200,7 @@ def test_ycylinder(): def test_zcylinder(): x, y, r = 3, 5, 2 - s = openmc.ZCylinder(x0=x, y0=y, R=r) + s = openmc.ZCylinder(x0=x, y0=y, r=r) assert s.x0 == x assert s.y0 == y assert s.r == r @@ -228,7 +228,7 @@ def test_zcylinder(): def test_sphere(): x, y, z, r = -3, 5, 6, 2 - s = openmc.Sphere(x0=x, y0=y, z0=z, R=r) + s = openmc.Sphere(x0=x, y0=y, z0=z, r=r) assert s.x0 == x assert s.y0 == y assert s.z0 == z @@ -258,7 +258,7 @@ def test_sphere(): def cone_common(apex, r2, cls): x, y, z = apex - s = cls(x0=x, y0=y, z0=z, R2=r2) + s = cls(x0=x, y0=y, z0=z, r2=r2) assert s.x0 == x assert s.y0 == y assert s.z0 == z diff --git a/tests/unit_tests/test_universe.py b/tests/unit_tests/test_universe.py index 89904524b..674fc5c18 100644 --- a/tests/unit_tests/test_universe.py +++ b/tests/unit_tests/test_universe.py @@ -34,8 +34,8 @@ def test_basic(): def test_bounding_box(): - cyl1 = openmc.ZCylinder(R=1.0) - cyl2 = openmc.ZCylinder(R=2.0) + cyl1 = openmc.ZCylinder(r=1.0) + cyl2 = openmc.ZCylinder(r=2.0) c1 = openmc.Cell(region=-cyl1) c2 = openmc.Cell(region=+cyl1 & -cyl2) From e1aa836ea6e301da54bb68a73382d61845796bf9 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 8 Mar 2019 14:45:33 -0600 Subject: [PATCH 017/165] Adding some point checks for the hex prism test and removing import from surfae.py. --- openmc/surface.py | 1 - tests/unit_tests/test_geometry.py | 25 ++++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/openmc/surface.py b/openmc/surface.py index c861880c5..1776fc10c 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -1,7 +1,6 @@ from abc import ABCMeta from collections import OrderedDict from copy import deepcopy -from functools import partial from numbers import Real, Integral from xml.etree import ElementTree as ET diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index 2c9306cb9..2068c9883 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -206,14 +206,25 @@ def test_get_by_name(): def test_hex_prism(): hex_prism = openmc.model.get_hexagonal_prism(edge_length=5.0, origin=(0.0, 0.0), - boundary_type='reflective', - orientation='y', - corner_radius=0.10) - - hex_prism = openmc.model.get_hexagonal_prism(edge_length=5.0, - origin=(0.0, 0.0), - boundary_type='reflective', orientation='y') + # clear checks + assert (0.0, 0.0, 0.0) in hex_prism + assert (10.0, 10.0, 10.0) not in hex_prism + # edge checks + assert (0.0, 5.01, 0.0) not in hex_prism + assert (0.0, 4.99, 0.0) in hex_prism + + rounded_hex_prism = openmc.model.get_hexagonal_prism(edge_length=5.0, + origin=(0.0, 0.0), + orientation='y', + corner_radius=1.0) + + # clear checks + assert (0.0, 0.0, 0.0) in rounded_hex_prism + assert (10.0, 10.0, 10.0) not in rounded_hex_prism + # edge checks + assert (0.0, 5.01, 0.0) not in rounded_hex_prism + assert (0.0, 4.99, 0.0) not in rounded_hex_prism def test_get_lattice_by_name(cell_with_lattice): From a48d590158ec60f96da773f8d0714f7c08ff1e45 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 7 Mar 2019 09:36:38 -0600 Subject: [PATCH 018/165] Store heating, gas production, and damage energy as redundant reactions --- docs/source/usersguide/tallies.rst | 18 ++++++++++++ include/openmc/constants.h | 7 +++++ openmc/data/neutron.py | 29 ++++++++++++------- openmc/data/njoy.py | 22 +++++++++++--- openmc/data/reaction.py | 8 ++++- src/reaction.cpp | 4 ++- src/tallies/tally.cpp | 14 +++++++++ .../regression_tests/tallies/inputs_true.dat | 3 ++ .../regression_tests/tallies/results_true.dat | 2 +- tests/regression_tests/tallies/test.py | 5 ++++ 10 files changed, 94 insertions(+), 18 deletions(-) diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index 1210bc282..3a8a6d432 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -220,6 +220,16 @@ The following tables show all valid scores: | |multiplicity from (n,2n), (n,3n), and (n,4n) | | |reactions. | +----------------------+---------------------------------------------------+ + |H1-production |Total production of H1. | + +----------------------+---------------------------------------------------+ + |H2-production |Total production of H2 (deuterium). | + +----------------------+---------------------------------------------------+ + |H3-production |Total production of H1 (tritium). | + +----------------------+---------------------------------------------------+ + |He3-production |Total production of He3. | + +----------------------+---------------------------------------------------+ + |He4-production |Total production of He4 (alpha particles). | + +----------------------+---------------------------------------------------+ .. table:: **Miscellaneous scores: units are indicated for each.** @@ -246,6 +256,10 @@ The following tables show all valid scores: |inverse-velocity |The flux-weighted inverse velocity where the | | |velocity is in units of centimeters per second. | +----------------------+---------------------------------------------------+ + |heating |Total neutron heating in units of eV per source | + | |particle. This corresponds to MT=301 produced by | + | |NJOY's HEATR module. | + +----------------------+---------------------------------------------------+ |kappa-fission |The recoverable energy production rate due to | | |fission. The recoverable energy is defined as the | | |fission product kinetic energy, prompt and delayed | @@ -281,3 +295,7 @@ The following tables show all valid scores: |decay-rate |The delayed-nu-fission-weighted decay rate where | | |the decay rate is in units of inverse seconds. | +----------------------+---------------------------------------------------+ + |damage-energy |Damage energy production in units of eV per source | + | |particle. This corresponds to MT=444 produced by | + | |NJOY's HEATR module. | + +----------------------+---------------------------------------------------+ diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 067e6431a..87388c91a 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -225,6 +225,13 @@ constexpr int N_3P {197}; constexpr int N_N3P {198}; constexpr int N_3N2PA {199}; constexpr int N_5N2P {200}; +constexpr int N_XP {203}; +constexpr int N_XD {204}; +constexpr int N_XT {205}; +constexpr int N_X3HE {206}; +constexpr int N_XA {207}; +constexpr int HEATING {301}; +constexpr int DAMAGE_ENERGY {444}; constexpr int COHERENT {502}; constexpr int INCOHERENT {504}; constexpr int PAIR_PROD_ELEC {515}; diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index eec083602..79761b0c9 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -448,11 +448,13 @@ class IncidentNeutron(EqualityMixin): for rx in self.reactions.values(): # Skip writing redundant reaction if it doesn't have photon # production or is a summed transmutation reaction. MT=4 is also - # sometimes needed for probability tables. + # sometimes needed for probability tables. Also write gas + # production, heating, and damage energy production. if rx.redundant: photon_rx = any(p.particle == 'photon' for p in rx.products) - transmutation_rx = (rx.mt in (16, 103, 104, 105, 106, 107)) - if not (photon_rx or transmutation_rx or rx.mt == 4): + keep_mts = (4, 16, 103, 104, 105, 106, 107, + 203, 204, 205, 206, 207, 301, 444) + if not (photon_rx or rx.mt in keep_mts): continue rx_group = rxs_group.create_group('reaction_{:03}'.format(rx.mt)) @@ -615,13 +617,14 @@ class IncidentNeutron(EqualityMixin): # Read energy grid n_energy = ace.nxs[3] - energy = ace.xss[ace.jxs[1]:ace.jxs[1] + n_energy]*EV_PER_MEV + i = ace.jxs[1] + energy = ace.xss[i : i + n_energy]*EV_PER_MEV data.energy[strT] = energy - total_xs = ace.xss[ace.jxs[1] + n_energy:ace.jxs[1] + 2 * n_energy] - absorption_xs = ace.xss[ace.jxs[1] + 2 * n_energy:ace.jxs[1] + - 3 * n_energy] + total_xs = ace.xss[i + n_energy : i + 2*n_energy] + absorption_xs = ace.xss[i + 2*n_energy : i + 3*n_energy] + heating_number = ace.xss[i + 3*n_energy : i + 4*n_energy]*EV_PER_MEV - # Create redundant reactions (total and absorption) + # Create redundant reactions (total, absorption, and heating) total = Reaction(1) total.xs[strT] = Tabulated1D(energy, total_xs) total.redundant = True @@ -633,13 +636,15 @@ class IncidentNeutron(EqualityMixin): absorption.redundant = True data.reactions[101] = absorption + heating = Reaction(301) + heating.xs[strT] = Tabulated1D(energy, heating_number) + heating.redundant = True + data.reactions[301] = heating + # Read each reaction n_reaction = ace.nxs[4] + 1 for i in range(n_reaction): rx = Reaction.from_ace(ace, i) - # Don't include gas production / damage cross sections - if 200 < rx.mt < 219 or rx.mt == 444: - continue data.reactions[rx.mt] = rx # Some photon production reactions may be assigned to MTs that don't @@ -690,6 +695,8 @@ class IncidentNeutron(EqualityMixin): mts = data.get_reaction_components(rx.mt) if mts != [rx.mt]: rx.redundant = True + if rx.mt in (203, 204, 205, 206, 207, 444): + rx.redundant = True # Read unresolved resonance probability tables urr = ProbabilityTables.from_ace(ace) diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index 0c82f32f1..ab6ba54dc 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -72,8 +72,13 @@ broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%% _TEMPLATE_HEATR = """ heatr / %%%%%%%%%%%%%%%%%%%%%%%%% Add heating kerma %%%%%%%%%%%%%%%%%%%%%%%%%%%% {nendf} {nheatr_in} {nheatr} / -{mat} 3 / -302 318 402 / +{mat} 4 / +302 318 402 444 / +""" + +_TEMPLATE_GASPR = """ +gaspr / %%%%%%%%%%%%%%%%%%%%%%%%% Add gas production %%%%%%%%%%%%%%%%%%%%%%%%%%% +{nendf} {ngaspr_in} {ngaspr} / """ _TEMPLATE_PURR = """ @@ -211,8 +216,8 @@ def make_pendf(filename, pendf='pendf', error=0.001, stdout=False): def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, - error=0.001, broadr=True, heatr=True, purr=True, acer=True, - **kwargs): + error=0.001, broadr=True, heatr=True, gaspr=True, purr=True, + acer=True, **kwargs): """Generate incident neutron ACE file from an ENDF file Parameters @@ -234,6 +239,8 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, Indicating whether to Doppler broaden XS when running NJOY heatr : bool, optional Indicating whether to add heating kerma when running NJOY + gaspr : bool, optional + Indicating whether to add gas production data when running NJOY purr : bool, optional Indicating whether to add probability table when running NJOY acer : bool, optional @@ -285,6 +292,13 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, commands += _TEMPLATE_HEATR nlast = nheatr + # gaspr + if gaspr: + ngaspr_in = nlast + ngaspr = ngaspr_in + 1 + commands += _TEMPLATE_GASPR + nlast = ngaspr + # purr if purr: npurr_in = nlast diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index 11807cadc..a988f2d6d 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -51,7 +51,9 @@ REACTION_NAME = {1: '(n,total)', 2: '(n,elastic)', 4: '(n,level)', 189: '(n,nta)', 190: '(n,2n2p)', 191: '(n,p3He)', 192: '(n,d3He)', 193: '(n,3Hea)', 194: '(n,4n2p)', 195: '(n,4n2a)', 196: '(n,4npa)', 197: '(n,3p)', - 198: '(n,n3p)', 199: '(n,3n2pa)', 200: '(n,5n2p)', 444: '(n,damage)', + 198: '(n,n3p)', 199: '(n,3n2pa)', 200: '(n,5n2p)', 203: '(n,Xp)', + 204: '(n,Xd)', 205: '(n,Xt)', 206: '(n,X3He)', 207: '(n,Xa)', + 301: 'heating', 444: 'damage-energy', 649: '(n,pc)', 699: '(n,dc)', 749: '(n,tc)', 799: '(n,3Hec)', 849: '(n,ac)', 891: '(n,2nc)'} REACTION_NAME.update({i: '(n,n{})'.format(i - 50) for i in range(50, 91)}) @@ -988,6 +990,10 @@ class Reaction(EqualityMixin): # Read reaction cross section xs = ace.xss[ace.jxs[7] + loc + 1:ace.jxs[7] + loc + 1 + n_energy] + # For damage energy production, convert to eV + if mt == 444: + xs *= EV_PER_MEV + # Fix negatives -- known issue for Y89 in JEFF 3.2 if np.any(xs < 0.0): warn("Negative cross sections found for MT={} in {}. Setting " diff --git a/src/reaction.cpp b/src/reaction.cpp index 1f997f078..d2405d899 100644 --- a/src/reaction.cpp +++ b/src/reaction.cpp @@ -229,8 +229,10 @@ std::string reaction_name(int mt) return "(n,X3He)"; } else if (mt == 207) { return "(n,Xa)"; + } else if (mt == 301) { + return "heating"; } else if (mt == 444) { - return "(damage)"; + return "damage-energy"; } else if (mt == COHERENT) { return "coherent scatter"; } else if (mt == INCOHERENT) { diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 5bae26b75..682db3540 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -197,6 +197,20 @@ score_str_to_int(std::string score_str) return N_PT; if (score_str == "(n,da)") return N_DA; + if (score_str == "(n,Xp)" || score_str == "H1-production") + return N_XP; + if (score_str == "(n,Xd)" || score_str == "H2-production") + return N_XD; + if (score_str == "(n,Xt)" || score_str == "H3-production") + return N_XT; + if (score_str == "(n,X3He)" || score_str == "He3-production") + return N_X3HE; + if (score_str == "(n,Xa)" || score_str == "He4-production") + return N_XA; + if (score_str == "heating") + return HEATING; + if (score_str == "damage-energy") + return DAMAGE_ENERGY; // So far we have not identified this score string. Check to see if it is a // deprecated score. diff --git a/tests/regression_tests/tallies/inputs_true.dat b/tests/regression_tests/tallies/inputs_true.dat index 80f55b034..3ec8d8d4c 100644 --- a/tests/regression_tests/tallies/inputs_true.dat +++ b/tests/regression_tests/tallies/inputs_true.dat @@ -511,4 +511,7 @@ total tracklength + + H1-production H2-production H3-production He3-production He4-production heating damage-energy + diff --git a/tests/regression_tests/tallies/results_true.dat b/tests/regression_tests/tallies/results_true.dat index 08a3ba110..9830ff872 100644 --- a/tests/regression_tests/tallies/results_true.dat +++ b/tests/regression_tests/tallies/results_true.dat @@ -1 +1 @@ -b5edf87cb58db29aa1c38203141df2f055b88aca675aee9673879b579391412abd232cb3d404f60840ac86b936384050576cccb1e3a1fc5c8290b6e890dda74c \ No newline at end of file +de773a799f84348241ebd65bf7beae8114861d8674b652bfd443d578c146a7d37ca38f2efc5d05124fdbb1cf12829907768351e6b2d6b5f4bd2c121417757507 \ No newline at end of file diff --git a/tests/regression_tests/tallies/test.py b/tests/regression_tests/tallies/test.py index eeb74636f..543d0acd2 100644 --- a/tests/regression_tests/tallies/test.py +++ b/tests/regression_tests/tallies/test.py @@ -165,6 +165,10 @@ def test_tallies(): all_nuclide_tallies[3].filters = [mesh_filter] all_nuclide_tallies[3].nuclides = ['U235'] + fusion_tally = Tally() + fusion_tally.scores = ['H1-production', 'H2-production', 'H3-production', + 'He3-production', 'He4-production', 'heating', 'damage-energy'] + model.tallies += [ azimuthal_tally1, azimuthal_tally2, azimuthal_tally3, cellborn_tally, dg_tally, energy_tally, energyout_tally, @@ -174,5 +178,6 @@ def test_tallies(): model.tallies += score_tallies model.tallies += flux_tallies model.tallies += all_nuclide_tallies + model.tallies.append(fusion_tally) harness.main() From 48413455700e184fa69e0481dd3e6c8d10aada65 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 10 Mar 2019 14:51:03 -0500 Subject: [PATCH 019/165] Update nndc test data --- tools/ci/download-xs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/download-xs.sh b/tools/ci/download-xs.sh index b2068ceca..ce4d12c1b 100755 --- a/tools/ci/download-xs.sh +++ b/tools/ci/download-xs.sh @@ -3,7 +3,7 @@ set -ex # Download HDF5 data if [[ ! -e $HOME/nndc_hdf5/cross_sections.xml ]]; then - wget -q -O - https://anl.box.com/shared/static/9jmb8v2cx6kx03s6mbr2ai0mnvx5j79p.xz | tar -C $HOME -xJ + wget -q -O - https://anl.box.com/shared/static/pzutl4i2717yypv12l78l7fn5nmg6grs.xz | tar -C $HOME -xJ fi # Download ENDF/B-VII.1 distribution From d1afac36052871328d07be46fa8a749fca80faf4 Mon Sep 17 00:00:00 2001 From: amandalund Date: Mon, 11 Mar 2019 11:33:38 -0500 Subject: [PATCH 020/165] Read in bremsstrahlung data in IncidentPhoton.from_ace --- openmc/data/photon.py | 126 +++++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 58 deletions(-) diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 01184a744..47bdbf1d9 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -513,6 +513,9 @@ class IncidentPhoton(EqualityMixin): e = data.atomic_relaxation.binding_energy[shell] rx.subshell_binding_energy = e + # Add bremsstrahlung DCS data + data._add_bremsstrahlung() + return data @classmethod @@ -572,65 +575,8 @@ class IncidentPhoton(EqualityMixin): data.compton_profiles['binding_energy'] = profile['binding_energy'] data.compton_profiles['J'] = [Tabulated1D(pz, J_k) for J_k in profile['J']] - # Load bremsstrahlung data if it has not yet been loaded - if not _BREMSSTRAHLUNG: - # Add data used for density effect correction - filename = os.path.join(os.path.dirname(__file__), 'density_effect.h5') - with h5py.File(filename, 'r') as f: - for i in range(1, 101): - group = f['{:03}'.format(i)] - _BREMSSTRAHLUNG[i] = { - 'I': group.attrs['I'], - 'num_electrons': group['num_electrons'].value, - 'ionization_energy': group['ionization_energy'].value - } - - filename = os.path.join(os.path.dirname(__file__), 'BREMX.DAT') - brem = open(filename, 'r').read().split() - - # Incident electron kinetic energy grid in eV - _BREMSSTRAHLUNG['electron_energy'] = np.logspace(3, 9, 200) - log_energy = np.log(_BREMSSTRAHLUNG['electron_energy']) - - # Get number of tabulated electron and photon energy values - n = int(brem[37]) - k = int(brem[38]) - - # Index in data - p = 39 - - # Get log of incident electron kinetic energy values, used for - # cubic spline interpolation in log energy. Units are in MeV, so - # convert to eV. - logx = np.log(np.fromiter(brem[p:p+n], float, n)*EV_PER_MEV) - p += n - - # Get reduced photon energy values - _BREMSSTRAHLUNG['photon_energy'] = np.fromiter(brem[p:p+k], float, k) - p += k - - for i in range(1, 101): - dcs = np.empty([len(log_energy), k]) - - # Get the scaled cross section values for each electron energy - # and reduced photon energy for this Z. Units are in mb, so - # convert to b. - y = np.reshape(np.fromiter(brem[p:p+n*k], float, n*k), (n, k))*1.0e-3 - p += k*n - - for j in range(k): - # Cubic spline interpolation in log energy and linear DCS - cs = CubicSpline(logx, y[:,j]) - - # Get scaled DCS values (millibarns) on new energy grid - dcs[:,j] = cs(log_energy) - - _BREMSSTRAHLUNG[i]['dcs'] = dcs - # Add bremsstrahlung DCS data - data.bremsstrahlung['electron_energy'] = _BREMSSTRAHLUNG['electron_energy'] - data.bremsstrahlung['photon_energy'] = _BREMSSTRAHLUNG['photon_energy'] - data.bremsstrahlung.update(_BREMSSTRAHLUNG[Z]) + data._add_bremsstrahlung() return data @@ -761,6 +707,70 @@ class IncidentPhoton(EqualityMixin): else: brem_group.create_dataset(key, data=value) + def _add_bremsstrahlung(self): + """Add the data used in the thick-target bremsstrahlung approximation + + """ + # Load bremsstrahlung data if it has not yet been loaded + if not _BREMSSTRAHLUNG: + # Add data used for density effect correction + filename = os.path.join(os.path.dirname(__file__), 'density_effect.h5') + with h5py.File(filename, 'r') as f: + for i in range(1, 101): + group = f['{:03}'.format(i)] + _BREMSSTRAHLUNG[i] = { + 'I': group.attrs['I'], + 'num_electrons': group['num_electrons'].value, + 'ionization_energy': group['ionization_energy'].value + } + + filename = os.path.join(os.path.dirname(__file__), 'BREMX.DAT') + brem = open(filename, 'r').read().split() + + # Incident electron kinetic energy grid in eV + _BREMSSTRAHLUNG['electron_energy'] = np.logspace(3, 9, 200) + log_energy = np.log(_BREMSSTRAHLUNG['electron_energy']) + + # Get number of tabulated electron and photon energy values + n = int(brem[37]) + k = int(brem[38]) + + # Index in data + p = 39 + + # Get log of incident electron kinetic energy values, used for + # cubic spline interpolation in log energy. Units are in MeV, so + # convert to eV. + logx = np.log(np.fromiter(brem[p:p+n], float, n)*EV_PER_MEV) + p += n + + # Get reduced photon energy values + _BREMSSTRAHLUNG['photon_energy'] = np.fromiter(brem[p:p+k], float, k) + p += k + + for i in range(1, 101): + dcs = np.empty([len(log_energy), k]) + + # Get the scaled cross section values for each electron energy + # and reduced photon energy for this Z. Units are in mb, so + # convert to b. + y = np.reshape(np.fromiter(brem[p:p+n*k], float, n*k), (n, k))*1.0e-3 + p += k*n + + for j in range(k): + # Cubic spline interpolation in log energy and linear DCS + cs = CubicSpline(logx, y[:,j]) + + # Get scaled DCS values (millibarns) on new energy grid + dcs[:,j] = cs(log_energy) + + _BREMSSTRAHLUNG[i]['dcs'] = dcs + + # Add bremsstrahlung DCS data + self.bremsstrahlung['electron_energy'] = _BREMSSTRAHLUNG['electron_energy'] + self.bremsstrahlung['photon_energy'] = _BREMSSTRAHLUNG['photon_energy'] + self.bremsstrahlung.update(_BREMSSTRAHLUNG[self.atomic_number]) + class PhotonReaction(EqualityMixin): """Photon-induced reaction From 08fd6b9cb12d7368eaa7db7f215de8c439a9c6c3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 11 Mar 2019 08:12:52 -0500 Subject: [PATCH 021/165] Enable from_njoy methods to use evaluation from ENDF tape containing multiple materials --- openmc/data/neutron.py | 10 +++++++--- openmc/data/njoy.py | 21 ++++++++++++++++----- openmc/data/thermal.py | 12 +++++++++++- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 79761b0c9..670144ec1 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -791,16 +791,19 @@ class IncidentNeutron(EqualityMixin): return data @classmethod - def from_njoy(cls, filename, temperatures=None, **kwargs): + def from_njoy(cls, filename, temperatures=None, evaluation=None, **kwargs): """Generate incident neutron data by running NJOY. Parameters ---------- filename : str - Path to ENDF evaluation + Path to ENDF file temperatures : iterable of float Temperatures in Kelvin to produce data at. If omitted, data is produced at room temperature (293.6 K) + evaluation : openmc.data.endf.Evaluation, optional + If the ENDF file contains multiple material evaluations, this + argument indicates which evaluation to use. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.make_ace` @@ -815,6 +818,7 @@ class IncidentNeutron(EqualityMixin): ace_file = os.path.join(tmpdir, 'ace') xsdir_file = os.path.join(tmpdir, 'xsdir') pendf_file = os.path.join(tmpdir, 'pendf') + kwargs['evaluation'] = evaluation make_ace(filename, temperatures, ace_file, xsdir_file, pendf_file, **kwargs) @@ -825,7 +829,7 @@ class IncidentNeutron(EqualityMixin): data.add_temperature_from_ace(table) # Add fission energy release data - ev = Evaluation(filename) + ev = evaluation if evaluation is not None else Evaluation(filename) if (1, 458) in ev.section: data.fission_energy = FissionEnergyRelease.from_endf(ev, data) diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index ab6ba54dc..ece20a878 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -217,7 +217,7 @@ def make_pendf(filename, pendf='pendf', error=0.001, stdout=False): def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, error=0.001, broadr=True, heatr=True, gaspr=True, purr=True, - acer=True, **kwargs): + acer=True, evaluation=None, **kwargs): """Generate incident neutron ACE file from an ENDF file Parameters @@ -245,6 +245,9 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, Indicating whether to add probability table when running NJOY acer : bool, optional Indicating whether to generate ACE file when running NJOY + evaluation : str, optional + If the ENDF file contains multiple material evaluations, this argument + indicates which evaluation should be used. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -254,7 +257,7 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, If the NJOY process returns with a non-zero status """ - ev = endf.Evaluation(filename) + ev = evaluation if evaluation is not None else endf.Evaluation(filename) mat = ev.material zsymam = ev.target['zsymam'] @@ -352,7 +355,8 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, def make_ace_thermal(filename, filename_thermal, temperatures=None, - ace='ace', xsdir='xsdir', error=0.001, **kwargs): + ace='ace', xsdir='xsdir', error=0.001, evaluation=None, + evaluation_thermal=None, **kwargs): """Generate thermal scattering ACE file from ENDF files Parameters @@ -370,6 +374,12 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, Path of xsdir file to write error : float, optional Fractional error tolerance for NJOY processing + evaluation : openmc.data.endf.Evaluation, optional + If the ENDF neutron sublibrary file contains multiple material + evaluations, this argument indicates which evaluation to use. + evaluation_thermal : openmc.data.endf.Evaluation, optional + If the ENDF thermal scattering sublibrary file contains multiple + material evaluations, this argument indicates which evaluation to use. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -379,11 +389,12 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, If the NJOY process returns with a non-zero status """ - ev = endf.Evaluation(filename) + ev = evaluation if evaluation is not None else endf.Evaluation(filename) mat = ev.material zsymam = ev.target['zsymam'] - ev_thermal = endf.Evaluation(filename_thermal) + ev_thermal = (evaluation_thermal if evaluation_thermal is not None + else endf.Evaluation(filename_thermal)) mat_thermal = ev_thermal.material zsymam_thermal = ev_thermal.target['zsymam'] diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index f6ce6326b..b10cdeba4 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -610,7 +610,8 @@ class ThermalScattering(EqualityMixin): return table @classmethod - def from_njoy(cls, filename, filename_thermal, temperatures=None, **kwargs): + def from_njoy(cls, filename, filename_thermal, temperatures=None, + evaluation=None, evaluation_thermal=None, **kwargs): """Generate incident neutron data by running NJOY. Parameters @@ -623,6 +624,13 @@ class ThermalScattering(EqualityMixin): Temperatures in Kelvin to produce data at. If omitted, data is produced at all temperatures in the ENDF thermal scattering sublibrary. + evaluation : openmc.data.endf.Evaluation, optional + If the ENDF neutron sublibrary file contains multiple material + evaluations, this argument indicates which evaluation to use. + evaluation_thermal : openmc.data.endf.Evaluation, optional + If the ENDF thermal scattering sublibrary file contains multiple + material evaluations, this argument indicates which evaluation to + use. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.make_ace_thermal` @@ -636,6 +644,8 @@ class ThermalScattering(EqualityMixin): # Run NJOY to create an ACE library ace_file = os.path.join(tmpdir, 'ace') xsdir_file = os.path.join(tmpdir, 'xsdir') + kwargs['evaluation'] = evaluation + kwargs['evaluation_thermal'] = evaluation_thermal make_ace_thermal(filename, filename_thermal, temperatures, ace_file, xsdir_file, **kwargs) From 711d85a4e44706321e6e5b09036bd53bc0d932dd Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 11 Mar 2019 08:13:46 -0500 Subject: [PATCH 022/165] Add DOI to one publication --- docs/source/publications.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/source/publications.rst b/docs/source/publications.rst index 990a8fc21..da7131649 100644 --- a/docs/source/publications.rst +++ b/docs/source/publications.rst @@ -200,6 +200,11 @@ Miscellaneous Multigroup Cross Section Generation ----------------------------------- +- William Boyd, Adam Nelson, Paul K. Romano, Samuel Shaner, Benoit Forget, and + Kord Smith, "`Multigroup Cross-Section Generation with the OpenMC Monte Carlo + Particle Transport Code `_," + *Nucl. Technol.* (2019). + - William Boyd, Benoit Forget, and Kord Smith, "`A single-step framework to generate spatially self-shielded multi-group cross sections from Monte Carlo transport simulations `_," From 285532c840aa4fe339c8c97ecf9dae224341878e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 11 Mar 2019 08:32:59 -0500 Subject: [PATCH 023/165] Improve int_endf and float_endf, and use int_endf consistently. Closes #1027 --- openmc/data/endf.py | 81 ++++++++++++++++------------------- tests/unit_tests/test_endf.py | 16 +++++++ 2 files changed, 53 insertions(+), 44 deletions(-) create mode 100644 tests/unit_tests/test_endf.py diff --git a/openmc/data/endf.py b/openmc/data/endf.py index 8e5fcf1a3..6131f3c6b 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -66,7 +66,7 @@ SUM_RULES = {1: [2, 3], 106: list(range(750, 800)), 107: list(range(800, 850))} -ENDF_FLOAT_RE = re.compile(r'([\s\-\+]?\d*\.\d+)([\+\-]\d+)') +ENDF_FLOAT_RE = re.compile(r'([\s\-\+]?\d*\.\d+)([\+\-]) ?(\d+)') def float_endf(s): @@ -89,12 +89,15 @@ def float_endf(s): The number """ - return float(ENDF_FLOAT_RE.sub(r'\1e\2', s)) + return float(ENDF_FLOAT_RE.sub(r'\1e\2\3', s)) -def _int_endf(s): - """Convert string to int. Used for INTG records where blank entries - indicate a 0. +def int_endf(s): + """Convert string of integer number in ENDF to int. + + The ENDF-6 format technically allows integers to be represented by a field + of all blanks. This function acts like int(s) except when s is a string of + all whitespace, in which case zero is returned. Parameters ---------- @@ -106,8 +109,7 @@ def _int_endf(s): integer The number or 0 """ - s = s.strip() - return int(s) if s else 0 + return 0 if s.isspace() else int(s) def get_text_record(file_obj): @@ -127,35 +129,35 @@ def get_text_record(file_obj): return file_obj.readline()[:66] -def get_cont_record(file_obj, skipC=False): +def get_cont_record(file_obj, skip_c=False): """Return data from a CONT record in an ENDF-6 file. Parameters ---------- file_obj : file-like object ENDF-6 file to read from - skipC : bool + skip_c : bool Determine whether to skip the first two quantities (C1, C2) of the CONT record. Returns ------- - list + tuple The six items within the CONT record """ line = file_obj.readline() - if skipC: + if skip_c: C1 = None C2 = None else: C1 = float_endf(line[:11]) C2 = float_endf(line[11:22]) - L1 = int(line[22:33]) - L2 = int(line[33:44]) - N1 = int(line[44:55]) - N2 = int(line[55:66]) - return [C1, C2, L1, L2, N1, N2] + L1 = int_endf(line[22:33]) + L2 = int_endf(line[33:44]) + N1 = int_endf(line[44:55]) + N2 = int_endf(line[55:66]) + return (C1, C2, L1, L2, N1, N2) def get_head_record(file_obj): @@ -168,18 +170,18 @@ def get_head_record(file_obj): Returns ------- - list + tuple The six items within the HEAD record """ line = file_obj.readline() ZA = int(float_endf(line[:11])) AWR = float_endf(line[11:22]) - L1 = int(line[22:33]) - L2 = int(line[33:44]) - N1 = int(line[44:55]) - N2 = int(line[55:66]) - return [ZA, AWR, L1, L2, N1, N2] + L1 = int_endf(line[22:33]) + L2 = int_endf(line[33:44]) + N1 = int_endf(line[44:55]) + N2 = int_endf(line[55:66]) + return (ZA, AWR, L1, L2, N1, N2) def get_list_record(file_obj): @@ -233,10 +235,10 @@ def get_tab1_record(file_obj): line = file_obj.readline() C1 = float_endf(line[:11]) C2 = float_endf(line[11:22]) - L1 = int(line[22:33]) - L2 = int(line[33:44]) - n_regions = int(line[44:55]) - n_pairs = int(line[55:66]) + L1 = int_endf(line[22:33]) + L2 = int_endf(line[33:44]) + n_regions = int_endf(line[44:55]) + n_pairs = int_endf(line[55:66]) params = [C1, C2, L1, L2] # Read the interpolation region data, namely NBT and INT @@ -247,8 +249,8 @@ def get_tab1_record(file_obj): line = file_obj.readline() to_read = min(3, n_regions - m) for j in range(to_read): - breakpoints[m] = int(line[0:11]) - interpolation[m] = int(line[11:22]) + breakpoints[m] = int_endf(line[0:11]) + interpolation[m] = int_endf(line[11:22]) line = line[22:] m += 1 @@ -306,9 +308,9 @@ def get_intg_record(file_obj): """ # determine how many items are in list and NDIGIT items = get_cont_record(file_obj) - ndigit = int(items[2]) - npar = int(items[3]) # Number of parameters - nlines = int(items[4]) # Lines to read + ndigit = items[2] + npar = items[3] # Number of parameters + nlines = items[4] # Lines to read NROW_RULES = {2: 18, 3: 12, 4: 11, 5: 9, 6: 8} nrow = NROW_RULES[ndigit] @@ -316,13 +318,13 @@ def get_intg_record(file_obj): corr = np.identity(npar) for i in range(nlines): line = file_obj.readline() - ii = _int_endf(line[:5]) - 1 # -1 to account for 0 indexing - jj = _int_endf(line[5:10]) - 1 + ii = int_endf(line[:5]) - 1 # -1 to account for 0 indexing + jj = int_endf(line[5:10]) - 1 factor = 10**ndigit for j in range(nrow): if jj+j >= ii: break - element = _int_endf(line[11+(ndigit+1)*j:11+(ndigit+1)*(j+1)]) + element = int_endf(line[11+(ndigit+1)*j:11+(ndigit+1)*(j+1)]) if element > 0: corr[ii, jj] = (element+0.5)/factor elif element < 0: @@ -507,16 +509,7 @@ class Evaluation(object): # File numbers, reaction designations, and number of records for i in range(NXC): - line = file_obj.readline() - mf = int(line[22:33]) - mt = int(line[33:44]) - nc = int(line[44:55]) - try: - mod = int(line[55:66]) - except ValueError: - # In JEFF 3.2, a few isotopes of U have MOD values that are - # missing. This prevents failure on these isotopes. - mod = 0 + _, _, mf, mt, nc, mod = get_cont_record(file_obj, skip_c=True) self.reaction_list.append((mf, mt, nc, mod)) @property diff --git a/tests/unit_tests/test_endf.py b/tests/unit_tests/test_endf.py new file mode 100644 index 000000000..147e2db87 --- /dev/null +++ b/tests/unit_tests/test_endf.py @@ -0,0 +1,16 @@ +from openmc.data import endf +from pytest import approx + + +def test_float_endf(): + assert endf.float_endf('+3.2146') == approx(3.2146) + assert endf.float_endf('.12345') == approx(0.12345) + assert endf.float_endf('6.022+23') == approx(6.022e23) + assert endf.float_endf('6.022-23') == approx(6.022e-23) + assert endf.float_endf(' +1.01+ 2') == approx(101.0) + assert endf.float_endf(' -1.01- 2') == approx(-0.0101) + + +def test_int_endf(): + assert endf.int_endf(' ') == 0 + assert endf.int_endf('+4032') == 4032 From 97f487da5b36745a49256bc95a9198f2b3fae1c4 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 11 Mar 2019 13:06:23 -0500 Subject: [PATCH 024/165] Fix typo in tallies user documentation --- docs/source/usersguide/tallies.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index 3a8a6d432..2ced8acf0 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -224,7 +224,7 @@ The following tables show all valid scores: +----------------------+---------------------------------------------------+ |H2-production |Total production of H2 (deuterium). | +----------------------+---------------------------------------------------+ - |H3-production |Total production of H1 (tritium). | + |H3-production |Total production of H3 (tritium). | +----------------------+---------------------------------------------------+ |He3-production |Total production of He3. | +----------------------+---------------------------------------------------+ From 30483039c9b980b1ff44e8543428392fc3fc4f8a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 12 Mar 2019 06:50:49 -0500 Subject: [PATCH 025/165] Fix docstring of make_ace as suggested by @liangjg --- openmc/data/njoy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index ece20a878..ddc1efb1c 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -191,7 +191,7 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False, def make_pendf(filename, pendf='pendf', error=0.001, stdout=False): - """Generate ACE file from an ENDF file + """Generate pointwise ENDF file from an ENDF file Parameters ---------- @@ -245,7 +245,7 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, Indicating whether to add probability table when running NJOY acer : bool, optional Indicating whether to generate ACE file when running NJOY - evaluation : str, optional + evaluation : openmc.data.endf.Evaluation, optional If the ENDF file contains multiple material evaluations, this argument indicates which evaluation should be used. **kwargs From 17d778e57f1c84bbec6f18c4d922259fc7eb46de Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 12 Mar 2019 09:58:35 -0500 Subject: [PATCH 026/165] Allow export_to_xml methods to take a directory --- openmc/geometry.py | 7 ++++++- openmc/material.py | 8 +++++++- openmc/model/model.py | 29 +++++++++++++++++++++-------- openmc/plots.py | 10 ++++++++-- openmc/settings.py | 8 +++++++- openmc/tallies.py | 9 +++++++-- 6 files changed, 56 insertions(+), 15 deletions(-) diff --git a/openmc/geometry.py b/openmc/geometry.py index e939ecbe3..260bb9e83 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -97,9 +97,14 @@ class Geometry(object): # Clean the indentation in the file to be user-readable xml.clean_indentation(root_element) + # Check if path is a directory + p = Path(path) + if p.is_dir(): + p /= 'geometry.xml' + # Write the XML Tree to the geometry.xml file tree = ET.ElementTree(root_element) - tree.write(path, xml_declaration=True, encoding='utf-8') + tree.write(str(p), xml_declaration=True, encoding='utf-8') @classmethod def from_xml(cls, path='geometry.xml', materials=None): diff --git a/openmc/material.py b/openmc/material.py index f8f122308..42c56aced 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1,6 +1,7 @@ from collections import OrderedDict from copy import deepcopy from numbers import Real, Integral +from pathlib import Path import warnings from xml.etree import ElementTree as ET @@ -1065,9 +1066,14 @@ class Materials(cv.CheckedList): # Clean the indentation in the file to be user-readable clean_indentation(root_element) + # Check if path is a directory + p = Path(path) + if p.is_dir(): + p /= 'materials.xml' + # Write the XML Tree to the materials.xml file tree = ET.ElementTree(root_element) - tree.write(path, xml_declaration=True, encoding='utf-8') + tree.write(str(p), xml_declaration=True, encoding='utf-8') @classmethod def from_xml(cls, path='materials.xml'): diff --git a/openmc/model/model.py b/openmc/model/model.py index b6a89792d..cf6603638 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -1,4 +1,5 @@ from collections.abc import Iterable +from pathlib import Path import openmc from openmc.checkvalue import check_type, check_value @@ -154,27 +155,39 @@ class Model(object): 'si_celi', 'si_leqi', 'celi', 'leqi')) getattr(dep.integrator, method)(op, timesteps, **kwargs) - def export_to_xml(self): - """Export model to XML files.""" + def export_to_xml(self, directory='.'): + """Export model to XML files. - self.settings.export_to_xml() + Parameters + ---------- + directory : str + Directory to write XML files to. If it doesn't exist already, it + will be created. + + """ + # Create directory if + d = Path(directory) + if not d.is_dir(): + d.mkdir(parents=True) + + self.settings.export_to_xml(d) if not self.settings.dagmc: - self.geometry.export_to_xml() + self.geometry.export_to_xml(d) # If a materials collection was specified, export it. Otherwise, look # for all materials in the geometry and use that to automatically build # a collection. if self.materials: - self.materials.export_to_xml() + self.materials.export_to_xml(d) else: materials = openmc.Materials(self.geometry.get_all_materials() .values()) - materials.export_to_xml() + materials.export_to_xml(d) if self.tallies: - self.tallies.export_to_xml() + self.tallies.export_to_xml(d) if self.plots: - self.plots.export_to_xml() + self.plots.export_to_xml(d) def run(self, **kwargs): """Creates the XML files, runs OpenMC, and returns k-effective diff --git a/openmc/plots.py b/openmc/plots.py index f99392def..eb582502e 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -1,9 +1,10 @@ from collections.abc import Iterable, Mapping from numbers import Real, Integral -from xml.etree import ElementTree as ET +from pathlib import Path import subprocess import sys import warnings +from xml.etree import ElementTree as ET import numpy as np @@ -818,6 +819,11 @@ class Plots(cv.CheckedList): # Clean the indentation in the file to be user-readable clean_indentation(self._plots_file) + # Check if path is a directory + p = Path(path) + if p.is_dir(): + p /= 'plots.xml' + # Write the XML Tree to the plots.xml file tree = ET.ElementTree(self._plots_file) - tree.write(path, xml_declaration=True, encoding='utf-8', method="xml") + tree.write(str(p), xml_declaration=True, encoding='utf-8') diff --git a/openmc/settings.py b/openmc/settings.py index 23450d98d..4be2eaaa3 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -1,4 +1,5 @@ from collections.abc import Iterable, MutableSequence, Mapping +from pathlib import Path from numbers import Real, Integral import warnings from xml.etree import ElementTree as ET @@ -995,6 +996,11 @@ class Settings(object): # Clean the indentation in the file to be user-readable clean_indentation(root_element) + # Check if path is a directory + p = Path(path) + if p.is_dir(): + p /= 'settings.xml' + # Write the XML Tree to the settings.xml file tree = ET.ElementTree(root_element) - tree.write(path, xml_declaration=True, encoding='utf-8', method="xml") + tree.write(str(p), xml_declaration=True, encoding='utf-8') diff --git a/openmc/tallies.py b/openmc/tallies.py index 5bc6494bb..291090b19 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -5,6 +5,7 @@ from functools import partial, reduce from itertools import product from numbers import Integral, Real import operator +from pathlib import Path import warnings from xml.etree import ElementTree as ET @@ -3189,7 +3190,11 @@ class Tallies(cv.CheckedList): # Clean the indentation in the file to be user-readable clean_indentation(root_element) + # Check if path is a directory + p = Path(path) + if p.is_dir(): + p /= 'tallies.xml' + # Write the XML Tree to the tallies.xml file tree = ET.ElementTree(root_element) - tree.write(path, xml_declaration=True, - encoding='utf-8', method="xml") + tree.write(str(p), xml_declaration=True, encoding='utf-8') From dd9d8f412b893c1b68397d9119ec2ade4b28b31a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 12 Mar 2019 11:17:48 -0500 Subject: [PATCH 027/165] Add one publication to list --- docs/source/publications.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/source/publications.rst b/docs/source/publications.rst index da7131649..762f9329e 100644 --- a/docs/source/publications.rst +++ b/docs/source/publications.rst @@ -210,6 +210,11 @@ Multigroup Cross Section Generation transport simulations `_," *Ann. Nucl. Energy*, **125**, 261-271 (2019). +- Kun Zhuang, Xiaobin Tang, and Liangzhi Cao, "`Development and verification of + a model for generation of MSFR few-group homogenized cross-sections based on a + Monte Carlo code OpenMC `_," + *Ann. Nucl. Energy*, **124**, 187-197 (2019). + - Changho Lee and Yeon Sang Jung, "Verification of the Cross Section Library Generated Using OpenMC and MC\ :sup:`2`-3 for PROTEUS," *Proc. PHYSOR*, Cancun, Mexico, Apr. 22-26 (2018). From c6a8c8bf13ec1222d232a73676717ab366e28462 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 9 Jan 2019 11:50:35 -0600 Subject: [PATCH 028/165] Adding function for writing plot ids to a binary file. --- src/plot.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/plot.cpp b/src/plot.cpp index ae2f00023..f44687a4b 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -88,6 +88,19 @@ void read_plots_xml() } } +void write_ids(xt::xtensor ids) { + + // create a binary file with ID information + std::string fname = "plot_ids.binary"; + std::ofstream of; + + of.open(fname); + + for (auto id : ids) { of << id; } + + of.close(); +} + //============================================================================== // CREATE_PPM creates an image based on user input from a plots.xml // specification in the portable pixmap format (PPM) @@ -104,6 +117,8 @@ void create_ppm(Plot pl) ImageData data; data.resize({width, height}); + xt::xtensor ids; + ids.resize({width, height}); int in_i, out_i; Position r; @@ -150,6 +165,7 @@ void create_ppm(Plot pl) p.r()[in_i] = r[in_i] + in_pixel * x; position_rgb(p, pl, rgb, id); data(x,y) = rgb; + ids(x,y) = id; } } } @@ -158,6 +174,9 @@ void create_ppm(Plot pl) // write ppm data to file output_ppm(pl, data); + + // write ids to binary file + write_ids(ids); } void From 7c810d6847135f27de4e76012e4c00dfffd6bab4 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 9 Jan 2019 16:04:43 -0600 Subject: [PATCH 029/165] Correcting binary write. --- src/plot.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index f44687a4b..5ad1deca1 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -88,15 +88,23 @@ void read_plots_xml() } } -void write_ids(xt::xtensor ids) { +void +write_ids(const Plot& pl, xt::xtensor ids) { // create a binary file with ID information std::string fname = "plot_ids.binary"; std::ofstream of; - of.open(fname); - - for (auto id : ids) { of << id; } + of.open(fname, std::ios::binary); + of.write((char*) &(pl.pixels_[0]), sizeof(int)); + of.write((char*) &(pl.pixels_[1]), sizeof(int)); + of.write((char*) &(pl.width_[0]), sizeof(double)); + of.write((char*) &(pl.width_[1]), sizeof(double)); + for (int y = 0; y < pl.pixels_[1]; y++) { + for (int x = 0; x < pl.pixels_[0]; x++) { + of.write((char*) &(ids(x,y)), sizeof(int)); + } + } of.close(); } @@ -176,7 +184,7 @@ void create_ppm(Plot pl) output_ppm(pl, data); // write ids to binary file - write_ids(ids); + write_ids(pl, ids); } void From 4df3f507f72107704ffc352ff7f87f38bc9b65d7 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 26 Feb 2019 07:50:03 -0600 Subject: [PATCH 030/165] Adding the start of a plot module for the capi. --- openmc/capi/__init__.py | 5 ++-- openmc/capi/plot.py | 62 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 openmc/capi/plot.py diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 1015df216..e162387ff 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -12,7 +12,8 @@ objects in the :mod:`openmc.capi` subpackage, for example: """ -from ctypes import CDLL, c_bool +from ctypes import CDLL, c_bool, c_int +import numpy as np import os import sys @@ -42,7 +43,6 @@ else: def _dagmc_enabled(): return c_bool.in_dll(_dll, "dagmc_enabled").value - from .error import * from .core import * from .nuclide import * @@ -53,3 +53,4 @@ from .filter import * from .tally import * from .settings import settings from .math import * +from .plot import * diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py new file mode 100644 index 000000000..fea300aed --- /dev/null +++ b/openmc/capi/plot.py @@ -0,0 +1,62 @@ +from ctypes import c_int, c_double, c_ushort, POINTER, Structure + +from . import _dll +from .core import _DLLGlobal + +import numpy as np + +_dll.openmc_get_image_data.argtypes = [c_int, c_int, c_int, c_int, c_int, + POINTER(c_double*3), c_double, + c_double, POINTER(c_double)] +_dll.openmc_get_image_data.restype = c_double + +class _Position(Structure): + pass + +_Position._fields_ = [('x', c_double), + ('y', c_double), + ('z', c_double)] + +class _RGBColor(Structure): + pass + +_RGBColor._fields_ = [('red', c_ushort), + ('green', c_ushort), + ('blue', c_ushort)] + +class _Plot(Structure): + pass + +_Plot._fields_ = [('id_', c_int), + ('type_', c_int), + ('color_by_', c_int), + ('origin_', _Position), + ('width_', _Position), + ('basis_', c_int), + ('pixels_', c_int*3), + ('meshlines_width_', c_int), + ('level_', c_int), + ('index_meshlines_mesh_', c_int), + ('meshlines_color_', _RGBColor), + ('not_found_', _RGBColor), + ('colors_', POINTER(_RGBColor))] + + +_dll.image_for_plot.argtypes= [POINTER(_Plot),] +_dll.image_for_plot.restype = c_int + +def get_image_data(): + origin = np.array([0.0, 0.0, 0.0]) + + val = np.array(1.0) + + out = _dll.openmc_get_image_data(0, 0, 0, 0, 0, origin.ctypes.data_as(POINTER(c_double*3)), 0.0, 0.0, val.ctypes.data_as(POINTER(c_double))) + print(val) + return out + + +def image_data_for_plot(plot): + img_data = np.zeros((plot.pixels_[0], plot.pixels_[1], 3), dtype = float) + + out = _dll.image_for_plot(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_double))) + return img_data From 177aff1a8dd4eed7687c64e4403b0409ac762277 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 26 Feb 2019 11:10:19 -0600 Subject: [PATCH 031/165] Separating Plot class into a C-compatible version for external use. Adding a function for returning an ID map. --- include/openmc/plot.h | 38 ++++++++++++------- openmc/capi/plot.py | 31 ++++------------ src/plot.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 115 insertions(+), 39 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index a6f215cfb..2898df363 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -20,6 +20,7 @@ namespace openmc { //=============================================================================== class Plot; +class PlotC; namespace model { @@ -52,6 +53,7 @@ struct RGBColor { }; typedef xt::xtensor ImageData; +typedef xt::xtensor IDData; enum class PlotType { slice = 1, @@ -73,7 +75,27 @@ enum class PlotColorBy { // Plot class //=============================================================================== -class Plot + +// plot class for interaction with external code +class CPlot { + +public: + int id_; //!< Plot ID + PlotType type_; //!< Plot type (Slice/Voxel) + PlotColorBy color_by_; //!< Plot coloring (cell/material) + Position origin_; //!< Plot origin in geometry + Position width_; //!< Plot width in geometry + PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) + std::array pixels_; //!< Plot size in pixels + int meshlines_width_; //!< Width of lines added to the plot + int level_; //!< Plot universe level + int index_meshlines_mesh_; //!< Index of the mesh to draw on the plot + RGBColor meshlines_color_; //!< Color of meshlines on the plot + RGBColor not_found_; //!< Plot background color +}; + + +class Plot : public CPlot { public: @@ -95,20 +117,8 @@ private: void set_meshlines(pugi::xml_node plot_node); void set_mask(pugi::xml_node plot_node); - // Members +// Members public: - int id_; //!< Plot ID - PlotType type_; //!< Plot type (Slice/Voxel) - PlotColorBy color_by_; //!< Plot coloring (cell/material) - Position origin_; //!< Plot origin in geometry - Position width_; //!< Plot width in geometry - PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) - std::array pixels_; //!< Plot size in pixels - int meshlines_width_; //!< Width of lines added to the plot - int level_; //!< Plot universe level - int index_meshlines_mesh_; //!< Index of the mesh to draw on the plot - RGBColor meshlines_color_; //!< Color of meshlines on the plot - RGBColor not_found_; //!< Plot background color std::vector colors_; //!< Plot colors std::string path_plot_; //!< Plot output filename }; diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index fea300aed..8ece52cb8 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -1,15 +1,10 @@ -from ctypes import c_int, c_double, c_ushort, POINTER, Structure +from ctypes import c_int, c_int32, c_double, c_ushort, POINTER, Structure from . import _dll from .core import _DLLGlobal import numpy as np -_dll.openmc_get_image_data.argtypes = [c_int, c_int, c_int, c_int, c_int, - POINTER(c_double*3), c_double, - c_double, POINTER(c_double)] -_dll.openmc_get_image_data.restype = c_double - class _Position(Structure): pass @@ -38,25 +33,15 @@ _Plot._fields_ = [('id_', c_int), ('level_', c_int), ('index_meshlines_mesh_', c_int), ('meshlines_color_', _RGBColor), - ('not_found_', _RGBColor), - ('colors_', POINTER(_RGBColor))] + ('not_found_', _RGBColor)] -_dll.image_for_plot.argtypes= [POINTER(_Plot),] -_dll.image_for_plot.restype = c_int - -def get_image_data(): - origin = np.array([0.0, 0.0, 0.0]) - - val = np.array(1.0) - - out = _dll.openmc_get_image_data(0, 0, 0, 0, 0, origin.ctypes.data_as(POINTER(c_double*3)), 0.0, 0.0, val.ctypes.data_as(POINTER(c_double))) - print(val) - return out - +_dll.openmc_id_map.argtypes= [POINTER(_Plot),] +_dll.openmc_id_map.restype = c_int def image_data_for_plot(plot): - img_data = np.zeros((plot.pixels_[0], plot.pixels_[1], 3), dtype = float) - - out = _dll.image_for_plot(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_double))) + img_data = np.zeros((plot.pixels_[0], plot.pixels_[1], 2), dtype=np.dtype('int32')) + print(img_data[0,0]) + out = _dll.openmc_id_map(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_int32))) + print(img_data[0,0]) return img_data diff --git a/src/plot.cpp b/src/plot.cpp index 5ad1deca1..20590dce8 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -645,9 +645,9 @@ Plot::set_mask(pugi::xml_node plot_node) } } -Plot::Plot(pugi::xml_node plot_node): -index_meshlines_mesh_(-1) +Plot::Plot(pugi::xml_node plot_node) { + index_meshlines_mesh_ = -1; set_id(plot_node); set_type(plot_node); set_output_path(plot_node); @@ -979,4 +979,85 @@ RGBColor random_color() { return {int(prn()*255), int(prn()*255), int(prn()*255)}; } +extern "C" int openmc_id_map(const CPlot& pl, int* data_out) { + + size_t width = pl.pixels_[0]; + size_t height = pl.pixels_[1]; + + double in_pixel = (pl.width_[0])/static_cast(width); + double out_pixel = (pl.width_[1])/static_cast(height); + + IDData data; + data.resize({width, height, 2}); + + int in_i, out_i; + double xyz[3]; + switch(pl.basis_) { + case PlotBasis::xy : + in_i = 0; + out_i = 1; + xyz[0] = pl.origin_[0] - pl.width_[0] / 2.; + xyz[1] = pl.origin_[1] + pl.width_[1] / 2.; + xyz[2] = pl.origin_[2]; + break; + case PlotBasis::xz : + in_i = 0; + out_i = 2; + xyz[0] = pl.origin_[0] - pl.width_[0] / 2.; + xyz[1] = pl.origin_[1]; + xyz[2] = pl.origin_[2] + pl.width_[1] / 2.; + break; + case PlotBasis::yz : + in_i = 1; + out_i = 2; + xyz[0] = pl.origin_[0]; + xyz[1] = pl.origin_[1] - pl.width_[0] / 2.; + xyz[2] = pl.origin_[2] + pl.width_[1] / 2.; + break; + } + + double dir[3] = {0.5, 0.5, 0.5}; + + //#pragma omp parallel +{ + Particle p; + p.initialize(); + std::copy(xyz, xyz+3, p.coord[0].xyz); + std::copy(dir, dir+3, p.coord[0].uvw); + p.coord[0].universe = model::root_universe; + int level = pl.level_; + int j{}; + + //#pragma omp for + for (int y = 0; y < height; y++) { + p.coord[0].xyz[out_i] = xyz[out_i] - out_pixel * y; + p.n_coord = 1; + for (int x = 0; x < width; x++) { + p.coord[0].xyz[in_i] = xyz[in_i] + in_pixel * x; + // local variables + bool found_cell = find_cell(&p, 0); + j = p.n_coord - 1; + if (level >=0) {j = level + 1;} + if (!found_cell) { + data(x,y,0) = -1; + data(x,y,1) = -1; + } else { + Cell *c = model::cells[p.coord[j].cell]; + data(x,y,0) = c->id_; + if (c->type_ == FILL_UNIVERSE || p.material == MATERIAL_VOID) { + data(x,y,1) = -1; + } else { + data(x,y,1) = model::materials[p.material - 1]->id_; + } + } + } + } + } + + size_t i = 0; + for (auto v : data) { data_out[i++] = v; } + + return 0; +} + } // namespace openmc From c968866c0e10dc3ab9dc2d96bb49fe54c7e9d5f0 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 26 Feb 2019 15:08:19 -0600 Subject: [PATCH 032/165] Removing prints from capi plot module. --- openmc/capi/plot.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 8ece52cb8..e1d67d704 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -41,7 +41,5 @@ _dll.openmc_id_map.restype = c_int def image_data_for_plot(plot): img_data = np.zeros((plot.pixels_[0], plot.pixels_[1], 2), dtype=np.dtype('int32')) - print(img_data[0,0]) out = _dll.openmc_id_map(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_int32))) - print(img_data[0,0]) return img_data From a0931879a6b6b8af5fbd0578489d6d2ce783ce73 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 26 Feb 2019 15:20:44 -0600 Subject: [PATCH 033/165] Re-adding OpenMP pragmas. --- src/plot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index 20590dce8..6f7853bfb 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -1018,7 +1018,7 @@ extern "C" int openmc_id_map(const CPlot& pl, int* data_out) { double dir[3] = {0.5, 0.5, 0.5}; - //#pragma omp parallel +#pragma omp parallel { Particle p; p.initialize(); @@ -1028,7 +1028,7 @@ extern "C" int openmc_id_map(const CPlot& pl, int* data_out) { int level = pl.level_; int j{}; - //#pragma omp for +#pragma omp for for (int y = 0; y < height; y++) { p.coord[0].xyz[out_i] = xyz[out_i] - out_pixel * y; p.n_coord = 1; From b8fec08eeb638155a6edb55185288693d282d4cb Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 26 Feb 2019 15:46:24 -0600 Subject: [PATCH 034/165] Some adjustments to the CPlot class. Moving attributes it doesn't need back to the main Plot class. --- include/openmc/plot.h | 14 +++++++------- openmc/capi/plot.py | 11 ++--------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 2898df363..aef7e613b 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -80,18 +80,11 @@ enum class PlotColorBy { class CPlot { public: - int id_; //!< Plot ID - PlotType type_; //!< Plot type (Slice/Voxel) - PlotColorBy color_by_; //!< Plot coloring (cell/material) Position origin_; //!< Plot origin in geometry Position width_; //!< Plot width in geometry PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) std::array pixels_; //!< Plot size in pixels - int meshlines_width_; //!< Width of lines added to the plot int level_; //!< Plot universe level - int index_meshlines_mesh_; //!< Index of the mesh to draw on the plot - RGBColor meshlines_color_; //!< Color of meshlines on the plot - RGBColor not_found_; //!< Plot background color }; @@ -119,6 +112,13 @@ private: // Members public: + int id_; //!< Plot ID + PlotType type_; //!< Plot type (Slice/Voxel) + PlotColorBy color_by_; //!< Plot coloring (cell/material) + int meshlines_width_; //!< Width of lines added to the plot + int index_meshlines_mesh_; //!< Index of the mesh to draw on the plot + RGBColor meshlines_color_; //!< Color of meshlines on the plot + RGBColor not_found_; //!< Plot background color std::vector colors_; //!< Plot colors std::string path_plot_; //!< Plot output filename }; diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index e1d67d704..ce527130d 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -22,18 +22,11 @@ _RGBColor._fields_ = [('red', c_ushort), class _Plot(Structure): pass -_Plot._fields_ = [('id_', c_int), - ('type_', c_int), - ('color_by_', c_int), - ('origin_', _Position), +_Plot._fields_ = [('origin_', _Position), ('width_', _Position), ('basis_', c_int), ('pixels_', c_int*3), - ('meshlines_width_', c_int), - ('level_', c_int), - ('index_meshlines_mesh_', c_int), - ('meshlines_color_', _RGBColor), - ('not_found_', _RGBColor)] + ('level_', c_int)] _dll.openmc_id_map.argtypes= [POINTER(_Plot),] From 10a8e3a83d45dc20983bf5de9d25b530cc2abab1 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 27 Feb 2019 11:54:40 -0600 Subject: [PATCH 035/165] Implementing proper python classes in the new capi plot module. --- openmc/capi/plot.py | 172 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 157 insertions(+), 15 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index ce527130d..dd95f3dd6 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -2,35 +2,177 @@ from ctypes import c_int, c_int32, c_double, c_ushort, POINTER, Structure from . import _dll from .core import _DLLGlobal +from .error import _error_handler import numpy as np +class _IntThree(): + type_ = c_int*3 + val_ = None + def __init__(self, vals=None): + if vals and iterable(vals) and all(vals == int): + self.val_ = type_(vals[0], vals[1], vals[2]) + else: + raise ValueError("{} is not a valid object to construct IntThree.".format(vals)) + + def __str__(self): + return "({}, {}, {})".format(self.val_[0], self.val_[1], self.val_[2]) + class _Position(Structure): - pass + _fields_ = [('x', c_double), + ('y', c_double), + ('z', c_double)] -_Position._fields_ = [('x', c_double), - ('y', c_double), - ('z', c_double)] + def __init__(self, vals=None): + if vals: + x = vals[0] + y = vals[1] + z = vals[2] + else: + x = 0.0 + y = 0.0 + z = 0.0 -class _RGBColor(Structure): - pass + @property + def x(self): + return self.x -_RGBColor._fields_ = [('red', c_ushort), - ('green', c_ushort), - ('blue', c_ushort)] + @property + def y(self): + return self.y + + @property + def z(self): + return self.z + + @x.setter + def x(self, x_val): + assert(isinstance(x_val, float)) + self.x = x_val + + @y.setter + def y(self, y_val): + assert(isinstance(y_val, float)) + self.y = y_val + + @z.setter + def z(self, z_val): + assert(isinstance(z_val, float)) + self.z = z_val + + def __str__(self): + return "({}, {}, {})".format(self.x, self.y, self.z) class _Plot(Structure): - pass + _fields_ = [('origin_', _Position), + ('width_', _Position), + ('basis_', c_int), + ('pixels_', c_int*3), + ('level_', c_int)] -_Plot._fields_ = [('origin_', _Position), - ('width_', _Position), - ('basis_', c_int), - ('pixels_', c_int*3), - ('level_', c_int)] + @property + def origin(self): + out = [self.origin_.x, self.origin_.y, self.origin_.z] + return [float(val) for val in out] + + @property + def width(self): + return float(self.width_.x) + + @property + def height(self): + return float(self.width_.y) + + @property + def basis(self): + if self.basis_ == 1: + return 'xy' + elif self.basis_ == 2: + return 'xz' + elif self.basis_ == 3: + return 'yz' + + raise ValueError("Plot basis {} is invalid".format(basis_)) + + @property + def hRes(self): + return self.pixels_[0] + + @property + def vRes(self): + return self.pixels_[1] + + @property + def level(self): + return int(self.level_) + + @origin.setter + def origin(self, origin): + self.origin_.x = origin[0] + self.origin_.y = origin[1] + self.origin_.z = origin[2] + + @width.setter + def width(self, width): + self.width_.x = width + + @height.setter + def height(self, height): + self.width_.y = height + + @basis.setter + def basis(self, basis): + if isinstance(basis, str): + valid_bases = ('xy', 'xz', 'yz') + if basis not in valid_bases: + raise ValueError("{} is not a valid plot basis.".format(basis)) + + if basis == 'xy': + self.basis_ = 1 + elif basis == 'xz': + self.basis_ = 2 + elif basis == 'yz': + self.basis_ = 3 + return + + if isinstance(basis, int): + valid_bases = (1, 2, 3) + if basis not in valid_bases: + raise ValueError("{} is not a valid plot basis.".format(basis)) + self.basis_ = basis + return + + raise ValueError("{} of type {} is an invalid plot basis".format(basis, type(basis))) + + @hRes.setter + def hRes(self, hRes): + self.pixels_[0] = hRes + + @vRes.setter + def vRes(self, vRes): + self.pixels_[1] = vRes + + @level.setter + def level(self, level): + self.level_ = level + + def __str__(self): + out_str = "-------" + out_str += "Plot:\n" + out_str += "-------" + out_str += "Origin: " + str(self.origin) + "\n" + out_str += "Width: " + str(self.width) + "\n" + out_str += "Height: " + str(self.height) + "\n" + out_str += "Basis: " + str(self.basis) + "\n" + out_str += "HRes: " + str(self.hRes) + "\n" + out_str += "VRes: " + str(self.vRes) + "\n" + out_str += "Level: " + str(self.level) + "\n" + return out_str _dll.openmc_id_map.argtypes= [POINTER(_Plot),] _dll.openmc_id_map.restype = c_int +_dll.openmc_id_map.errcheck = _error_handler def image_data_for_plot(plot): img_data = np.zeros((plot.pixels_[0], plot.pixels_[1], 2), dtype=np.dtype('int32')) From 64d54c692da65a54493cb36119d9b0ebe753373a Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 27 Feb 2019 16:19:12 -0600 Subject: [PATCH 036/165] Adding inital value for plot level --- openmc/capi/plot.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index dd95f3dd6..3e3ec2e68 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -70,6 +70,9 @@ class _Plot(Structure): ('pixels_', c_int*3), ('level_', c_int)] + def __init__(self): + self.level_ = -1 + @property def origin(self): out = [self.origin_.x, self.origin_.y, self.origin_.z] From 7d98804bca14aad738802d8539bf7ff9839ada89 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 27 Feb 2019 21:57:09 -0600 Subject: [PATCH 037/165] Renaming external function. --- openmc/capi/plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 3e3ec2e68..22f1416b2 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -177,7 +177,7 @@ _dll.openmc_id_map.argtypes= [POINTER(_Plot),] _dll.openmc_id_map.restype = c_int _dll.openmc_id_map.errcheck = _error_handler -def image_data_for_plot(plot): +def id_map(plot): img_data = np.zeros((plot.pixels_[0], plot.pixels_[1], 2), dtype=np.dtype('int32')) out = _dll.openmc_id_map(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_int32))) return img_data From b0bafee385a784fea77a638b23ecc9485588353d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 27 Feb 2019 22:13:46 -0600 Subject: [PATCH 038/165] Flipping id_map ordering. --- openmc/capi/plot.py | 2 +- src/plot.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 22f1416b2..10a6aa280 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -178,6 +178,6 @@ _dll.openmc_id_map.restype = c_int _dll.openmc_id_map.errcheck = _error_handler def id_map(plot): - img_data = np.zeros((plot.pixels_[0], plot.pixels_[1], 2), dtype=np.dtype('int32')) + img_data = np.zeros((plot.pixels_[1], plot.pixels_[0], 2), dtype=np.dtype('int32')) out = _dll.openmc_id_map(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_int32))) return img_data diff --git a/src/plot.cpp b/src/plot.cpp index 6f7853bfb..9bf3656d9 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -988,7 +988,7 @@ extern "C" int openmc_id_map(const CPlot& pl, int* data_out) { double out_pixel = (pl.width_[1])/static_cast(height); IDData data; - data.resize({width, height, 2}); + data.resize({height, width, 2}); int in_i, out_i; double xyz[3]; @@ -1039,15 +1039,15 @@ extern "C" int openmc_id_map(const CPlot& pl, int* data_out) { j = p.n_coord - 1; if (level >=0) {j = level + 1;} if (!found_cell) { - data(x,y,0) = -1; - data(x,y,1) = -1; + data(y,x,0) = -1; + data(y,x,1) = -1; } else { Cell *c = model::cells[p.coord[j].cell]; - data(x,y,0) = c->id_; + data(y,x,0) = c->id_; if (c->type_ == FILL_UNIVERSE || p.material == MATERIAL_VOID) { - data(x,y,1) = -1; + data(y,x,1) = -1; } else { - data(x,y,1) = model::materials[p.material - 1]->id_; + data(y,x,1) = model::materials[p.material - 1]->id_; } } } From a371f402a2b078ab4237067dd0c5ada8e17f78f0 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 5 Mar 2019 19:24:38 -0600 Subject: [PATCH 039/165] Correction to n_coord reset on particle for proper handling of universes. Renaming CPlot to PlotBase and adding a capi test. Mirroring use of Bank in the capi. Updating header name. Adding documentation to capi plot module. Removing plot base header and struct. --- include/openmc/capi.h | 1 + include/openmc/plot.h | 15 ++--- openmc/capi/plot.py | 102 +++++++++++++++++++++++++--------- src/plot.cpp | 39 +++++++------ tests/unit_tests/test_capi.py | 21 +++++++ 5 files changed, 125 insertions(+), 53 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 9bfe4aa9e..07c6bc80e 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -70,6 +70,7 @@ extern "C" { int openmc_next_batch(int* status); int openmc_nuclide_name(int index, const char** name); int openmc_plot_geometry(); + int openmc_id_map(void* slice, int32_t *data_out); int openmc_reset(); int openmc_run(); void openmc_set_seed(int64_t new_seed); diff --git a/include/openmc/plot.h b/include/openmc/plot.h index aef7e613b..0bbd3c3ad 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -20,7 +20,7 @@ namespace openmc { //=============================================================================== class Plot; -class PlotC; + namespace model { @@ -74,21 +74,16 @@ enum class PlotColorBy { //=============================================================================== // Plot class //=============================================================================== - - -// plot class for interaction with external code -class CPlot { - -public: +struct Slice { + // Members Position origin_; //!< Plot origin in geometry Position width_; //!< Plot width in geometry PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) - std::array pixels_; //!< Plot size in pixels + int pixels_[3]; //!< Plot size in pixels int level_; //!< Plot universe level }; - -class Plot : public CPlot +class Plot : public Slice { public: diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 10a6aa280..fe7dd531c 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -6,19 +6,18 @@ from .error import _error_handler import numpy as np -class _IntThree(): - type_ = c_int*3 - val_ = None - def __init__(self, vals=None): - if vals and iterable(vals) and all(vals == int): - self.val_ = type_(vals[0], vals[1], vals[2]) - else: - raise ValueError("{} is not a valid object to construct IntThree.".format(vals)) - - def __str__(self): - return "({}, {}, {})".format(self.val_[0], self.val_[1], self.val_[2]) - class _Position(Structure): + """Definition of an xyz location in space with underlying c-types + + C-type Attributes + ----------------- + x : c_double + Position's x value (default: 0.0) + y : c_double + Position's y value (default: 0.0) + z : c_double + Position's z value (default: 0.0) + """ _fields_ = [('x', c_double), ('y', c_double), ('z', c_double)] @@ -61,9 +60,43 @@ class _Position(Structure): self.z = z_val def __str__(self): - return "({}, {}, {})".format(self.x, self.y, self.z) + return "Position: ({}, {}, {})".format(self.x, self.y, self.z) + class _Plot(Structure): + """A Plot structure defining a 2-D slice with underlying c-types + + C-Type Attributes + ----------------- + origin : openmc.capi.plot._Position + A position defining the origin of the plot. + width_ : openmc.capi.plot._Position + The width of the plot along the x, y, and z axes, respectively + basis_ : c_int + The axes basis of the plot view. + pixels_ : c_int[3] + The resolution of the plot in the horizontal and vertical dimensions + level_ : c_int + The universe level for the plot view + + Attributes + ---------- + origin : tuple or list of ndarray + Origin (center) of the plot + width : float + The horizontal dimension of the plot in geometry units (cm) + height : float + The vertical dimension of the plot in geometry units (cm) + basis : string + One of {'xy', 'xz', 'yz'} indicating the horizontal and vertical + axes of the plot. + hRes : float + The horizontal resolution of the plot in pixels + vRes : float + The vertical resolution of the plot in pixels + level : int + The universe level for the plot (default: -1 -> all universes shown) + """ _fields_ = [('origin_', _Position), ('width_', _Position), ('basis_', c_int), @@ -127,6 +160,7 @@ class _Plot(Structure): def basis(self, basis): if isinstance(basis, str): valid_bases = ('xy', 'xz', 'yz') + basis = basis.lower() if basis not in valid_bases: raise ValueError("{} is not a valid plot basis.".format(basis)) @@ -159,25 +193,43 @@ class _Plot(Structure): def level(self, level): self.level_ = level - def __str__(self): - out_str = "-------" + def __repr__(self): + out_str = "-----\n" out_str += "Plot:\n" - out_str += "-------" - out_str += "Origin: " + str(self.origin) + "\n" - out_str += "Width: " + str(self.width) + "\n" - out_str += "Height: " + str(self.height) + "\n" - out_str += "Basis: " + str(self.basis) + "\n" - out_str += "HRes: " + str(self.hRes) + "\n" - out_str += "VRes: " + str(self.vRes) + "\n" - out_str += "Level: " + str(self.level) + "\n" + out_str += "-----\n" + out_str += "Origin: {}\n".format(self.origin) + out_str += "Width: {}\n".format(self.width) + out_str += "Height: {}\n".format(self.height) + out_str += "Basis: {}\n".format(self.basis) + out_str += "HRes: {}\n".format(self.hRes) + out_str += "VRes: {}\n".format(self.vRes) + out_str += "Level: {}\n".format(self.level) return out_str + def __str__(self): + return self.__repr__() + _dll.openmc_id_map.argtypes= [POINTER(_Plot),] _dll.openmc_id_map.restype = c_int _dll.openmc_id_map.errcheck = _error_handler + def id_map(plot): - img_data = np.zeros((plot.pixels_[1], plot.pixels_[0], 2), dtype=np.dtype('int32')) - out = _dll.openmc_id_map(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_int32))) + """ + Generate a 2-D map of (cell_id, material_id). Used for in-memory image generation. + + Parameters + ---------- + plot : An openmc.capi.plot._Plot object describing the slice of the model to + be generated + + Returns + ------- + id_map : a NumPy array with shape (vertical pixels, horizontal pixels, 2) + of OpenMC property ids with dtype int32 + + """ + img_data = np.zeros((plot.vRes, plot.hRes, 2), dtype=np.dtype('int32')) + _dll.openmc_id_map(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_int32))) return img_data diff --git a/src/plot.cpp b/src/plot.cpp index 9bf3656d9..73aa3d4f6 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -886,7 +886,8 @@ void create_voxel(Plot pl) // Write current date and time write_attribute(file_id, "date_and_time", time_stamp().c_str()); hsize_t three = 3; - write_attribute(file_id, "num_voxels", pl.pixels_); + std::array pixels = {pl.pixels_[0], pl.pixels_[1], pl.pixels_[2]}; + write_attribute(file_id, "num_voxels", pixels); write_attribute(file_id, "voxel_width", vox); write_attribute(file_id, "lower_left", ll); @@ -979,40 +980,42 @@ RGBColor random_color() { return {int(prn()*255), int(prn()*255), int(prn()*255)}; } -extern "C" int openmc_id_map(const CPlot& pl, int* data_out) { +extern "C" int openmc_id_map(void* slice, int32_t* data_out) { - size_t width = pl.pixels_[0]; - size_t height = pl.pixels_[1]; + auto* sl = static_cast(slice); - double in_pixel = (pl.width_[0])/static_cast(width); - double out_pixel = (pl.width_[1])/static_cast(height); + size_t width = sl->pixels_[0]; + size_t height = sl->pixels_[1]; + + double in_pixel = (sl->width_[0])/static_cast(width); + double out_pixel = (sl->width_[1])/static_cast(height); IDData data; data.resize({height, width, 2}); int in_i, out_i; double xyz[3]; - switch(pl.basis_) { + switch(sl->basis_) { case PlotBasis::xy : in_i = 0; out_i = 1; - xyz[0] = pl.origin_[0] - pl.width_[0] / 2.; - xyz[1] = pl.origin_[1] + pl.width_[1] / 2.; - xyz[2] = pl.origin_[2]; + xyz[0] = sl->origin_[0] - sl->width_[0] / 2. + in_pixel / 2.; + xyz[1] = sl->origin_[1] + sl->width_[1] / 2. - out_pixel / 2.; + xyz[2] = sl->origin_[2]; break; case PlotBasis::xz : in_i = 0; out_i = 2; - xyz[0] = pl.origin_[0] - pl.width_[0] / 2.; - xyz[1] = pl.origin_[1]; - xyz[2] = pl.origin_[2] + pl.width_[1] / 2.; + xyz[0] = sl->origin_[0] - sl->width_[0] / 2. + in_pixel / 2.; + xyz[1] = sl->origin_[1]; + xyz[2] = sl->origin_[2] + sl->width_[1] / 2. - out_pixel / 2.; break; case PlotBasis::yz : in_i = 1; out_i = 2; - xyz[0] = pl.origin_[0]; - xyz[1] = pl.origin_[1] - pl.width_[0] / 2.; - xyz[2] = pl.origin_[2] + pl.width_[1] / 2.; + xyz[0] = sl->origin_[0]; + xyz[1] = sl->origin_[1] - sl->width_[0] / 2. + in_pixel / 2.; + xyz[2] = sl->origin_[2] + sl->width_[1] / 2. - out_pixel / 2.; break; } @@ -1025,15 +1028,15 @@ extern "C" int openmc_id_map(const CPlot& pl, int* data_out) { std::copy(xyz, xyz+3, p.coord[0].xyz); std::copy(dir, dir+3, p.coord[0].uvw); p.coord[0].universe = model::root_universe; - int level = pl.level_; + int level = sl->level_; int j{}; #pragma omp for for (int y = 0; y < height; y++) { p.coord[0].xyz[out_i] = xyz[out_i] - out_pixel * y; - p.n_coord = 1; for (int x = 0; x < width; x++) { p.coord[0].xyz[in_i] = xyz[in_i] + in_pixel * x; + p.n_coord = 1; // local variables bool found_cell = find_cell(&p, 0); j = p.n_coord - 1; diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 0ebc898b4..9d9ab66c0 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -400,3 +400,24 @@ def test_load_nuclide(capi_init): # load non-existent nuclide with pytest.raises(exc.DataError): openmc.capi.load_nuclide('Pu3') + + +def test_id_map(capi_init): + expected_ids = np.array([[(3,3), (2,2), (3,3)], + [(2,2), (1,1), (2,2)], + [(3,3), (2,2), (3,3)]], dtype = 'int32') + + # create a plot object + p = openmc.capi.plot._Plot() + + p.width = 1.26 + p.height = 1.26 + p.vRes = 3 + p.hRes = 3 + p.origin = (0,0,0) + p.basis = 'xy' + p.level = -1 + + ids = openmc.capi.plot.id_map(p) + print(ids) + assert np.array_equal(expected_ids, ids) From 1f13efecdb023449aa77d123da2abcf72d4d9a6f Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 7 Mar 2019 17:25:25 -0600 Subject: [PATCH 040/165] Rebase updates. --- include/openmc/plot.h | 1 - openmc/capi/plot.py | 3 ++- src/plot.cpp | 23 +++++++++++------------ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 0bbd3c3ad..778bef4f6 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -21,7 +21,6 @@ namespace openmc { class Plot; - namespace model { extern std::vector plots; //!< Plot instance container diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index fe7dd531c..f119ce476 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -210,7 +210,7 @@ class _Plot(Structure): return self.__repr__() -_dll.openmc_id_map.argtypes= [POINTER(_Plot),] +_dll.openmc_id_map.argtypes= [POINTER(_Plot),POINTER(c_int32)] _dll.openmc_id_map.restype = c_int _dll.openmc_id_map.errcheck = _error_handler @@ -231,5 +231,6 @@ def id_map(plot): """ img_data = np.zeros((plot.vRes, plot.hRes, 2), dtype=np.dtype('int32')) + print("Calling openmc id map") _dll.openmc_id_map(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_int32))) return img_data diff --git a/src/plot.cpp b/src/plot.cpp index 73aa3d4f6..8b3fefc81 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -982,7 +982,7 @@ RGBColor random_color() { extern "C" int openmc_id_map(void* slice, int32_t* data_out) { - auto* sl = static_cast(slice); + auto sl = static_cast(slice); size_t width = sl->pixels_[0]; size_t height = sl->pixels_[1]; @@ -1024,33 +1024,32 @@ extern "C" int openmc_id_map(void* slice, int32_t* data_out) { #pragma omp parallel { Particle p; - p.initialize(); - std::copy(xyz, xyz+3, p.coord[0].xyz); - std::copy(dir, dir+3, p.coord[0].uvw); - p.coord[0].universe = model::root_universe; + p.coord_[0].r = xyz; + p.coord_[0].u = dir; + p.coord_[0].universe = model::root_universe; int level = sl->level_; int j{}; #pragma omp for for (int y = 0; y < height; y++) { - p.coord[0].xyz[out_i] = xyz[out_i] - out_pixel * y; + p.coord_[0].r[out_i] = xyz[out_i] - out_pixel * y; for (int x = 0; x < width; x++) { - p.coord[0].xyz[in_i] = xyz[in_i] + in_pixel * x; - p.n_coord = 1; + p.coord_[0].r[in_i] = xyz[in_i] + in_pixel * x; + p.n_coord_ = 1; // local variables bool found_cell = find_cell(&p, 0); - j = p.n_coord - 1; + j = p.n_coord_ - 1; if (level >=0) {j = level + 1;} if (!found_cell) { data(y,x,0) = -1; data(y,x,1) = -1; } else { - Cell *c = model::cells[p.coord[j].cell]; + Cell *c = model::cells[p.coord_[j].cell].get(); data(y,x,0) = c->id_; - if (c->type_ == FILL_UNIVERSE || p.material == MATERIAL_VOID) { + if (c->type_ == FILL_UNIVERSE || p.material_ == MATERIAL_VOID) { data(y,x,1) = -1; } else { - data(y,x,1) = model::materials[p.material - 1]->id_; + data(y,x,1) = model::materials[p.material_]->id_; } } } From c97d046bc61e57672a99ddf7e9439aa6096187f6 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 7 Mar 2019 18:09:20 -0600 Subject: [PATCH 041/165] Self review. --- include/openmc/plot.h | 2 +- openmc/capi/__init__.py | 3 +- openmc/capi/plot.py | 18 ++++----- src/plot.cpp | 69 +++++++++++++---------------------- tests/unit_tests/test_capi.py | 20 +++++----- 5 files changed, 45 insertions(+), 67 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 778bef4f6..a5fa4b065 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -78,7 +78,7 @@ struct Slice { Position origin_; //!< Plot origin in geometry Position width_; //!< Plot width in geometry PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) - int pixels_[3]; //!< Plot size in pixels + std::array pixels_; //!< Plot size in pixels int level_; //!< Plot universe level }; diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index e162387ff..5ca867d67 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -12,8 +12,7 @@ objects in the :mod:`openmc.capi` subpackage, for example: """ -from ctypes import CDLL, c_bool, c_int -import numpy as np +from ctypes import CDLL, c_bool import os import sys diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index f119ce476..2227435ed 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -1,4 +1,4 @@ -from ctypes import c_int, c_int32, c_double, c_ushort, POINTER, Structure +from ctypes import c_int, c_int32, c_double, Structure, POINTER from . import _dll from .core import _DLLGlobal @@ -63,8 +63,8 @@ class _Position(Structure): return "Position: ({}, {}, {})".format(self.x, self.y, self.z) -class _Plot(Structure): - """A Plot structure defining a 2-D slice with underlying c-types +class _Slice(Structure): + """A structure defining a 2-D slice with underlying c-types C-Type Attributes ----------------- @@ -100,7 +100,7 @@ class _Plot(Structure): _fields_ = [('origin_', _Position), ('width_', _Position), ('basis_', c_int), - ('pixels_', c_int*3), + ('pixels_', 3*c_int), ('level_', c_int)] def __init__(self): @@ -210,18 +210,18 @@ class _Plot(Structure): return self.__repr__() -_dll.openmc_id_map.argtypes= [POINTER(_Plot),POINTER(c_int32)] +_dll.openmc_id_map.argtypes= [POINTER(_Slice),POINTER(c_int32)] _dll.openmc_id_map.restype = c_int _dll.openmc_id_map.errcheck = _error_handler -def id_map(plot): +def id_map(slice_view): """ Generate a 2-D map of (cell_id, material_id). Used for in-memory image generation. Parameters ---------- - plot : An openmc.capi.plot._Plot object describing the slice of the model to + plot : An openmc.capi.plot._Slice object describing the slice of the model to be generated Returns @@ -230,7 +230,7 @@ def id_map(plot): of OpenMC property ids with dtype int32 """ - img_data = np.zeros((plot.vRes, plot.hRes, 2), dtype=np.dtype('int32')) + img_data = np.zeros((slice_view.vRes, slice_view.hRes, 2), dtype=np.dtype('int32')) print("Calling openmc id map") - _dll.openmc_id_map(POINTER(_Plot)(plot), img_data.ctypes.data_as(POINTER(c_int32))) + _dll.openmc_id_map(POINTER(_Slice)(slice_view), img_data.ctypes.data_as(POINTER(c_int32))) return img_data diff --git a/src/plot.cpp b/src/plot.cpp index 8b3fefc81..b5b91adba 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -27,7 +27,7 @@ namespace openmc { const RGBColor WHITE {255, 255, 255}; constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level - +constexpr int NOT_FOUND {-1}; //============================================================================== // Global variables //============================================================================== @@ -88,27 +88,6 @@ void read_plots_xml() } } -void -write_ids(const Plot& pl, xt::xtensor ids) { - - // create a binary file with ID information - std::string fname = "plot_ids.binary"; - std::ofstream of; - - of.open(fname, std::ios::binary); - of.write((char*) &(pl.pixels_[0]), sizeof(int)); - of.write((char*) &(pl.pixels_[1]), sizeof(int)); - of.write((char*) &(pl.width_[0]), sizeof(double)); - of.write((char*) &(pl.width_[1]), sizeof(double)); - for (int y = 0; y < pl.pixels_[1]; y++) { - for (int x = 0; x < pl.pixels_[0]; x++) { - of.write((char*) &(ids(x,y)), sizeof(int)); - } - } - - of.close(); -} - //============================================================================== // CREATE_PPM creates an image based on user input from a plots.xml // specification in the portable pixmap format (PPM) @@ -125,8 +104,6 @@ void create_ppm(Plot pl) ImageData data; data.resize({width, height}); - xt::xtensor ids; - ids.resize({width, height}); int in_i, out_i; Position r; @@ -173,7 +150,6 @@ void create_ppm(Plot pl) p.r()[in_i] = r[in_i] + in_pixel * x; position_rgb(p, pl, rgb, id); data(x,y) = rgb; - ids(x,y) = id; } } } @@ -182,9 +158,6 @@ void create_ppm(Plot pl) // write ppm data to file output_ppm(pl, data); - - // write ids to binary file - write_ids(pl, ids); } void @@ -684,7 +657,7 @@ void position_rgb(Particle p, Plot pl, RGBColor& rgb, int& id) if (!found_cell) { // If no cell, revert to default color rgb = pl.not_found_; - id = -1; + id = NOT_FOUND; } else { if (PlotColorBy::mats == pl.color_by_) { // Assign color based on material @@ -692,11 +665,11 @@ void position_rgb(Particle p, Plot pl, RGBColor& rgb, int& id) if (c->type_ == FILL_UNIVERSE) { // If we stopped on a middle universe level, treat as if not found rgb = pl.not_found_; - id = -1; + id = NOT_FOUND; } else if (p.material_ == MATERIAL_VOID) { // By default, color void cells white rgb = WHITE; - id = -1; + id = NOT_FOUND; } else { rgb = pl.colors_[p.material_]; id = model::materials[p.material_]->id_; @@ -886,8 +859,7 @@ void create_voxel(Plot pl) // Write current date and time write_attribute(file_id, "date_and_time", time_stamp().c_str()); hsize_t three = 3; - std::array pixels = {pl.pixels_[0], pl.pixels_[1], pl.pixels_[2]}; - write_attribute(file_id, "num_voxels", pixels); + write_attribute(file_id, "num_voxels", pl.pixels_); write_attribute(file_id, "voxel_width", vox); write_attribute(file_id, "lower_left", ll); @@ -982,17 +954,24 @@ RGBColor random_color() { extern "C" int openmc_id_map(void* slice, int32_t* data_out) { - auto sl = static_cast(slice); + auto sl = reinterpret_cast(slice); + if (!sl) { + set_errmsg("Invalid slice pointer passed to openmc_id_map"); + return OPENMC_E_INVALID_ARGUMENT; + } size_t width = sl->pixels_[0]; size_t height = sl->pixels_[1]; + // get pixel size double in_pixel = (sl->width_[0])/static_cast(width); double out_pixel = (sl->width_[1])/static_cast(height); + // size data array IDData data; data.resize({height, width, 2}); + // setup basis indices and initial position centered on pixel int in_i, out_i; double xyz[3]; switch(sl->basis_) { @@ -1019,43 +998,45 @@ extern "C" int openmc_id_map(void* slice, int32_t* data_out) { break; } + // arbitrary direction double dir[3] = {0.5, 0.5, 0.5}; #pragma omp parallel { Particle p; - p.coord_[0].r = xyz; - p.coord_[0].u = dir; + p.r() = xyz; + p.u() = dir; p.coord_[0].universe = model::root_universe; int level = sl->level_; int j{}; #pragma omp for for (int y = 0; y < height; y++) { - p.coord_[0].r[out_i] = xyz[out_i] - out_pixel * y; + p.r()[out_i] = xyz[out_i] - out_pixel * y; for (int x = 0; x < width; x++) { - p.coord_[0].r[in_i] = xyz[in_i] + in_pixel * x; + p.r()[in_i] = xyz[in_i] + in_pixel * x; p.n_coord_ = 1; // local variables bool found_cell = find_cell(&p, 0); j = p.n_coord_ - 1; if (level >=0) {j = level + 1;} if (!found_cell) { - data(y,x,0) = -1; - data(y,x,1) = -1; + data(y,x,0) = NOT_FOUND; + data(y,x,1) = NOT_FOUND; } else { Cell *c = model::cells[p.coord_[j].cell].get(); data(y,x,0) = c->id_; if (c->type_ == FILL_UNIVERSE || p.material_ == MATERIAL_VOID) { - data(y,x,1) = -1; + data(y,x,1) = NOT_FOUND; } else { data(y,x,1) = model::materials[p.material_]->id_; } } - } - } - } + } // inner for + } // outer for + } // omp parallel + // write id data to array size_t i = 0; for (auto v : data) { data_out[i++] = v; } diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 9d9ab66c0..760022706 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -408,16 +408,14 @@ def test_id_map(capi_init): [(3,3), (2,2), (3,3)]], dtype = 'int32') # create a plot object - p = openmc.capi.plot._Plot() + s = openmc.capi.plot._Slice() + s.width = 1.26 + s.height = 1.26 + s.vRes = 3 + s.hRes = 3 + s.origin = (0,0,0) + s.basis = 'xy' + s.level = -1 - p.width = 1.26 - p.height = 1.26 - p.vRes = 3 - p.hRes = 3 - p.origin = (0,0,0) - p.basis = 'xy' - p.level = -1 - - ids = openmc.capi.plot.id_map(p) - print(ids) + ids = openmc.capi.plot.id_map(s) assert np.array_equal(expected_ids, ids) From fbd0e5e4c52f42bb8d30942f6f2a87ae839c0340 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 7 Mar 2019 18:17:20 -0600 Subject: [PATCH 042/165] PEP8 adherence --- openmc/capi/plot.py | 22 +++++++++++++--------- tests/unit_tests/test_capi.py | 8 ++++---- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 2227435ed..c66ab076e 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -6,6 +6,7 @@ from .error import _error_handler import numpy as np + class _Position(Structure): """Definition of an xyz location in space with underlying c-types @@ -179,7 +180,8 @@ class _Slice(Structure): self.basis_ = basis return - raise ValueError("{} of type {} is an invalid plot basis".format(basis, type(basis))) + raise ValueError("{} of type {} is an" + " invalid plot basis".format(basis, type(basis))) @hRes.setter def hRes(self, hRes): @@ -194,7 +196,7 @@ class _Slice(Structure): self.level_ = level def __repr__(self): - out_str = "-----\n" + out_str = "-----\n" out_str += "Plot:\n" out_str += "-----\n" out_str += "Origin: {}\n".format(self.origin) @@ -210,19 +212,20 @@ class _Slice(Structure): return self.__repr__() -_dll.openmc_id_map.argtypes= [POINTER(_Slice),POINTER(c_int32)] +_dll.openmc_id_map.argtypes = [POINTER(_Slice), POINTER(c_int32)] _dll.openmc_id_map.restype = c_int _dll.openmc_id_map.errcheck = _error_handler def id_map(slice_view): """ - Generate a 2-D map of (cell_id, material_id). Used for in-memory image generation. + Generate a 2-D map of (cell_id, material_id). Used for in-memory image + generation. Parameters ---------- - plot : An openmc.capi.plot._Slice object describing the slice of the model to - be generated + plot : An openmc.capi.plot._Slice object describing the slice of the model + to be generated Returns ------- @@ -230,7 +233,8 @@ def id_map(slice_view): of OpenMC property ids with dtype int32 """ - img_data = np.zeros((slice_view.vRes, slice_view.hRes, 2), dtype=np.dtype('int32')) - print("Calling openmc id map") - _dll.openmc_id_map(POINTER(_Slice)(slice_view), img_data.ctypes.data_as(POINTER(c_int32))) + img_data = np.zeros((slice_view.vRes, slice_view.hRes, 2), + dtype=np.dtype('int32')) + _dll.openmc_id_map(POINTER(_Slice)(slice_view), + img_data.ctypes.data_as(POINTER(c_int32))) return img_data diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 760022706..0919eb8d0 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -403,9 +403,9 @@ def test_load_nuclide(capi_init): def test_id_map(capi_init): - expected_ids = np.array([[(3,3), (2,2), (3,3)], - [(2,2), (1,1), (2,2)], - [(3,3), (2,2), (3,3)]], dtype = 'int32') + expected_ids = np.array([[(3, 3), (2, 2), (3, 3)], + [(2, 2), (1, 1), (2, 2)], + [(3, 3), (2, 2), (3, 3)]], dtype='int32') # create a plot object s = openmc.capi.plot._Slice() @@ -413,7 +413,7 @@ def test_id_map(capi_init): s.height = 1.26 s.vRes = 3 s.hRes = 3 - s.origin = (0,0,0) + s.origin = (0.0, 0.0, 0.0) s.basis = 'xy' s.level = -1 From 1e7271d0b4792c86c9443a1d1ab3c8a713ca67ed Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 8 Mar 2019 09:23:33 -0600 Subject: [PATCH 043/165] Going back to PlotBase. Makes more sense as Plot inherits from it. --- include/openmc/plot.h | 4 ++-- openmc/capi/plot.py | 16 ++++++++-------- src/plot.cpp | 36 ++++++++++++++++++------------------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index a5fa4b065..c6ad951cb 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -73,7 +73,7 @@ enum class PlotColorBy { //=============================================================================== // Plot class //=============================================================================== -struct Slice { +struct PlotBase { // Members Position origin_; //!< Plot origin in geometry Position width_; //!< Plot width in geometry @@ -82,7 +82,7 @@ struct Slice { int level_; //!< Plot universe level }; -class Plot : public Slice +class Plot : public PlotBase { public: diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index c66ab076e..d66c62746 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -64,8 +64,8 @@ class _Position(Structure): return "Position: ({}, {}, {})".format(self.x, self.y, self.z) -class _Slice(Structure): - """A structure defining a 2-D slice with underlying c-types +class _PlotBase(Structure): + """A structure defining a 2-D geometry slice with underlying c-types C-Type Attributes ----------------- @@ -212,20 +212,20 @@ class _Slice(Structure): return self.__repr__() -_dll.openmc_id_map.argtypes = [POINTER(_Slice), POINTER(c_int32)] +_dll.openmc_id_map.argtypes = [POINTER(_PlotBase), POINTER(c_int32)] _dll.openmc_id_map.restype = c_int _dll.openmc_id_map.errcheck = _error_handler -def id_map(slice_view): +def id_map(plot): """ Generate a 2-D map of (cell_id, material_id). Used for in-memory image generation. Parameters ---------- - plot : An openmc.capi.plot._Slice object describing the slice of the model - to be generated + plot : An openmc.capi.plot._PlotBase object describing the slice of the + model to be generated Returns ------- @@ -233,8 +233,8 @@ def id_map(slice_view): of OpenMC property ids with dtype int32 """ - img_data = np.zeros((slice_view.vRes, slice_view.hRes, 2), + img_data = np.zeros((plot.vRes, plot.hRes, 2), dtype=np.dtype('int32')) - _dll.openmc_id_map(POINTER(_Slice)(slice_view), + _dll.openmc_id_map(POINTER(_PlotBase)(plot), img_data.ctypes.data_as(POINTER(c_int32))) return img_data diff --git a/src/plot.cpp b/src/plot.cpp index b5b91adba..2dbf0b6f7 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -952,20 +952,20 @@ RGBColor random_color() { return {int(prn()*255), int(prn()*255), int(prn()*255)}; } -extern "C" int openmc_id_map(void* slice, int32_t* data_out) { +extern "C" int openmc_id_map(void* plot, int32_t* data_out) { - auto sl = reinterpret_cast(slice); - if (!sl) { + auto plt = reinterpret_cast(plot); + if (!plt) { set_errmsg("Invalid slice pointer passed to openmc_id_map"); return OPENMC_E_INVALID_ARGUMENT; } - size_t width = sl->pixels_[0]; - size_t height = sl->pixels_[1]; + size_t width = plt->pixels_[0]; + size_t height = plt->pixels_[1]; // get pixel size - double in_pixel = (sl->width_[0])/static_cast(width); - double out_pixel = (sl->width_[1])/static_cast(height); + double in_pixel = (plt->width_[0])/static_cast(width); + double out_pixel = (plt->width_[1])/static_cast(height); // size data array IDData data; @@ -974,27 +974,27 @@ extern "C" int openmc_id_map(void* slice, int32_t* data_out) { // setup basis indices and initial position centered on pixel int in_i, out_i; double xyz[3]; - switch(sl->basis_) { + switch(plt->basis_) { case PlotBasis::xy : in_i = 0; out_i = 1; - xyz[0] = sl->origin_[0] - sl->width_[0] / 2. + in_pixel / 2.; - xyz[1] = sl->origin_[1] + sl->width_[1] / 2. - out_pixel / 2.; - xyz[2] = sl->origin_[2]; + xyz[0] = plt->origin_[0] - plt->width_[0] / 2. + in_pixel / 2.; + xyz[1] = plt->origin_[1] + plt->width_[1] / 2. - out_pixel / 2.; + xyz[2] = plt->origin_[2]; break; case PlotBasis::xz : in_i = 0; out_i = 2; - xyz[0] = sl->origin_[0] - sl->width_[0] / 2. + in_pixel / 2.; - xyz[1] = sl->origin_[1]; - xyz[2] = sl->origin_[2] + sl->width_[1] / 2. - out_pixel / 2.; + xyz[0] = plt->origin_[0] - plt->width_[0] / 2. + in_pixel / 2.; + xyz[1] = plt->origin_[1]; + xyz[2] = plt->origin_[2] + plt->width_[1] / 2. - out_pixel / 2.; break; case PlotBasis::yz : in_i = 1; out_i = 2; - xyz[0] = sl->origin_[0]; - xyz[1] = sl->origin_[1] - sl->width_[0] / 2. + in_pixel / 2.; - xyz[2] = sl->origin_[2] + sl->width_[1] / 2. - out_pixel / 2.; + xyz[0] = plt->origin_[0]; + xyz[1] = plt->origin_[1] - plt->width_[0] / 2. + in_pixel / 2.; + xyz[2] = plt->origin_[2] + plt->width_[1] / 2. - out_pixel / 2.; break; } @@ -1007,7 +1007,7 @@ extern "C" int openmc_id_map(void* slice, int32_t* data_out) { p.r() = xyz; p.u() = dir; p.coord_[0].universe = model::root_universe; - int level = sl->level_; + int level = plt->level_; int j{}; #pragma omp for From bb862009ee0673f3ac6105362ecadc0b4d7ec5b5 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 8 Mar 2019 10:00:24 -0600 Subject: [PATCH 044/165] Updating plot name in unit tests --- tests/unit_tests/test_capi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 0919eb8d0..bc529f02f 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -408,7 +408,7 @@ def test_id_map(capi_init): [(3, 3), (2, 2), (3, 3)]], dtype='int32') # create a plot object - s = openmc.capi.plot._Slice() + s = openmc.capi.plot._PlotBase() s.width = 1.26 s.height = 1.26 s.vRes = 3 From 263f70642cd0ee8f3928b0b212f5882704ebe8c0 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 8 Mar 2019 10:50:11 -0600 Subject: [PATCH 045/165] Renaming ID data structure. --- include/openmc/plot.h | 2 +- src/plot.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index c6ad951cb..8a9e4e74d 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -52,7 +52,7 @@ struct RGBColor { }; typedef xt::xtensor ImageData; -typedef xt::xtensor IDData; +typedef xt::xtensor IdData; enum class PlotType { slice = 1, diff --git a/src/plot.cpp b/src/plot.cpp index 2dbf0b6f7..f4e1389e2 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -968,7 +968,7 @@ extern "C" int openmc_id_map(void* plot, int32_t* data_out) { double out_pixel = (plt->width_[1])/static_cast(height); // size data array - IDData data; + IdData data; data.resize({height, width, 2}); // setup basis indices and initial position centered on pixel From e7b3175da13cd76f7f2f42ad4b95425cd9525ce3 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 12 Mar 2019 11:39:04 -0500 Subject: [PATCH 046/165] Addressing @promano's comments. --- include/openmc/capi.h | 2 +- openmc/capi/plot.py | 96 +++++++++++------------------------ src/plot.cpp | 42 ++++++--------- tests/unit_tests/test_capi.py | 4 +- 4 files changed, 49 insertions(+), 95 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 07c6bc80e..ed58eaded 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -70,7 +70,7 @@ extern "C" { int openmc_next_batch(int* status); int openmc_nuclide_name(int index, const char** name); int openmc_plot_geometry(); - int openmc_id_map(void* slice, int32_t *data_out); + int openmc_id_map(const void* slice, int32_t *data_out); int openmc_reset(); int openmc_run(); void openmc_set_seed(int64_t new_seed); diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index d66c62746..4ed78e393 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -23,46 +23,11 @@ class _Position(Structure): ('y', c_double), ('z', c_double)] - def __init__(self, vals=None): - if vals: - x = vals[0] - y = vals[1] - z = vals[2] - else: - x = 0.0 - y = 0.0 - z = 0.0 - - @property - def x(self): - return self.x - - @property - def y(self): - return self.y - - @property - def z(self): - return self.z - - @x.setter - def x(self, x_val): - assert(isinstance(x_val, float)) - self.x = x_val - - @y.setter - def y(self, y_val): - assert(isinstance(y_val, float)) - self.y = y_val - - @z.setter - def z(self, z_val): - assert(isinstance(z_val, float)) - self.z = z_val + def __repr__(self): + return "({}, {}, {})".format(self.x, self.y, self.z) def __str__(self): - return "Position: ({}, {}, {})".format(self.x, self.y, self.z) - + return self.__repr__() class _PlotBase(Structure): """A structure defining a 2-D geometry slice with underlying c-types @@ -91,9 +56,9 @@ class _PlotBase(Structure): basis : string One of {'xy', 'xz', 'yz'} indicating the horizontal and vertical axes of the plot. - hRes : float + h_res : float The horizontal resolution of the plot in pixels - vRes : float + v_res : float The vertical resolution of the plot in pixels level : int The universe level for the plot (default: -1 -> all universes shown) @@ -132,11 +97,11 @@ class _PlotBase(Structure): raise ValueError("Plot basis {} is invalid".format(basis_)) @property - def hRes(self): + def h_res(self): return self.pixels_[0] @property - def vRes(self): + def v_res(self): return self.pixels_[1] @property @@ -183,30 +148,30 @@ class _PlotBase(Structure): raise ValueError("{} of type {} is an" " invalid plot basis".format(basis, type(basis))) - @hRes.setter - def hRes(self, hRes): - self.pixels_[0] = hRes + @h_res.setter + def h_res(self, h_res): + self.pixels_[0] = h_res - @vRes.setter - def vRes(self, vRes): - self.pixels_[1] = vRes + @v_res.setter + def v_res(self, v_res): + self.pixels_[1] = v_res @level.setter def level(self, level): self.level_ = level def __repr__(self): - out_str = "-----\n" - out_str += "Plot:\n" - out_str += "-----\n" - out_str += "Origin: {}\n".format(self.origin) - out_str += "Width: {}\n".format(self.width) - out_str += "Height: {}\n".format(self.height) - out_str += "Basis: {}\n".format(self.basis) - out_str += "HRes: {}\n".format(self.hRes) - out_str += "VRes: {}\n".format(self.vRes) - out_str += "Level: {}\n".format(self.level) - return out_str + out_str = ["-----", + "Plot:", + "-----", + "Origin: {}".format(self.origin), + "Width: {}".format(self.width), + "Height: {}".format(self.height), + "Basis: {}".format(self.basis), + "HRes: {}".format(self.h_res), + "VRes: {}".format(self.v_res), + "Level: {}".format(self.level)] + return '\n'.join(output) def __str__(self): return self.__repr__() @@ -220,20 +185,21 @@ _dll.openmc_id_map.errcheck = _error_handler def id_map(plot): """ Generate a 2-D map of (cell_id, material_id). Used for in-memory image - generation. + generation. Parameters ---------- - plot : An openmc.capi.plot._PlotBase object describing the slice of the - model to be generated + plot : An openmc.capi.plot._PlotBase + Object describing the slice of the model to be generated Returns ------- - id_map : a NumPy array with shape (vertical pixels, horizontal pixels, 2) - of OpenMC property ids with dtype int32 + id_map : numpy.ndarray + A NumPy array with shape (vertical pixels, horizontal pixels, 2) of + OpenMC property ids with dtype int32 """ - img_data = np.zeros((plot.vRes, plot.hRes, 2), + img_data = np.zeros((plot.v_res, plot.h_res, 2), dtype=np.dtype('int32')) _dll.openmc_id_map(POINTER(_PlotBase)(plot), img_data.ctypes.data_as(POINTER(c_int32))) diff --git a/src/plot.cpp b/src/plot.cpp index f4e1389e2..281d878a7 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -619,8 +619,8 @@ Plot::set_mask(pugi::xml_node plot_node) } Plot::Plot(pugi::xml_node plot_node) + : index_meshlines_mesh_{-1} { - index_meshlines_mesh_ = -1; set_id(plot_node); set_type(plot_node); set_output_path(plot_node); @@ -952,9 +952,9 @@ RGBColor random_color() { return {int(prn()*255), int(prn()*255), int(prn()*255)}; } -extern "C" int openmc_id_map(void* plot, int32_t* data_out) { +extern "C" int openmc_id_map(const void* plot, int32_t* data_out) { - auto plt = reinterpret_cast(plot); + auto plt = reinterpret_cast(plot); if (!plt) { set_errmsg("Invalid slice pointer passed to openmc_id_map"); return OPENMC_E_INVALID_ARGUMENT; @@ -968,38 +968,32 @@ extern "C" int openmc_id_map(void* plot, int32_t* data_out) { double out_pixel = (plt->width_[1])/static_cast(height); // size data array - IdData data; - data.resize({height, width, 2}); + IdData data({height, width, 2}, NOT_FOUND); // setup basis indices and initial position centered on pixel int in_i, out_i; - double xyz[3]; + Position xyz = plt->origin_; switch(plt->basis_) { case PlotBasis::xy : in_i = 0; out_i = 1; - xyz[0] = plt->origin_[0] - plt->width_[0] / 2. + in_pixel / 2.; - xyz[1] = plt->origin_[1] + plt->width_[1] / 2. - out_pixel / 2.; - xyz[2] = plt->origin_[2]; break; case PlotBasis::xz : in_i = 0; out_i = 2; - xyz[0] = plt->origin_[0] - plt->width_[0] / 2. + in_pixel / 2.; - xyz[1] = plt->origin_[1]; - xyz[2] = plt->origin_[2] + plt->width_[1] / 2. - out_pixel / 2.; break; case PlotBasis::yz : in_i = 1; out_i = 2; - xyz[0] = plt->origin_[0]; - xyz[1] = plt->origin_[1] - plt->width_[0] / 2. + in_pixel / 2.; - xyz[2] = plt->origin_[2] + plt->width_[1] / 2. - out_pixel / 2.; break; } + // set initial position + xyz[in_i] = plt->origin_[in_i] - plt->width_[0] / 2. + in_pixel / 2.; + xyz[out_i] = plt->origin_[out_i] + plt->width_[1] / 2. - out_pixel / 2.; + // arbitrary direction - double dir[3] = {0.5, 0.5, 0.5}; + Direction dir = {0.5, 0.5, 0.5}; #pragma omp parallel { @@ -1010,7 +1004,7 @@ extern "C" int openmc_id_map(void* plot, int32_t* data_out) { int level = plt->level_; int j{}; -#pragma omp for + #pragma omp for for (int y = 0; y < height; y++) { p.r()[out_i] = xyz[out_i] - out_pixel * y; for (int x = 0; x < width; x++) { @@ -1020,15 +1014,10 @@ extern "C" int openmc_id_map(void* plot, int32_t* data_out) { bool found_cell = find_cell(&p, 0); j = p.n_coord_ - 1; if (level >=0) {j = level + 1;} - if (!found_cell) { - data(y,x,0) = NOT_FOUND; - data(y,x,1) = NOT_FOUND; - } else { - Cell *c = model::cells[p.coord_[j].cell].get(); + if (found_cell) { + Cell* c = model::cells[p.coord_[j].cell].get(); data(y,x,0) = c->id_; - if (c->type_ == FILL_UNIVERSE || p.material_ == MATERIAL_VOID) { - data(y,x,1) = NOT_FOUND; - } else { + if (c->type_ != FILL_UNIVERSE && p.material_ != MATERIAL_VOID) { data(y,x,1) = model::materials[p.material_]->id_; } } @@ -1037,8 +1026,7 @@ extern "C" int openmc_id_map(void* plot, int32_t* data_out) { } // omp parallel // write id data to array - size_t i = 0; - for (auto v : data) { data_out[i++] = v; } + std::copy(data.begin(), data.end(), data_out); return 0; } diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index bc529f02f..97d18531b 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -411,8 +411,8 @@ def test_id_map(capi_init): s = openmc.capi.plot._PlotBase() s.width = 1.26 s.height = 1.26 - s.vRes = 3 - s.hRes = 3 + s.v_res = 3 + s.h_res = 3 s.origin = (0.0, 0.0, 0.0) s.basis = 'xy' s.level = -1 From 9cfd7dee35f12115747bf34a9f43d47b6fbbe231 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 12 Mar 2019 11:58:58 -0500 Subject: [PATCH 047/165] Make sure Particle::Bank::particle member gets written in HDF5 --- openmc/capi/core.py | 3 ++- src/state_point.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/openmc/capi/core.py b/openmc/capi/core.py index 922877c8e..ad4f77dff 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -17,7 +17,8 @@ class _Bank(Structure): ('u', c_double*3), ('E', c_double), ('wgt', c_double), - ('delayed_group', c_int)] + ('delayed_group', c_int), + ('particle', c_int)] # Define input type for numpy arrays that will be passed into C++ functions diff --git a/src/state_point.cpp b/src/state_point.cpp index ab1473403..d657316f9 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -480,6 +480,7 @@ hid_t h5banktype() { H5Tinsert(banktype, "E", HOFFSET(Particle::Bank, E), H5T_NATIVE_DOUBLE); H5Tinsert(banktype, "wgt", HOFFSET(Particle::Bank, wgt), H5T_NATIVE_DOUBLE); H5Tinsert(banktype, "delayed_group", HOFFSET(Particle::Bank, delayed_group), H5T_NATIVE_INT); + H5Tinsert(banktype, "particle", HOFFSET(Particle::Bank, particle), H5T_NATIVE_INT); H5Tclose(postype); return banktype; From 2ab24d85cd7bf0293539be54c5ae41aade9f76b7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 13 Mar 2019 06:15:22 -0500 Subject: [PATCH 048/165] Fix extraction of heating number from ACE file --- openmc/data/neutron.py | 2 +- tests/regression_tests/tallies/results_true.dat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 670144ec1..bcb830aa0 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -622,7 +622,7 @@ class IncidentNeutron(EqualityMixin): data.energy[strT] = energy total_xs = ace.xss[i + n_energy : i + 2*n_energy] absorption_xs = ace.xss[i + 2*n_energy : i + 3*n_energy] - heating_number = ace.xss[i + 3*n_energy : i + 4*n_energy]*EV_PER_MEV + heating_number = ace.xss[i + 4*n_energy : i + 5*n_energy]*EV_PER_MEV # Create redundant reactions (total, absorption, and heating) total = Reaction(1) diff --git a/tests/regression_tests/tallies/results_true.dat b/tests/regression_tests/tallies/results_true.dat index 9830ff872..945e20fc6 100644 --- a/tests/regression_tests/tallies/results_true.dat +++ b/tests/regression_tests/tallies/results_true.dat @@ -1 +1 @@ -de773a799f84348241ebd65bf7beae8114861d8674b652bfd443d578c146a7d37ca38f2efc5d05124fdbb1cf12829907768351e6b2d6b5f4bd2c121417757507 \ No newline at end of file +cc3993048a54cb162a3224d69c5734df14e17a4c8784a9b8781537a5a5ecb3d9b8145c3b0e95957e67a68dc098e8ce1bc6c61d39e9125d0d0327a659f4b49808 \ No newline at end of file From 86c33fa7cb85c5c8ff93af93ae30e33c2b1fd842 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 13 Mar 2019 06:46:33 -0500 Subject: [PATCH 049/165] Fix build warnings --- include/openmc/lattice.h | 3 +-- src/physics.cpp | 10 ++++++++-- src/tallies/filter_sph_harm.cpp | 3 ++- src/tallies/filter_zernike.cpp | 3 ++- src/tallies/trigger.cpp | 7 ++++++- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/include/openmc/lattice.h b/include/openmc/lattice.h index 9c8b8af68..25ab4c034 100644 --- a/include/openmc/lattice.h +++ b/include/openmc/lattice.h @@ -152,8 +152,7 @@ public: int indx_; //!< An index to a Lattice universes or offsets array. LatticeIter(Lattice &lat, int indx) - : lat_(lat), - indx_(indx) + : indx_(indx), lat_(lat) {} bool operator==(const LatticeIter &rhs) {return (indx_ == rhs.indx_);} diff --git a/src/physics.cpp b/src/physics.cpp index 85b6e2417..858aae8f4 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -267,7 +267,7 @@ void sample_photon_reaction(Particle* p) double phi = 2.0*PI*prn(); double E_electron = (alpha - alpha_out)*MASS_ELECTRON_EV - e_b; int electron = static_cast(Particle::Type::electron); - if (E_electron >= settings::energy_cutoff[electron]) { + if (E_electron >= settings::energy_cutoff[electron]) { double mu_electron = (alpha - alpha_out*mu) / std::sqrt(alpha*alpha + alpha_out*alpha_out - 2.0*alpha*alpha_out*mu); Direction u = rotate_angle(p->u(), mu_electron, &phi); @@ -504,6 +504,9 @@ Reaction* sample_fission(int i_nuclide, double E) // Create fission bank sites if fission occurs if (prob > cutoff) return rx; } + + // If we reached here, no reaction was sampled + throw std::runtime_error{"No fission reaction was sampled for " + nuc->name_}; } void sample_photon_product(int i_nuclide, double E, int* i_rx, int* i_product) @@ -901,8 +904,11 @@ Direction sample_target_velocity(const Nuclide* nuc, double E, Direction u, } } } - } // case RVS, DBRC + } // case RVS, DBRC } // switch (sampling_method) + + throw std::runtime_error{"Unable to sample target velocity for " + "elastic scattering."}; } Direction diff --git a/src/tallies/filter_sph_harm.cpp b/src/tallies/filter_sph_harm.cpp index 9aae06bee..1e97e64c1 100644 --- a/src/tallies/filter_sph_harm.cpp +++ b/src/tallies/filter_sph_harm.cpp @@ -80,9 +80,10 @@ SphericalHarmonicsFilter::text_label(int bin) const if (bin < (n + 1) * (n + 1)) { int m = (bin - n*n) - n; out << "Spherical harmonic expansion, Y" << n << "," << m; - return out.str(); + break; } } + return out.str(); } //============================================================================== diff --git a/src/tallies/filter_zernike.cpp b/src/tallies/filter_zernike.cpp index c4e620c76..9f66a68f9 100644 --- a/src/tallies/filter_zernike.cpp +++ b/src/tallies/filter_zernike.cpp @@ -65,9 +65,10 @@ ZernikeFilter::text_label(int bin) const int first = last - (n + 1); int m = -n + (bin - first) * 2; out << "Zernike expansion, Z" << n << "," << m; - return out.str(); + break; } } + return out.str(); } void diff --git a/src/tallies/trigger.cpp b/src/tallies/trigger.cpp index 2f7f36920..c1b0a9364 100644 --- a/src/tallies/trigger.cpp +++ b/src/tallies/trigger.cpp @@ -83,6 +83,9 @@ check_tally_triggers(double& ratio, int& tally_id, int& score) case TriggerMetric::relative_error: uncertainty = rel_err; break; + case TriggerMetric::not_active: + uncertainty = 0.0; + break; } // Compute the uncertainty / threshold ratio. @@ -109,7 +112,6 @@ double check_keff_trigger() { if (settings::run_mode != RUN_MODE_EIGENVALUE) return 0.; - if (settings::keff_trigger.metric == TriggerMetric::not_active) return 0.; double k_combined[2]; int err = openmc_get_keff(k_combined); @@ -124,6 +126,9 @@ check_keff_trigger() break; case TriggerMetric::relative_error: uncertainty = k_combined[1] / k_combined[0]; + break; + case TriggerMetric::not_active: + break; } double ratio = uncertainty / settings::keff_trigger.threshold; From dcff11a917b61d67aec6d66ee3f424fdc43a246f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 13 Mar 2019 11:02:38 -0500 Subject: [PATCH 050/165] Make HDF5 includes and MAX_COORD transitive (since they are needed in header files) --- CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cb92be848..f943d0969 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,13 +255,12 @@ set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc) target_include_directories(libopenmc - PUBLIC include - PRIVATE ${HDF5_INCLUDE_DIRS}) + PUBLIC include ${HDF5_INCLUDE_DIRS}) # Set compile flags target_compile_options(libopenmc PRIVATE ${cxxflags}) -target_compile_definitions(libopenmc PRIVATE -DMAX_COORD=${maxcoord}) +target_compile_definitions(libopenmc PUBLIC -DMAX_COORD=${maxcoord}) if (HDF5_IS_PARALLEL) target_compile_definitions(libopenmc PRIVATE -DPHDF5) endif() From 6c351bf7bc913851d66acd26eb6f4c304b2d2ead Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 13 Mar 2019 16:13:57 -0500 Subject: [PATCH 051/165] Make sure ACE heating number is multipled by total cross section --- openmc/data/neutron.py | 2 +- tests/regression_tests/tallies/results_true.dat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index bcb830aa0..2ff55700f 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -637,7 +637,7 @@ class IncidentNeutron(EqualityMixin): data.reactions[101] = absorption heating = Reaction(301) - heating.xs[strT] = Tabulated1D(energy, heating_number) + heating.xs[strT] = Tabulated1D(energy, heating_number*total_xs) heating.redundant = True data.reactions[301] = heating diff --git a/tests/regression_tests/tallies/results_true.dat b/tests/regression_tests/tallies/results_true.dat index 945e20fc6..de1a18eff 100644 --- a/tests/regression_tests/tallies/results_true.dat +++ b/tests/regression_tests/tallies/results_true.dat @@ -1 +1 @@ -cc3993048a54cb162a3224d69c5734df14e17a4c8784a9b8781537a5a5ecb3d9b8145c3b0e95957e67a68dc098e8ce1bc6c61d39e9125d0d0327a659f4b49808 \ No newline at end of file +c37e0468f1684f7810429332721762884f3cdf0429d38caa99500bbde04ad84cf1e1639adc46b6db44b28b6f31028ed029f85920c8164d77463b6d89336043a8 \ No newline at end of file From 14e46653017ff17e6af394f9f4f70b66d09dccdd Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 14 Mar 2019 11:02:19 -0500 Subject: [PATCH 052/165] Addressing more of @promano's comments. --- include/openmc/capi.h | 2 +- openmc/capi/plot.py | 18 +++------ src/plot.cpp | 90 ++++++++++++++++++++++--------------------- 3 files changed, 53 insertions(+), 57 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index ed58eaded..5d07edb21 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -70,7 +70,7 @@ extern "C" { int openmc_next_batch(int* status); int openmc_nuclide_name(int index, const char** name); int openmc_plot_geometry(); - int openmc_id_map(const void* slice, int32_t *data_out); + int openmc_id_map(const void* slice, int32_t* data_out); int openmc_reset(); int openmc_run(); void openmc_set_seed(int64_t new_seed); diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 4ed78e393..53639a396 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -26,8 +26,6 @@ class _Position(Structure): def __repr__(self): return "({}, {}, {})".format(self.x, self.y, self.z) - def __str__(self): - return self.__repr__() class _PlotBase(Structure): """A structure defining a 2-D geometry slice with underlying c-types @@ -74,16 +72,15 @@ class _PlotBase(Structure): @property def origin(self): - out = [self.origin_.x, self.origin_.y, self.origin_.z] - return [float(val) for val in out] + return self.origin_ @property def width(self): - return float(self.width_.x) + return self.width_.x @property def height(self): - return float(self.width_.y) + return self.width_.y @property def basis(self): @@ -94,7 +91,7 @@ class _PlotBase(Structure): elif self.basis_ == 3: return 'yz' - raise ValueError("Plot basis {} is invalid".format(basis_)) + raise ValueError("Plot basis {} is invalid".format(self.basis_)) @property def h_res(self): @@ -171,10 +168,7 @@ class _PlotBase(Structure): "HRes: {}".format(self.h_res), "VRes: {}".format(self.v_res), "Level: {}".format(self.level)] - return '\n'.join(output) - - def __str__(self): - return self.__repr__() + return '\n'.join(out_str) _dll.openmc_id_map.argtypes = [POINTER(_PlotBase), POINTER(c_int32)] @@ -189,7 +183,7 @@ def id_map(plot): Parameters ---------- - plot : An openmc.capi.plot._PlotBase + plot : openmc.capi.plot._PlotBase Object describing the slice of the model to be generated Returns diff --git a/src/plot.cpp b/src/plot.cpp index 281d878a7..53f6956c2 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -1,5 +1,6 @@ #include "openmc/plot.h" +#include #include #include @@ -133,26 +134,27 @@ void create_ppm(Plot pl) Direction u {0.5, 0.5, 0.5}; -#pragma omp parallel -{ - Particle p; - p.r() = r; - p.u() = u; - p.coord_[0].universe = model::root_universe; + #pragma omp parallel + { + Particle p; + p.r() = r; + p.u() = u; + p.coord_[0].universe = model::root_universe; -#pragma omp for - for (int y = 0; y < height; y++) { - p.r()[out_i] = r[out_i] - out_pixel * y; - for (int x = 0; x < width; x++) { - // local variables - RGBColor rgb; - int id; - p.r()[in_i] = r[in_i] + in_pixel * x; - position_rgb(p, pl, rgb, id); - data(x,y) = rgb; + #pragma omp for + for (int y = 0; y < height; y++) { + p.r()[out_i] = r[out_i] - out_pixel * y; + for (int x = 0; x < width; x++) { + // local variables + RGBColor rgb; + int id; + p.r()[in_i] = r[in_i] + in_pixel * x; + position_rgb(p, pl, rgb, id); + data(x,y) = rgb; + } } } -} + // draw mesh lines if present if (pl.index_meshlines_mesh_ >= 0) {draw_mesh_lines(pl, data);} @@ -995,35 +997,35 @@ extern "C" int openmc_id_map(const void* plot, int32_t* data_out) { // arbitrary direction Direction dir = {0.5, 0.5, 0.5}; -#pragma omp parallel -{ - Particle p; - p.r() = xyz; - p.u() = dir; - p.coord_[0].universe = model::root_universe; - int level = plt->level_; - int j{}; + #pragma omp parallel + { + Particle p; + p.r() = xyz; + p.u() = dir; + p.coord_[0].universe = model::root_universe; + int level = plt->level_; + int j{}; - #pragma omp for - for (int y = 0; y < height; y++) { - p.r()[out_i] = xyz[out_i] - out_pixel * y; - for (int x = 0; x < width; x++) { - p.r()[in_i] = xyz[in_i] + in_pixel * x; - p.n_coord_ = 1; - // local variables - bool found_cell = find_cell(&p, 0); - j = p.n_coord_ - 1; - if (level >=0) {j = level + 1;} - if (found_cell) { - Cell* c = model::cells[p.coord_[j].cell].get(); - data(y,x,0) = c->id_; - if (c->type_ != FILL_UNIVERSE && p.material_ != MATERIAL_VOID) { - data(y,x,1) = model::materials[p.material_]->id_; + #pragma omp for + for (int y = 0; y < height; y++) { + p.r()[out_i] = xyz[out_i] - out_pixel * y; + for (int x = 0; x < width; x++) { + p.r()[in_i] = xyz[in_i] + in_pixel * x; + p.n_coord_ = 1; + // local variables + bool found_cell = find_cell(&p, 0); + j = p.n_coord_ - 1; + if (level >=0) {j = level + 1;} + if (found_cell) { + Cell* c = model::cells[p.coord_[j].cell].get(); + data(y,x,0) = c->id_; + if (c->type_ != FILL_UNIVERSE && p.material_ != MATERIAL_VOID) { + data(y,x,1) = model::materials[p.material_]->id_; + } } - } - } // inner for - } // outer for - } // omp parallel + } // inner for + } // outer for + } // omp parallel // write id data to array std::copy(data.begin(), data.end(), data_out); From 66f7b559e82b61f867c446724684f6e1ff1c63ae Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 14 Mar 2019 12:15:20 -0400 Subject: [PATCH 053/165] Add XMAS 172 and SHEM 361 pre-defined group structures --- openmc/mgxs/__init__.py | 124 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 120 insertions(+), 4 deletions(-) diff --git a/openmc/mgxs/__init__.py b/openmc/mgxs/__init__.py index b3ce9438c..db5b61b09 100644 --- a/openmc/mgxs/__init__.py +++ b/openmc/mgxs/__init__.py @@ -6,12 +6,18 @@ from openmc.mgxs.mgxs import * from openmc.mgxs.mdgxs import * GROUP_STRUCTURES = {} -"""Dictionary of commonly used energy group structures, including "CASMO-X" (where X -is 2, 4, 8, 16, 25, 40 or 70) from the CASMO_ lattice physics code and other commonly -used activation_ energy group structures "VITAMIN-J-175", "TRIPOLI-315", "CCFE-709_" -and "UKAEA-1102_" +"""Dictionary of commonly used energy group structures: +- "CASMO-X" (where X is 2, 4, 8, 16, 25, 40 or 70) from the CASMO_ lattice +physics code +- "XMAS-172" designed for LWR analysis (Sartori 1990, Santamarina et al. 2004) +- "SHEM-361" designed for LWR analysis to eliminate self-shielding calculations +of thermal resonances (Hfaiedh et al. 2005, Santamarina 2007, Hebert et al. 2008) +- activation_ energy group structures "VITAMIN-J-175", "TRIPOLI-315", +"CCFE-709_" and "UKAEA-1102_" .. _CASMO: https://www.studsvik.com/SharepointFiles/CASMO-5%20Development%20and%20Applications.pdf +.. _XMAS: https://www-nds.iaea.org/wimsd/energy.htm +.. _SHEM-361: https://www.polymtl.ca/merlin/libraries.htm .. _activation: https://fispact.ukaea.uk/wiki/Keyword:GETXS .. _CCFE-709: https://fispact.ukaea.uk/wiki/CCFE-709_group_structure .. _UKAEA-1102: https://fispact.ukaea.uk/wiki/UKAEA-1102_group_structure @@ -46,6 +52,42 @@ GROUP_STRUCTURES['CASMO-70'] = np.array([ 3.6726e2, 9.069e2, 1.4251e3, 2.2395e3, 3.5191e3, 5.53e3, 9.118e3, 1.503e4, 2.478e4, 4.085e4, 6.734e4, 1.11e5, 1.83e5, 3.025e5, 5.e5, 8.21e5, 1.353e6, 2.231e6, 3.679e6, 6.0655e6, 2.e7]) +GROUP_STRUCTURES['XMAS-172'] = np.array([ + 1.00001e-05, 3.00000e-03, 5.00000e-03, 6.90000e-03, 1.00000e-02, + 1.50000e-02, 2.00000e-02, 2.50000e-02, 3.00000e-02, 3.50000e-02, + 4.20000e-02, 5.00000e-02, 5.80000e-02, 6.70000e-02, 7.70000e-02, + 8.00000e-02, 9.50000e-02, 1.00001e-01, 1.15000e-01, 1.34000e-01, + 1.40000e-01, 1.60000e-01, 1.80000e-01, 1.89000e-01, 2.20000e-01, + 2.48000e-01, 2.80000e-01, 3.00000e-01, 3.14500e-01, 3.20000e-01, + 3.50000e-01, 3.91000e-01, 4.00000e-01, 4.33000e-01, 4.85000e-01, + 5.00000e-01, 5.40000e-01, 6.25000e-01, 7.05000e-01, 7.80000e-01, + 7.90000e-01, 8.50000e-01, 8.60000e-01, 9.10000e-01, 9.30000e-01, + 9.50000e-01, 9.72000e-01, 9.86000e-01, 9.96000e-01, 1.02000e+00, + 1.03500e+00, 1.04500e+00, 1.07100e+00, 1.09700e+00, 1.11000e+00, + 1.12535e+00, 1.15000e+00, 1.17000e+00, 1.23500e+00, 1.30000e+00, + 1.33750e+00, 1.37000e+00, 1.44498e+00, 1.47500e+00, 1.50000e+00, + 1.59000e+00, 1.67000e+00, 1.75500e+00, 1.84000e+00, 1.93000e+00, + 2.02000e+00, 2.10000e+00, 2.13000e+00, 2.36000e+00, 2.55000e+00, + 2.60000e+00, 2.72000e+00, 2.76792e+00, 3.30000e+00, 3.38075e+00, + 4.00000e+00, 4.12925e+00, 5.04348e+00, 5.34643e+00, 6.16012e+00, + 7.52398e+00, 8.31529e+00, 9.18981e+00, 9.90555e+00, 1.12245e+01, + 1.37096e+01, 1.59283e+01, 1.94548e+01, 2.26033e+01, 2.49805e+01, + 2.76077e+01, 3.05113e+01, 3.37201e+01, 3.72665e+01, 4.01690e+01, + 4.55174e+01, 4.82516e+01, 5.15780e+01, 5.55951e+01, 6.79041e+01, + 7.56736e+01, 9.16609e+01, 1.36742e+02, 1.48625e+02, 2.03995e+02, + 3.04325e+02, 3.71703e+02, 4.53999e+02, 6.77287e+02, 7.48518e+02, + 9.14242e+02, 1.01039e+03, 1.23410e+03, 1.43382e+03, 1.50733e+03, + 2.03468e+03, 2.24867e+03, 3.35463e+03, 3.52662e+03, 5.00451e+03, + 5.53084e+03, 7.46586e+03, 9.11882e+03, 1.11378e+04, 1.50344e+04, + 1.66156e+04, 2.47875e+04, 2.73944e+04, 2.92830e+04, 3.69786e+04, + 4.08677e+04, 5.51656e+04, 6.73795e+04, 8.22975e+04, 1.11090e+05, + 1.22773e+05, 1.83156e+05, 2.47235e+05, 2.73237e+05, 3.01974e+05, + 4.07622e+05, 4.50492e+05, 4.97871e+05, 5.50232e+05, 6.08101e+05, + 8.20850e+05, 9.07180e+05, 1.00259e+06, 1.10803e+06, 1.22456e+06, + 1.35335e+06, 1.65299e+06, 2.01897e+06, 2.23130e+06, 2.46597e+06, + 3.01194e+06, 3.67879e+06, 4.49329e+06, 5.48812e+06, 6.06531e+06, + 6.70320e+06, 8.18731e+06, 1.00000e+07, 1.16183e+07, 1.38403e+07, + 1.49182e+07, 1.73325e+07, 1.96403e+07]) GROUP_STRUCTURES['VITAMIN-J-175'] = np.array([ 1.0000e-5, 1.0000e-1, 4.1399e-1, 5.3158e-1, 6.8256e-1, 8.7643e-1, 1.1253, 1.4450, 1.8554, 2.3824, 3.0590, @@ -123,6 +165,80 @@ GROUP_STRUCTURES['TRIPOLI-315,'] = np.array([ 7.788e6, 8.187e6, 8.607e6, 9.048e6, 9.512e6, 1.000e7, 1.051e7, 1.105e7, 1.162e7, 1.221e7, 1.284e7, 1.350e7, 1.384e7, 1.419e7, 1.455e7, 1.492e7, 1.568e7, 1.649e7, 1.691e7, 1.733e7, 1.964e7]) +GROUP_STRUCTURES['SHEM-361'] = np.array([ + 2.49990e-03, 4.55602e-03, 7.14526e-03, 1.04505e-02, 1.48300e-02, + 2.00104e-02, 2.49394e-02, 2.92989e-02, 3.43998e-02, 4.02999e-02, + 4.73019e-02, 5.54982e-02, 6.51999e-02, 7.64969e-02, 8.97968e-02, + 1.04298e-01, 1.19995e-01, 1.37999e-01, 1.61895e-01, 1.90005e-01, + 2.09610e-01, 2.31192e-01, 2.54997e-01, 2.79989e-01, 3.05012e-01, + 3.25008e-01, 3.52994e-01, 3.90001e-01, 4.31579e-01, 4.75017e-01, + 5.20011e-01, 5.54990e-01, 5.94993e-01, 6.24999e-01, 7.19999e-01, + 8.00371e-01, 8.80024e-01, 9.19978e-01, 9.44022e-01, 9.63960e-01, + 9.81959e-01, 9.96501e-01, 1.00904e+00, 1.02101e+00, 1.03499e+00, + 1.07799e+00, 1.09198e+00, 1.10395e+00, 1.11605e+00, 1.12997e+00, + 1.14797e+00, 1.16999e+00, 1.21397e+00, 1.25094e+00, 1.29304e+00, + 1.33095e+00, 1.38098e+00, 1.41001e+00, 1.44397e+00, 1.51998e+00, + 1.58803e+00, 1.66895e+00, 1.77997e+00, 1.90008e+00, 1.98992e+00, + 2.07010e+00, 2.15695e+00, 2.21709e+00, 2.27299e+00, 2.33006e+00, + 2.46994e+00, 2.55000e+00, 2.59009e+00, 2.62005e+00, 2.64004e+00, + 2.70012e+00, 2.71990e+00, 2.74092e+00, 2.77512e+00, 2.88405e+00, + 3.14211e+00, 3.54307e+00, 3.71209e+00, 3.88217e+00, 4.00000e+00, + 4.21983e+00, 4.30981e+00, 4.41980e+00, 4.76785e+00, 4.93323e+00, + 5.10997e+00, 5.21008e+00, 5.32011e+00, 5.38003e+00, 5.41025e+00, + 5.48817e+00, 5.53004e+00, 5.61979e+00, 5.72015e+00, 5.80021e+00, + 5.96014e+00, 6.05991e+00, 6.16011e+00, 6.28016e+00, 6.35978e+00, + 6.43206e+00, 6.48178e+00, 6.51492e+00, 6.53907e+00, 6.55609e+00, + 6.57184e+00, 6.58829e+00, 6.60611e+00, 6.63126e+00, 6.71668e+00, + 6.74225e+00, 6.75981e+00, 6.77605e+00, 6.79165e+00, 6.81070e+00, + 6.83526e+00, 6.87021e+00, 6.91778e+00, 6.99429e+00, 7.13987e+00, + 7.38015e+00, 7.60035e+00, 7.73994e+00, 7.83965e+00, 7.97008e+00, + 8.13027e+00, 8.30032e+00, 8.52407e+00, 8.67369e+00, 8.80038e+00, + 8.97995e+00, 9.14031e+00, 9.50002e+00, 1.05793e+01, 1.08038e+01, + 1.10529e+01, 1.12694e+01, 1.15894e+01, 1.17094e+01, 1.18153e+01, + 1.19795e+01, 1.21302e+01, 1.23086e+01, 1.24721e+01, 1.26000e+01, + 1.33297e+01, 1.35460e+01, 1.40496e+01, 1.42505e+01, 1.44702e+01, + 1.45952e+01, 1.47301e+01, 1.48662e+01, 1.57792e+01, 1.60498e+01, + 1.65501e+01, 1.68305e+01, 1.74457e+01, 1.75648e+01, 1.77590e+01, + 1.79591e+01, 1.90848e+01, 1.91997e+01, 1.93927e+01, 1.95974e+01, + 2.00734e+01, 2.02751e+01, 2.04175e+01, 2.05199e+01, 2.06021e+01, + 2.06847e+01, 2.07676e+01, 2.09763e+01, 2.10604e+01, 2.11448e+01, + 2.12296e+01, 2.13360e+01, 2.14859e+01, 2.17018e+01, 2.20011e+01, + 2.21557e+01, 2.23788e+01, 2.25356e+01, 2.46578e+01, 2.78852e+01, + 3.16930e+01, 3.30855e+01, 3.45392e+01, 3.56980e+01, 3.60568e+01, + 3.64191e+01, 3.68588e+01, 3.73038e+01, 3.77919e+01, 3.87874e+01, + 3.97295e+01, 4.12270e+01, 4.21441e+01, 4.31246e+01, 4.41721e+01, + 4.52904e+01, 4.62053e+01, 4.75173e+01, 4.92591e+01, 5.17847e+01, + 5.29895e+01, 5.40600e+01, 5.70595e+01, 5.99250e+01, 6.23083e+01, + 6.36306e+01, 6.45923e+01, 6.50460e+01, 6.55029e+01, 6.58312e+01, + 6.61612e+01, 6.64929e+01, 6.68261e+01, 6.90682e+01, 7.18869e+01, + 7.35595e+01, 7.63322e+01, 7.93679e+01, 8.39393e+01, 8.87741e+01, + 9.33256e+01, 9.73287e+01, 1.00594e+02, 1.01098e+02, 1.01605e+02, + 1.02115e+02, 1.03038e+02, 1.05646e+02, 1.10288e+02, 1.12854e+02, + 1.15480e+02, 1.16524e+02, 1.17577e+02, 1.20554e+02, 1.26229e+02, + 1.32701e+02, 1.39504e+02, 1.46657e+02, 1.54176e+02, 1.63056e+02, + 1.67519e+02, 1.75229e+02, 1.83295e+02, 1.84952e+02, 1.86251e+02, + 1.87559e+02, 1.88877e+02, 1.90204e+02, 1.93078e+02, 1.95996e+02, + 2.00958e+02, 2.12108e+02, 2.24325e+02, 2.35590e+02, 2.41796e+02, + 2.56748e+02, 2.68297e+02, 2.76468e+02, 2.84888e+02, 2.88327e+02, + 2.95922e+02, 3.19928e+02, 3.35323e+02, 3.53575e+02, 3.71703e+02, + 3.90760e+02, 4.19094e+02, 4.53999e+02, 5.01746e+02, 5.39204e+02, + 5.77146e+02, 5.92941e+02, 6.00099e+02, 6.12834e+02, 6.46837e+02, + 6.77287e+02, 7.48517e+02, 8.32218e+02, 9.09681e+02, 9.82494e+02, + 1.06432e+03, 1.13467e+03, 1.34358e+03, 1.58620e+03, 1.81183e+03, + 2.08410e+03, 2.39729e+03, 2.70024e+03, 2.99618e+03, 3.48107e+03, + 4.09735e+03, 5.00451e+03, 6.11252e+03, 7.46585e+03, 9.11881e+03, + 1.11377e+04, 1.36037e+04, 1.48997e+04, 1.62005e+04, 1.85847e+04, + 2.26994e+04, 2.49991e+04, 2.61001e+04, 2.73944e+04, 2.92810e+04, + 3.34596e+04, 3.69786e+04, 4.08677e+04, 4.99159e+04, 5.51656e+04, + 6.73794e+04, 8.22974e+04, 9.46645e+04, 1.15624e+05, 1.22773e+05, + 1.40000e+05, 1.64999e+05, 1.95008e+05, 2.30014e+05, 2.67826e+05, + 3.20646e+05, 3.83884e+05, 4.12501e+05, 4.56021e+05, 4.94002e+05, + 5.78443e+05, 7.06511e+05, 8.60006e+05, 9.51119e+05, 1.05115e+06, + 1.16205e+06, 1.28696e+06, 1.33694e+06, 1.40577e+06, 1.63654e+06, + 1.90139e+06, 2.23130e+06, 2.72531e+06, 3.32871e+06, 4.06569e+06, + 4.96585e+06, 6.06530e+06, 6.70319e+06, 7.40817e+06, 8.18730e+06, + 9.04836e+06, 9.99999e+06, 1.16183e+07, 1.38403e+07, 1.49182e+07, + 1.96403e+07]) GROUP_STRUCTURES['CCFE-709'] = np.array([ 1.e-5, 1.0471e-5, 1.0965e-5, 1.1482e-5, 1.2023e-5, 1.2589e-5, 1.3183e-5, 1.3804e-5, 1.4454e-5, 1.5136e-5, From af54f3512ea4440783369d30ce0c86a4fb2ef50f Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 14 Mar 2019 12:13:38 -0500 Subject: [PATCH 054/165] Adding getitem method to _Position. --- openmc/capi/plot.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 53639a396..92245dd74 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -23,6 +23,16 @@ class _Position(Structure): ('y', c_double), ('z', c_double)] + def __getitem__(self, key): + if key == 0: + return self.x + elif key == 1: + return self.y + elif key == 2: + return self.z + + raise ValueError("{} index is invalid for _Position".format(key)) + def __repr__(self): return "({}, {}, {})".format(self.x, self.y, self.z) From 25710ad88cbaf435d1224d14b0853f41948bf49e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 14 Mar 2019 16:13:08 -0500 Subject: [PATCH 055/165] Adding set method to _Position as well. --- openmc/capi/plot.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 92245dd74..55552194e 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -23,15 +23,25 @@ class _Position(Structure): ('y', c_double), ('z', c_double)] - def __getitem__(self, key): - if key == 0: + def __getitem__(self, idx): + if idx == 0: return self.x - elif key == 1: + elif idx == 1: return self.y - elif key == 2: + elif idx == 2: return self.z - raise ValueError("{} index is invalid for _Position".format(key)) + raise ValueError("{} index is invalid for _Position".format(idx)) + + def __setitem__(self, idx, val): + if idx == 0: + self.x = val + elif idx == 1: + self.y = val + elif idx == 2: + self.z = val + + raise ValueError("{} index is invalid for _Position".format(idx)) def __repr__(self): return "({}, {}, {})".format(self.x, self.y, self.z) From 7ad2c4137508e9b6cb53980742a7eeda894ec01c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 14 Mar 2019 16:22:03 -0500 Subject: [PATCH 056/165] Putting exception raise in if-else. --- openmc/capi/plot.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 55552194e..ac4a457b5 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -30,8 +30,8 @@ class _Position(Structure): return self.y elif idx == 2: return self.z - - raise ValueError("{} index is invalid for _Position".format(idx)) + else: + raise ValueError("{} index is invalid for _Position".format(idx)) def __setitem__(self, idx, val): if idx == 0: @@ -40,8 +40,8 @@ class _Position(Structure): self.y = val elif idx == 2: self.z = val - - raise ValueError("{} index is invalid for _Position".format(idx)) + else: + raise ValueError("{} index is invalid for _Position".format(idx)) def __repr__(self): return "({}, {}, {})".format(self.x, self.y, self.z) From 61ad86dba0882896317538ac01f60be87d94332c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 15 Mar 2019 09:31:59 -0500 Subject: [PATCH 057/165] Updating error raised and a sylte change. --- openmc/capi/plot.py | 4 ++-- src/plot.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index ac4a457b5..78fcef912 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -31,7 +31,7 @@ class _Position(Structure): elif idx == 2: return self.z else: - raise ValueError("{} index is invalid for _Position".format(idx)) + raise IndexError("{} index is invalid for _Position".format(key)) def __setitem__(self, idx, val): if idx == 0: @@ -41,7 +41,7 @@ class _Position(Structure): elif idx == 2: self.z = val else: - raise ValueError("{} index is invalid for _Position".format(idx)) + raise IndexError("{} index is invalid for _Position".format(idx)) def __repr__(self): return "({}, {}, {})".format(self.x, self.y, self.z) diff --git a/src/plot.cpp b/src/plot.cpp index 53f6956c2..18103a141 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -954,7 +954,8 @@ RGBColor random_color() { return {int(prn()*255), int(prn()*255), int(prn()*255)}; } -extern "C" int openmc_id_map(const void* plot, int32_t* data_out) { +extern "C" int openmc_id_map(const void* plot, int32_t* data_out) +{ auto plt = reinterpret_cast(plot); if (!plt) { From 13b9061cf388fce4cd3d5b4f134a09497120c7e0 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 14 Mar 2019 20:47:43 -0500 Subject: [PATCH 058/165] Using entity_by_index and correcting entries in surface map. --- src/cell.cpp | 8 ++++---- src/dagmc.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index d4712b9d1..2eec07d2a 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -601,7 +601,7 @@ std::pair DAGCell::distance(Position r, Direction u, int32_t on_surface) const { moab::ErrorCode rval; - moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); + moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, model::cell_map[id_] + 1); moab::EntityHandle hit_surf; double dist; double pnt[3] = {r.x, r.y, r.z}; @@ -621,7 +621,7 @@ DAGCell::distance(Position r, Direction u, int32_t on_surface) const bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const { moab::ErrorCode rval; - moab::EntityHandle vol = dagmc_ptr_->entity_by_id(3, id_); + moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, model::cell_map[id_] + 1); int result = 0; double pnt[3] = {r.x, r.y, r.z}; @@ -830,9 +830,9 @@ openmc_extend_cells(int32_t n, int32_t* index_start, int32_t* index_end) int32_t next_cell(DAGCell* cur_cell, DAGSurface* surf_xed) { moab::EntityHandle surf = - surf_xed->dagmc_ptr_->entity_by_id(2, surf_xed->id_); + surf_xed->dagmc_ptr_->entity_by_index(2, model::surface_map[surf_xed->id_] + 1); moab::EntityHandle vol = - cur_cell->dagmc_ptr_->entity_by_id(3, cur_cell->id_); + cur_cell->dagmc_ptr_->entity_by_index(3, model::cell_map[cur_cell->id_] + 1); moab::EntityHandle new_vol; cur_cell->dagmc_ptr_->next_vol(surf, vol, new_vol); diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 34027ce7c..54bf38ad9 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -303,7 +303,7 @@ void load_dagmc_geometry() // add to global array and map model::surfaces.emplace_back(s); - model::surface_map[s->id_] = s->id_; + model::surface_map[s->id_] = i; } return; From 23fc873a6962d93491ff403e48c5726144b600f4 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 15 Mar 2019 14:04:35 -0500 Subject: [PATCH 059/165] Using a normalized direction for plotting. --- src/plot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index 18103a141..729b2db48 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -132,7 +132,7 @@ void create_ppm(Plot pl) break; } - Direction u {0.5, 0.5, 0.5}; + Direction u {0.7071, 0.7071, 0.0}; #pragma omp parallel { @@ -837,7 +837,7 @@ void create_voxel(Plot pl) Position ll = pl.origin_ - pl.width_ / 2.; // allocate and initialize particle - Direction u {0.5, 0.5, 0.5}; + Direction u {0.7071, 0.7071, 0.0}; Particle p; p.r() = ll; p.u() = u; From 1df5e95f66254ef3fca85f6bf1cf3fc117d1e204 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 15 Mar 2019 15:52:00 -0500 Subject: [PATCH 060/165] Using a DAGSurface/Cell class attribute to track DAGMC indices and contain +1's. --- include/openmc/cell.h | 1 + include/openmc/surface.h | 2 ++ src/cell.cpp | 8 ++++---- src/dagmc.cpp | 6 ++++-- src/surface.cpp | 6 +++--- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index f436592cd..d4c220635 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -182,6 +182,7 @@ class DAGCell : public Cell public: moab::DagMC* dagmc_ptr_; DAGCell(); + int32_t dag_index_; bool contains(Position r, Direction u, int32_t on_surface) const; diff --git a/include/openmc/surface.h b/include/openmc/surface.h index e1acefa23..bebff35ee 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -131,6 +131,8 @@ class DAGSurface : public Surface public: moab::DagMC* dagmc_ptr_; DAGSurface(); + int32_t dag_index_; + double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; diff --git a/src/cell.cpp b/src/cell.cpp index 2eec07d2a..c7b92c829 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -601,7 +601,7 @@ std::pair DAGCell::distance(Position r, Direction u, int32_t on_surface) const { moab::ErrorCode rval; - moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, model::cell_map[id_] + 1); + moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_); moab::EntityHandle hit_surf; double dist; double pnt[3] = {r.x, r.y, r.z}; @@ -621,7 +621,7 @@ DAGCell::distance(Position r, Direction u, int32_t on_surface) const bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const { moab::ErrorCode rval; - moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, model::cell_map[id_] + 1); + moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_); int result = 0; double pnt[3] = {r.x, r.y, r.z}; @@ -830,9 +830,9 @@ openmc_extend_cells(int32_t n, int32_t* index_start, int32_t* index_end) int32_t next_cell(DAGCell* cur_cell, DAGSurface* surf_xed) { moab::EntityHandle surf = - surf_xed->dagmc_ptr_->entity_by_index(2, model::surface_map[surf_xed->id_] + 1); + surf_xed->dagmc_ptr_->entity_by_index(2, surf_xed->dag_index_); moab::EntityHandle vol = - cur_cell->dagmc_ptr_->entity_by_index(3, model::cell_map[cur_cell->id_] + 1); + cur_cell->dagmc_ptr_->entity_by_index(3, cur_cell->dag_index_); moab::EntityHandle new_vol; cur_cell->dagmc_ptr_->next_vol(surf, vol, new_vol); diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 54bf38ad9..1ccc72595 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -138,7 +138,8 @@ void load_dagmc_geometry() // set cell ids using global IDs DAGCell* c = new DAGCell(); - c->id_ = model::DAG->id_by_index(3, i+1); + c->dag_index_ = i+1; + c->id_ = model::DAG->id_by_index(3, c->dag_index_); c->dagmc_ptr_ = model::DAG; c->universe_ = dagmc_univ_id; // set to zero for now c->fill_ = C_NONE; // no fill, single universe @@ -261,7 +262,8 @@ void load_dagmc_geometry() // set cell ids using global IDs DAGSurface* s = new DAGSurface(); - s->id_ = model::DAG->id_by_index(2, i+1); + s->dag_index_ = i+1; + s->id_ = model::DAG->id_by_index(2, s->dag_index_); s->dagmc_ptr_ = model::DAG; // set BCs diff --git a/src/surface.cpp b/src/surface.cpp index bf0315698..f30b44431 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -241,7 +241,7 @@ double DAGSurface::distance(Position r, Direction u, bool coincident) const { moab::ErrorCode rval; - moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); + moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); moab::EntityHandle hit_surf; double dist; double pnt[3] = {r.x, r.y, r.z}; @@ -256,7 +256,7 @@ Direction DAGSurface::normal(Position r) const { moab::ErrorCode rval; Direction u; - moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); + moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); double pnt[3] = {r.x, r.y, r.z}; double dir[3] = {u.x, u.y, u.z}; rval = dagmc_ptr_->get_angle(surf, pnt, dir); @@ -267,7 +267,7 @@ Direction DAGSurface::normal(Position r) const BoundingBox DAGSurface::bounding_box() const { moab::ErrorCode rval; - moab::EntityHandle surf = dagmc_ptr_->entity_by_id(2, id_); + moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); double min[3], max[3]; rval = dagmc_ptr_->getobb(surf, min, max); MB_CHK_ERR_CONT(rval); From 5135353db57129f1d4860b3fd161c62fe06aed2e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 16 Mar 2019 08:03:33 -0500 Subject: [PATCH 061/165] Allowing dagmc materials to be set by name. --- src/dagmc.cpp | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 34027ce7c..a37cf630d 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -4,10 +4,11 @@ #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/file_utils.h" +#include "openmc/geometry.h" #include "openmc/geometry_aux.h" +#include "openmc/material.h" #include "openmc/string_utils.h" #include "openmc/settings.h" -#include "openmc/geometry.h" #ifdef DAGMC @@ -88,6 +89,34 @@ bool write_uwuw_materials_xml() { return found_uwuw_mats; } +void legacy_assign_material(const std::string& mat_string, + DAGCell* c) +{ + bool mat_found = false; + // attempt to find a material with a matching name + for (const auto& m : model::materials) { + if (mat_string == m->name_) { + // assign the material with that name + if (!mat_found) { + mat_found = true; + c->material_.push_back(m->id_); + // report error if more than one material is found + } else { + std::stringstream err_msg; + err_msg << "More than one material found with name " << mat_string + << ". Please ensure materials have unique names if using this" + << " property to assign materials."; + fatal_error(err_msg); + } + } + } + + // if no material was set using a name, assign by id + if (!mat_found) { + c->material_.emplace_back(std::stoi(mat_string)); + } +} + void load_dagmc_geometry() { if (!model::DAG) { @@ -187,7 +216,7 @@ void load_dagmc_geometry() size_t _comp_pos = mat_value.find(_comp); if (_comp_pos != std::string::npos) { mat_value.erase(_comp_pos, _comp.length()); } // assign IC material by id - c->material_.push_back(std::stoi(mat_value)); + legacy_assign_material(mat_value, c); } } else { // if no material is found, the implicit complement is void @@ -234,9 +263,7 @@ void load_dagmc_geometry() fatal_error(err_msg); } } else { - // if not using UWUW materials, we'll find this material - // later in the materials.xml - c->material_.push_back(std::stoi(mat_value)); + legacy_assign_material(mat_value, c); } } } From 1f55d331b87042bd579e7c8271c63c19340ad420 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 16 Mar 2019 08:08:23 -0500 Subject: [PATCH 062/165] Setting fuel material by name in the dagmc test. --- tests/regression_tests/dagmc/dagmc.h5m | Bin 1233372 -> 1233372 bytes tests/regression_tests/dagmc/inputs_true.dat | 4 ++-- tests/regression_tests/dagmc/test.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/regression_tests/dagmc/dagmc.h5m b/tests/regression_tests/dagmc/dagmc.h5m index a55e061dcac9f0bf284ecd0741d62c1bafb6a77c..c90b6d674d9b016aba5b8614d952d90205c355f2 100644 GIT binary patch delta 487 zcmcb!*!#|6?+tHcm_L8%nfzYnk-V|Kp_#s+B@+V#a6oAT3o8RND^ttKA7n)s4L7sO zxeI`_Z1&fS+2S6o>{>Rme@SM7OHf8-B&iS^!(Z*le61A!EF1&g_|SVuRxUQ_rgr=iv=s) zJbwyI^Hf)eX89$rCqJ5_1lFv-^zh_Ub0K!#cbvF+#k>-TLGnwW+Vq#gOkDO9qW?b7 z`xn+iybrXz`Nq2T8|xT>m0@ByXf|V5V$dJv{l;T!@|b9Vc#HF|Pz-ko*#;HvOeA6PG=O=)Vv2 z{)M#=?*lDwzOk - + - + diff --git a/tests/regression_tests/dagmc/test.py b/tests/regression_tests/dagmc/test.py index 6c9be63bf..b6f2f55e2 100644 --- a/tests/regression_tests/dagmc/test.py +++ b/tests/regression_tests/dagmc/test.py @@ -30,12 +30,12 @@ def test_dagmc(): model.tallies = [tally] # materials - u235 = openmc.Material() + u235 = openmc.Material(name="fuel") u235.add_nuclide('U235', 1.0, 'ao') u235.set_density('g/cc', 11) u235.id = 40 - water = openmc.Material() + water = openmc.Material(name="water") water.add_nuclide('H1', 2.0, 'ao') water.add_nuclide('O16', 1.0, 'ao') water.set_density('g/cc', 1.0) From 163304773e873abee122838be8c67179c7682d2d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 16 Mar 2019 10:14:07 -0500 Subject: [PATCH 063/165] Adding messages for verbose output. --- src/dagmc.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index a37cf630d..435cb4218 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -92,13 +92,13 @@ bool write_uwuw_materials_xml() { void legacy_assign_material(const std::string& mat_string, DAGCell* c) { - bool mat_found = false; + bool mat_found_by_name = false; // attempt to find a material with a matching name for (const auto& m : model::materials) { if (mat_string == m->name_) { // assign the material with that name - if (!mat_found) { - mat_found = true; + if (!mat_found_by_name) { + mat_found_by_name = true; c->material_.push_back(m->id_); // report error if more than one material is found } else { @@ -112,9 +112,21 @@ void legacy_assign_material(const std::string& mat_string, } // if no material was set using a name, assign by id - if (!mat_found) { + if (!mat_found_by_name) { c->material_.emplace_back(std::stoi(mat_string)); } + + if (settings::verbosity >= 10) { + Material* m = model::materials[model::material_map[c->material_[0]]].get(); + std::stringstream msg; + msg << "DAGMC material " << mat_string << " was assigned"; + if (mat_found_by_name) { + msg << " using material name: " << m->name_; + } else { + msg << " using material id: " << m->id_; + } + write_message(msg.str(), 10); + } } void load_dagmc_geometry() From f6b251145f18d4e28542e4d6f3f7f4c94a9ab35f Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 16 Mar 2019 12:48:47 -0500 Subject: [PATCH 064/165] Placing id read in try-catch. --- src/dagmc.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 435cb4218..456f9f279 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -113,7 +113,15 @@ void legacy_assign_material(const std::string& mat_string, // if no material was set using a name, assign by id if (!mat_found_by_name) { - c->material_.emplace_back(std::stoi(mat_string)); + try { + auto id = std::stoi(mat_string); + c->material_.emplace_back(id); + } catch (...) { + std::stringstream err_msg; + err_msg << "No material " << mat_string + << " found for volume (cell) " << c->id_; + fatal_error(err_msg); + } } if (settings::verbosity >= 10) { From 3de82b743823c96f15e8cad7ccf602eb530bbde5 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 17 Mar 2019 14:32:36 -0400 Subject: [PATCH 065/165] Compute mesh intersections rather than searching --- include/openmc/mesh.h | 35 +++-- src/mesh.cpp | 333 +++++++++++++++++++++++------------------- 2 files changed, 204 insertions(+), 164 deletions(-) diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index b13f9568a..3fc7db781 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -43,7 +43,7 @@ public: // Methods //! Determine which bins were crossed by a particle - //! + // //! \param[in] p Particle to check //! \param[out] bins Bins that were crossed //! \param[out] lengths Fraction of tracklength in each bin @@ -51,50 +51,51 @@ public: std::vector& lengths) const; //! Determine which surface bins were crossed by a particle - //! + // //! \param[in] p Particle to check //! \param[out] bins Surface bins that were crossed void surface_bins_crossed(const Particle* p, std::vector& bins) const; //! Get bin at a given position in space - //! + // //! \param[in] r Position to get bin for //! \return Mesh bin int get_bin(Position r) const; //! Get bin given mesh indices - //! + // //! \param[in] Array of mesh indices //! \return Mesh bin int get_bin_from_indices(const int* ijk) const; //! Get mesh indices given a position - //! + // //! \param[in] r Position to get indices for //! \param[out] ijk Array of mesh indices //! \param[out] in_mesh Whether position is in mesh void get_indices(Position r, int* ijk, bool* in_mesh) const; //! Get mesh indices corresponding to a mesh bin - //! + // //! \param[in] bin Mesh bin //! \param[out] ijk Mesh indices void get_indices_from_bin(int bin, int* ijk) const; - //! Check if a line connected by two points intersects the mesh - //! - //! \param[in] r0 Starting position + //! Check where a line segment intersects the mesh and if it intersects at all + // + //! \param[in,out] r0 In: starting position, out: intersection point //! \param[in] r1 Ending position - //! \return Whether line connecting r0 and r1 intersects mesh - bool intersects(Position r0, Position r1) const; + //! \param[out] ijk Indices of the mesh bin containing the intersection point + //! \return Whether the line segment connecting r0 and r1 intersects mesh + bool intersects(Position& r0, Position r1, int* ijk) const; //! Write mesh data to an HDF5 group - //! + // //! \param[in] group HDF5 group void to_hdf5(hid_t group) const; //! Count number of bank sites in each mesh bin / energy bin - //! + // //! \param[in] n Number of bank sites //! \param[in] bank Array of bank sites //! \param[in] n_energy Number of energies @@ -113,9 +114,9 @@ public: xt::xarray width_; //!< Width of each mesh element private: - bool intersects_1d(Position r0, Position r1) const; - bool intersects_2d(Position r0, Position r1) const; - bool intersects_3d(Position r0, Position r1) const; + bool intersects_1d(Position& r0, Position r1, int* ijk) const; + bool intersects_2d(Position& r0, Position r1, int* ijk) const; + bool intersects_3d(Position& r0, Position r1, int* ijk) const; }; //============================================================================== @@ -123,10 +124,12 @@ private: //============================================================================== //! Read meshes from either settings/tallies +// //! \param[in] root XML node void read_meshes(pugi::xml_node root); //! Write mesh data to an HDF5 group +// //! \param[in] group HDF5 group void meshes_to_hdf5(hid_t group); diff --git a/src/mesh.cpp b/src/mesh.cpp index 97ec81ba2..b75a0aad1 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -36,6 +36,32 @@ std::unordered_map mesh_map; } // namespace model +//============================================================================== +// Helper functions +//============================================================================== + +//! Update an intersection point if the given candidate is closer. +// +//! The first 6 arguments are coordinates for the starting point of a particle +//! and its intersection with a mesh surface. If the distance between these +//! two points is shorter than the given `min_distance`, then the `r` argument +//! will be updated to match the intersection point, and `min_distance` will +//! also be updated. + +inline bool check_intersection_point(double x1, double x0, double y1, + double y0, double z1, double z0, Position& r, double& min_distance) +{ + double dist = std::pow(x1-x0, 2) + std::pow(y1-y0, 2) + std::pow(z1-z0, 2); + if (dist < min_distance) { + r.x = x1; + r.y = y1; + r.z = z1; + min_distance = dist; + return true; + } + return false; +} + //============================================================================== // RegularMesh implementation //============================================================================== @@ -167,14 +193,14 @@ int RegularMesh::get_bin(Position r) const int RegularMesh::get_bin_from_indices(const int* ijk) const { switch (n_dimension_) { - case 1: - return ijk[0] - 1; - case 2: - return (ijk[1] - 1)*shape_[0] + ijk[0] - 1; - case 3: - return ((ijk[2] - 1)*shape_[1] + (ijk[1] - 1))*shape_[0] + ijk[0] - 1; - default: - throw std::runtime_error{"Invalid number of mesh dimensions"}; + case 1: + return ijk[0] - 1; + case 2: + return (ijk[1] - 1)*shape_[0] + ijk[0] - 1; + case 3: + return ((ijk[2] - 1)*shape_[1] + (ijk[1] - 1))*shape_[0] + ijk[0] - 1; + default: + throw std::runtime_error{"Invalid number of mesh dimensions"}; } } @@ -204,45 +230,72 @@ void RegularMesh::get_indices_from_bin(int bin, int* ijk) const } } -bool RegularMesh::intersects(Position r0, Position r1) const +bool RegularMesh::intersects(Position& r0, Position r1, int* ijk) const { switch(n_dimension_) { - case 1: - return intersects_1d(r0, r1); - case 2: - return intersects_2d(r0, r1); - case 3: - return intersects_3d(r0, r1); - default: - throw std::runtime_error{"Invalid number of mesh dimensions."}; + case 1: + return intersects_1d(r0, r1, ijk); + case 2: + return intersects_2d(r0, r1, ijk); + case 3: + return intersects_3d(r0, r1, ijk); + default: + throw std::runtime_error{"Invalid number of mesh dimensions."}; } } -bool RegularMesh::intersects_1d(Position r0, Position r1) const -{ - // Copy coordinates of mesh lower_left and upper_right - double left = lower_left_[0]; - double right = upper_right_[0]; - - // Check if line intersects either left or right surface - if (r0.x < left) { - return r1.x > left; - } else if (r0.x < right) { - return r1.x < left || r1.x > right; - } else { - return r1.x < right; - } -} - -bool RegularMesh::intersects_2d(Position r0, Position r1) const +bool RegularMesh::intersects_1d(Position& r0, Position r1, int* ijk) const { // Copy coordinates of starting point double x0 = r0.x; double y0 = r0.y; + double z0 = r0.z; // Copy coordinates of ending point double x1 = r1.x; double y1 = r1.y; + double z1 = r1.z; + + // Copy coordinates of mesh lower_left and upper_right + double xm0 = lower_left_[0]; + double xm1 = upper_right_[0]; + + double min_dist = INFTY; + + // Check if line intersects left surface -- calculate the intersection point + // (y,z) + if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) { + double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0); + double zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0); + if (check_intersection_point(xm0, x0, yi, yi, zi, zi, r0, min_dist)) { + ijk[0] = 1; + } + } + + // Check if line intersects right surface -- calculate the intersection point + // (y,z) + if ((x0 < xm1 && x1 > xm1) || (x0 > xm1 && x1 < xm1)) { + double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0); + double zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0); + if (check_intersection_point(xm1, x0, yi, yi, zi, zi, r0, min_dist)) { + ijk[0] = shape_[0]; + } + } + + return min_dist < INFTY; +} + +bool RegularMesh::intersects_2d(Position& r0, Position r1, int* ijk) const +{ + // Copy coordinates of starting point + double x0 = r0.x; + double y0 = r0.y; + double z0 = r0.z; + + // Copy coordinates of ending point + double x1 = r1.x; + double y1 = r1.y; + double z1 = r1.z; // Copy coordinates of mesh lower_left double xm0 = lower_left_[0]; @@ -252,44 +305,64 @@ bool RegularMesh::intersects_2d(Position r0, Position r1) const double xm1 = upper_right_[0]; double ym1 = upper_right_[1]; - // Check if line intersects left surface -- calculate the intersection point y + double min_dist = INFTY; + + // Check if line intersects left surface -- calculate the intersection point + // (y,z) if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) { double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0); + double zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0); if (yi >= ym0 && yi < ym1) { - return true; + if (check_intersection_point(xm0, x0, yi, y0, zi, zi, r0, min_dist)) { + ijk[0] = 1; + ijk[1] = std::ceil((yi - lower_left_[1]) / width_[1]); + } } } // Check if line intersects back surface -- calculate the intersection point - // x + // (x,z) if ((y0 < ym0 && y1 > ym0) || (y0 > ym0 && y1 < ym0)) { double xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0); + double zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0); if (xi >= xm0 && xi < xm1) { - return true; + if (check_intersection_point(xi, x0, ym0, y0, zi, zi, r0, min_dist)) { + ijk[0] = std::ceil((xi - lower_left_[0]) / width_[0]); + ijk[1] = 1; + } } } - // Check if line intersects right surface -- calculate the intersection - // point y + // Check if line intersects right surface -- calculate the intersection point + // (y,z) if ((x0 < xm1 && x1 > xm1) || (x0 > xm1 && x1 < xm1)) { double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0); + double zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0); if (yi >= ym0 && yi < ym1) { - return true; + if (check_intersection_point(xm1, x0, yi, y0, zi, zi, r0, min_dist)) { + ijk[0] = shape_[0]; + ijk[1] = std::ceil((yi - lower_left_[1]) / width_[1]); + } } } // Check if line intersects front surface -- calculate the intersection point - // x + // (x,z) if ((y0 < ym1 && y1 > ym1) || (y0 > ym1 && y1 < ym1)) { double xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0); + double zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0); if (xi >= xm0 && xi < xm1) { - return true; + if (check_intersection_point(xi, x0, ym1, y0, zi, zi, r0, min_dist)) { + ijk[0] = std::ceil((xi - lower_left_[0]) / width_[0]); + ijk[1] = shape_[1]; + } } } - return false; + + return min_dist < INFTY; } -bool RegularMesh::intersects_3d(Position r0, Position r1) const +bool RegularMesh::intersects_3d(Position& r0, Position r1, int* ijk) const { // Copy coordinates of starting point double x0 = r0.x; @@ -311,13 +384,19 @@ bool RegularMesh::intersects_3d(Position r0, Position r1) const double ym1 = upper_right_[1]; double zm1 = upper_right_[2]; + double min_dist = INFTY; + // Check if line intersects left surface -- calculate the intersection point // (y,z) if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) { double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0); double zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0); if (yi >= ym0 && yi < ym1 && zi >= zm0 && zi < zm1) { - return true; + if (check_intersection_point(xm0, x0, yi, y0, zi, z0, r0, min_dist)) { + ijk[0] = 1; + ijk[1] = std::ceil((yi - lower_left_[1]) / width_[1]); + ijk[2] = std::ceil((zi - lower_left_[2]) / width_[2]); + } } } @@ -327,7 +406,11 @@ bool RegularMesh::intersects_3d(Position r0, Position r1) const double xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0); double zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0); if (xi >= xm0 && xi < xm1 && zi >= zm0 && zi < zm1) { - return true; + if (check_intersection_point(xi, x0, ym0, y0, zi, z0, r0, min_dist)) { + ijk[0] = std::ceil((xi - lower_left_[0]) / width_[0]); + ijk[1] = 1; + ijk[2] = std::ceil((zi - lower_left_[2]) / width_[2]); + } } } @@ -337,7 +420,11 @@ bool RegularMesh::intersects_3d(Position r0, Position r1) const double xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0); double yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0); if (xi >= xm0 && xi < xm1 && yi >= ym0 && yi < ym1) { - return true; + if (check_intersection_point(xi, x0, yi, y0, zm0, z0, r0, min_dist)) { + ijk[0] = std::ceil((xi - lower_left_[0]) / width_[0]); + ijk[1] = std::ceil((yi - lower_left_[1]) / width_[1]); + ijk[2] = 1; + } } } @@ -347,7 +434,11 @@ bool RegularMesh::intersects_3d(Position r0, Position r1) const double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0); double zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0); if (yi >= ym0 && yi < ym1 && zi >= zm0 && zi < zm1) { - return true; + if (check_intersection_point(xm1, x0, yi, y0, zi, z0, r0, min_dist)) { + ijk[0] = shape_[0]; + ijk[1] = std::ceil((yi - lower_left_[1]) / width_[1]); + ijk[2] = std::ceil((zi - lower_left_[2]) / width_[2]); + } } } @@ -357,7 +448,11 @@ bool RegularMesh::intersects_3d(Position r0, Position r1) const double xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0); double zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0); if (xi >= xm0 && xi < xm1 && zi >= zm0 && zi < zm1) { - return true; + if (check_intersection_point(xi, x0, ym1, y0, zi, z0, r0, min_dist)) { + ijk[0] = std::ceil((xi - lower_left_[0]) / width_[0]); + ijk[1] = shape_[1]; + ijk[2] = std::ceil((zi - lower_left_[2]) / width_[2]); + } } } @@ -367,32 +462,38 @@ bool RegularMesh::intersects_3d(Position r0, Position r1) const double xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0); double yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0); if (xi >= xm0 && xi < xm1 && yi >= ym0 && yi < ym1) { - return true; + if (check_intersection_point(xi, x0, yi, y0, zm1, z0, r0, min_dist)) { + ijk[0] = std::ceil((xi - lower_left_[0]) / width_[0]); + ijk[1] = std::ceil((yi - lower_left_[1]) / width_[1]); + ijk[2] = shape_[2]; + } } } - return false; + + return min_dist < INFTY; } void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, std::vector& lengths) const { - constexpr int MAX_SEARCH_ITER = 100; - // ======================================================================== - // Determine if the track intersects the tally mesh. + // Determine where the track intersects the mesh and if it intersects at all. - // Copy the starting and ending coordinates of the particle. Offset these - // just a bit for the purposes of determining if there was an intersection - // in case the mesh surfaces coincide with lattice/geometric surfaces which - // might produce finite-precision errors. + // Copy the starting and ending coordinates of the particle. Position last_r {p->r_last_}; Position r {p->r()}; Direction u {p->u()}; + // Compute the length of the entire track. + double total_distance = (r - last_r).norm(); + + // While determining if this track intersects the mesh, offset the starting + // and ending coords by a bit. This avoid finite-precision errors that can + // occur when the mesh surfaces coincide with lattice or geometric surfaces. Position r0 = last_r + TINY_BIT*u; Position r1 = r - TINY_BIT*u; - // Determine indices for starting and ending location. + // Determine the mesh indices for the starting and ending coords. int n = n_dimension_; int ijk0[n], ijk1[n]; bool start_in_mesh; @@ -400,99 +501,32 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, bool end_in_mesh; get_indices(r1, ijk1, &end_in_mesh); - // Check if the track intersects any part of the mesh. - if (!start_in_mesh && !end_in_mesh) { - if (!intersects(r0, r1)) return; + // Reset coordinates and check for a mesh intersection if necessary. + if (start_in_mesh) { + // The initial coords lie in the mesh, use those coords for tallying. + r0 = last_r; + } else { + // The initial coords do not lie in the mesh. Check to see if the particle + // eventually intersects the mesh and compute the relevant coords and + // indices. + if (!intersects(r0, r1, ijk0)) return; } - - // ======================================================================== - // Figure out which mesh cell to tally. - - // Copy the un-modified coordinates the particle direction. - r0 = last_r; r1 = r; - // Compute the length of the entire track. - double total_distance = (r1 - r0).norm(); - - // We are looking for the first valid mesh bin. Check to see if the - // particle starts inside the mesh. - if (!start_in_mesh) { - double d[n]; - - // The particle does not start in the mesh. Note that we nudged the - // start and end coordinates by a TINY_BIT each so we will have - // difficulty resolving tracks that are less than 2*TINY_BIT in length. - // If the track is that short, it is also insignificant so we can - // safely ignore it in the tallies. - if (total_distance < 2*TINY_BIT) return; - - // The particle does not start in the mesh so keep iterating the ijk0 - // indices to cross the nearest mesh surface until we've found a valid - // bin. MAX_SEARCH_ITER prevents an infinite loop. - int search_iter = 0; - int j; - bool in_mesh = true; - for (int i = 0; i < n; ++i) { - if (ijk0[i] < 1 || ijk0[i] > shape_[i]) { - in_mesh = false; - break; - } - } - while (!in_mesh) { - if (search_iter == MAX_SEARCH_ITER) { - warning("Failed to find a mesh intersection on a tally mesh filter."); - return; - } - - for (j = 0; j < n; ++j) { - if (std::fabs(u[j]) < FP_PRECISION) { - d[j] = INFTY; - } else if (u[j] > 0.0) { - double xyz_cross = lower_left_[j] + ijk0[j] * width_[j]; - d[j] = (xyz_cross - r0[j]) / u[j]; - } else { - double xyz_cross = lower_left_[j] + (ijk0[j] - 1) * width_[j]; - d[j] = (xyz_cross - r0[j]) / u[j]; - } - } - - j = std::min_element(d, d+n) - d; - if (u[j] > 0.0) { - ++ijk0[j]; - } else { - --ijk0[j]; - } - - ++search_iter; - in_mesh = true; - for (int i = 0; i < n; ++i) { - if (ijk0[i] < 1 || ijk0[i] > shape_[i]) { - in_mesh = false; - break; - } - } - } - - // Advance position - r0 += d[j] * u; - } + // ======================================================================== + // Find which mesh cells are traversed and the length of each traversal. while (true) { - // ======================================================================== - // Compute the length of the track segment in the each mesh cell and return - if (std::equal(ijk0, ijk0+n, ijk1)) { // The track ends in this cell. Use the particle end location rather - // than the mesh surface. + // than the mesh surface and stop iterating. double distance = (r1 - r0).norm(); bins.push_back(get_bin_from_indices(ijk0)); lengths.push_back(distance / total_distance); break; } - // The track exits this cell. Determine the distance to the closest mesh - // surface. + // The track exits this cell. Determine the distance to each mesh surface. double d[n]; for (int k = 0; k < n; ++k) { if (std::fabs(u[k]) < FP_PRECISION) { @@ -506,14 +540,13 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, } } - // Assign the next tally bin and the score. + // Pick the closest mesh surface and append this traversal to the output. auto j = std::min_element(d, d+n) - d; double distance = d[j]; bins.push_back(get_bin_from_indices(ijk0)); lengths.push_back(distance / total_distance); - // Translate the starting coordintes by the distance to the oncoming mesh - // surface. + // Translate to the oncoming mesh surface. r0 += distance * u; // Increment the indices into the next mesh cell. @@ -536,7 +569,8 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, } } -void RegularMesh::surface_bins_crossed(const Particle* p, std::vector& bins) const +void RegularMesh::surface_bins_crossed(const Particle* p, + std::vector& bins) const { // ======================================================================== // Determine if the track intersects the tally mesh. @@ -555,12 +589,15 @@ void RegularMesh::surface_bins_crossed(const Particle* p, std::vector& bins get_indices(r1, ijk1, &end_in_mesh); // Check if the track intersects any part of the mesh. - if (!start_in_mesh && !end_in_mesh) { - if (!intersects(r0, r1)) return; + if (!start_in_mesh) { + Position r0_copy = r0; + int ijk0_copy[n]; + for (int i = 0; i < n; ++i) ijk0_copy[i] = ijk0[i]; + if (!intersects(r0_copy, r1, ijk0_copy)) return; } // ======================================================================== - // Figure out which mesh cell to tally. + // Find which mesh surfaces are crossed. // Calculate number of surface crossings int n_cross = 0; @@ -587,7 +624,7 @@ void RegularMesh::surface_bins_crossed(const Particle* p, std::vector& bins double distance = INFTY; for (int i = 0; i < n; ++i) { if (u[i] == 0) { - d[i] = INFINITY; + d[i] = INFTY; } else { d[i] = (xyz_cross[i] - r0[i])/u[i]; } From 707df812421ce1d81c61c30da0b175dcd4e8303f Mon Sep 17 00:00:00 2001 From: guillaume Date: Sun, 17 Mar 2019 17:11:12 -0400 Subject: [PATCH 066/165] Address some of Paul's comments --- openmc/mgxs/__init__.py | 162 ++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/openmc/mgxs/__init__.py b/openmc/mgxs/__init__.py index db5b61b09..4c17efce4 100644 --- a/openmc/mgxs/__init__.py +++ b/openmc/mgxs/__init__.py @@ -9,14 +9,14 @@ GROUP_STRUCTURES = {} """Dictionary of commonly used energy group structures: - "CASMO-X" (where X is 2, 4, 8, 16, 25, 40 or 70) from the CASMO_ lattice physics code -- "XMAS-172" designed for LWR analysis (Sartori 1990, Santamarina et al. 2004) -- "SHEM-361" designed for LWR analysis to eliminate self-shielding calculations +- "XMAS-172_" designed for LWR analysis (Sartori_ 1990, Santamarina et al. 2004) +- "SHEM-361_" designed for LWR analysis to eliminate self-shielding calculations of thermal resonances (Hfaiedh et al. 2005, Santamarina 2007, Hebert et al. 2008) - activation_ energy group structures "VITAMIN-J-175", "TRIPOLI-315", "CCFE-709_" and "UKAEA-1102_" .. _CASMO: https://www.studsvik.com/SharepointFiles/CASMO-5%20Development%20and%20Applications.pdf -.. _XMAS: https://www-nds.iaea.org/wimsd/energy.htm +.. _XMAS-172: https://www-nds.iaea.org/wimsd/energy.htm .. _SHEM-361: https://www.polymtl.ca/merlin/libraries.htm .. _activation: https://fispact.ukaea.uk/wiki/Keyword:GETXS .. _CCFE-709: https://fispact.ukaea.uk/wiki/CCFE-709_group_structure @@ -24,14 +24,14 @@ of thermal resonances (Hfaiedh et al. 2005, Santamarina 2007, Hebert et al. 2008 """ GROUP_STRUCTURES['CASMO-2'] = np.array([ - 0., 6.25e-1, 2.e7]) + 0., 6.25e-1, 2.e7]) GROUP_STRUCTURES['CASMO-4'] = np.array([ - 0., 6.25e-1, 5.53e3, 8.21e5, 2.e7]) + 0., 6.25e-1, 5.53e3, 8.21e5, 2.e7]) GROUP_STRUCTURES['CASMO-8'] = np.array([ - 0., 5.8e-2, 1.4e-1, 2.8e-1, 6.25e-1, 4., 5.53e3, 8.21e5, 2.e7]) + 0., 5.8e-2, 1.4e-1, 2.8e-1, 6.25e-1, 4., 5.53e3, 8.21e5, 2.e7]) GROUP_STRUCTURES['CASMO-16'] = np.array([ - 0., 3.e-2, 5.8e-2, 1.4e-1, 2.8e-1, 3.5e-1, 6.25e-1, 8.5e-1, - 9.72e-1, 1.02, 1.097, 1.15, 1.3, 4., 5.53e3, 8.21e5, 2.e7]) + 0., 3.e-2, 5.8e-2, 1.4e-1, 2.8e-1, 3.5e-1, 6.25e-1, 8.5e-1, + 9.72e-1, 1.02, 1.097, 1.15, 1.3, 4., 5.53e3, 8.21e5, 2.e7]) GROUP_STRUCTURES['CASMO-25'] = np.array([ 0., 3.e-2, 5.8e-2, 1.4e-1, 2.8e-1, 3.5e-1, 6.25e-1, 9.72e-1, 1.02, 1.097, 1.15, 1.855, 4., 9.877, 1.5968e1, 1.4873e2, 5.53e3, 9.118e3, 1.11e5, 5.e5, @@ -166,79 +166,79 @@ GROUP_STRUCTURES['TRIPOLI-315,'] = np.array([ 1.105e7, 1.162e7, 1.221e7, 1.284e7, 1.350e7, 1.384e7, 1.419e7, 1.455e7, 1.492e7, 1.568e7, 1.649e7, 1.691e7, 1.733e7, 1.964e7]) GROUP_STRUCTURES['SHEM-361'] = np.array([ - 2.49990e-03, 4.55602e-03, 7.14526e-03, 1.04505e-02, 1.48300e-02, - 2.00104e-02, 2.49394e-02, 2.92989e-02, 3.43998e-02, 4.02999e-02, - 4.73019e-02, 5.54982e-02, 6.51999e-02, 7.64969e-02, 8.97968e-02, - 1.04298e-01, 1.19995e-01, 1.37999e-01, 1.61895e-01, 1.90005e-01, - 2.09610e-01, 2.31192e-01, 2.54997e-01, 2.79989e-01, 3.05012e-01, - 3.25008e-01, 3.52994e-01, 3.90001e-01, 4.31579e-01, 4.75017e-01, - 5.20011e-01, 5.54990e-01, 5.94993e-01, 6.24999e-01, 7.19999e-01, - 8.00371e-01, 8.80024e-01, 9.19978e-01, 9.44022e-01, 9.63960e-01, - 9.81959e-01, 9.96501e-01, 1.00904e+00, 1.02101e+00, 1.03499e+00, - 1.07799e+00, 1.09198e+00, 1.10395e+00, 1.11605e+00, 1.12997e+00, - 1.14797e+00, 1.16999e+00, 1.21397e+00, 1.25094e+00, 1.29304e+00, - 1.33095e+00, 1.38098e+00, 1.41001e+00, 1.44397e+00, 1.51998e+00, - 1.58803e+00, 1.66895e+00, 1.77997e+00, 1.90008e+00, 1.98992e+00, - 2.07010e+00, 2.15695e+00, 2.21709e+00, 2.27299e+00, 2.33006e+00, - 2.46994e+00, 2.55000e+00, 2.59009e+00, 2.62005e+00, 2.64004e+00, - 2.70012e+00, 2.71990e+00, 2.74092e+00, 2.77512e+00, 2.88405e+00, - 3.14211e+00, 3.54307e+00, 3.71209e+00, 3.88217e+00, 4.00000e+00, - 4.21983e+00, 4.30981e+00, 4.41980e+00, 4.76785e+00, 4.93323e+00, - 5.10997e+00, 5.21008e+00, 5.32011e+00, 5.38003e+00, 5.41025e+00, - 5.48817e+00, 5.53004e+00, 5.61979e+00, 5.72015e+00, 5.80021e+00, - 5.96014e+00, 6.05991e+00, 6.16011e+00, 6.28016e+00, 6.35978e+00, - 6.43206e+00, 6.48178e+00, 6.51492e+00, 6.53907e+00, 6.55609e+00, - 6.57184e+00, 6.58829e+00, 6.60611e+00, 6.63126e+00, 6.71668e+00, - 6.74225e+00, 6.75981e+00, 6.77605e+00, 6.79165e+00, 6.81070e+00, - 6.83526e+00, 6.87021e+00, 6.91778e+00, 6.99429e+00, 7.13987e+00, - 7.38015e+00, 7.60035e+00, 7.73994e+00, 7.83965e+00, 7.97008e+00, - 8.13027e+00, 8.30032e+00, 8.52407e+00, 8.67369e+00, 8.80038e+00, - 8.97995e+00, 9.14031e+00, 9.50002e+00, 1.05793e+01, 1.08038e+01, - 1.10529e+01, 1.12694e+01, 1.15894e+01, 1.17094e+01, 1.18153e+01, - 1.19795e+01, 1.21302e+01, 1.23086e+01, 1.24721e+01, 1.26000e+01, - 1.33297e+01, 1.35460e+01, 1.40496e+01, 1.42505e+01, 1.44702e+01, - 1.45952e+01, 1.47301e+01, 1.48662e+01, 1.57792e+01, 1.60498e+01, - 1.65501e+01, 1.68305e+01, 1.74457e+01, 1.75648e+01, 1.77590e+01, - 1.79591e+01, 1.90848e+01, 1.91997e+01, 1.93927e+01, 1.95974e+01, - 2.00734e+01, 2.02751e+01, 2.04175e+01, 2.05199e+01, 2.06021e+01, - 2.06847e+01, 2.07676e+01, 2.09763e+01, 2.10604e+01, 2.11448e+01, - 2.12296e+01, 2.13360e+01, 2.14859e+01, 2.17018e+01, 2.20011e+01, - 2.21557e+01, 2.23788e+01, 2.25356e+01, 2.46578e+01, 2.78852e+01, - 3.16930e+01, 3.30855e+01, 3.45392e+01, 3.56980e+01, 3.60568e+01, - 3.64191e+01, 3.68588e+01, 3.73038e+01, 3.77919e+01, 3.87874e+01, - 3.97295e+01, 4.12270e+01, 4.21441e+01, 4.31246e+01, 4.41721e+01, - 4.52904e+01, 4.62053e+01, 4.75173e+01, 4.92591e+01, 5.17847e+01, - 5.29895e+01, 5.40600e+01, 5.70595e+01, 5.99250e+01, 6.23083e+01, - 6.36306e+01, 6.45923e+01, 6.50460e+01, 6.55029e+01, 6.58312e+01, - 6.61612e+01, 6.64929e+01, 6.68261e+01, 6.90682e+01, 7.18869e+01, - 7.35595e+01, 7.63322e+01, 7.93679e+01, 8.39393e+01, 8.87741e+01, - 9.33256e+01, 9.73287e+01, 1.00594e+02, 1.01098e+02, 1.01605e+02, - 1.02115e+02, 1.03038e+02, 1.05646e+02, 1.10288e+02, 1.12854e+02, - 1.15480e+02, 1.16524e+02, 1.17577e+02, 1.20554e+02, 1.26229e+02, - 1.32701e+02, 1.39504e+02, 1.46657e+02, 1.54176e+02, 1.63056e+02, - 1.67519e+02, 1.75229e+02, 1.83295e+02, 1.84952e+02, 1.86251e+02, - 1.87559e+02, 1.88877e+02, 1.90204e+02, 1.93078e+02, 1.95996e+02, - 2.00958e+02, 2.12108e+02, 2.24325e+02, 2.35590e+02, 2.41796e+02, - 2.56748e+02, 2.68297e+02, 2.76468e+02, 2.84888e+02, 2.88327e+02, - 2.95922e+02, 3.19928e+02, 3.35323e+02, 3.53575e+02, 3.71703e+02, - 3.90760e+02, 4.19094e+02, 4.53999e+02, 5.01746e+02, 5.39204e+02, - 5.77146e+02, 5.92941e+02, 6.00099e+02, 6.12834e+02, 6.46837e+02, - 6.77287e+02, 7.48517e+02, 8.32218e+02, 9.09681e+02, 9.82494e+02, - 1.06432e+03, 1.13467e+03, 1.34358e+03, 1.58620e+03, 1.81183e+03, - 2.08410e+03, 2.39729e+03, 2.70024e+03, 2.99618e+03, 3.48107e+03, - 4.09735e+03, 5.00451e+03, 6.11252e+03, 7.46585e+03, 9.11881e+03, - 1.11377e+04, 1.36037e+04, 1.48997e+04, 1.62005e+04, 1.85847e+04, - 2.26994e+04, 2.49991e+04, 2.61001e+04, 2.73944e+04, 2.92810e+04, - 3.34596e+04, 3.69786e+04, 4.08677e+04, 4.99159e+04, 5.51656e+04, - 6.73794e+04, 8.22974e+04, 9.46645e+04, 1.15624e+05, 1.22773e+05, - 1.40000e+05, 1.64999e+05, 1.95008e+05, 2.30014e+05, 2.67826e+05, - 3.20646e+05, 3.83884e+05, 4.12501e+05, 4.56021e+05, 4.94002e+05, - 5.78443e+05, 7.06511e+05, 8.60006e+05, 9.51119e+05, 1.05115e+06, - 1.16205e+06, 1.28696e+06, 1.33694e+06, 1.40577e+06, 1.63654e+06, - 1.90139e+06, 2.23130e+06, 2.72531e+06, 3.32871e+06, 4.06569e+06, - 4.96585e+06, 6.06530e+06, 6.70319e+06, 7.40817e+06, 8.18730e+06, - 9.04836e+06, 9.99999e+06, 1.16183e+07, 1.38403e+07, 1.49182e+07, - 1.96403e+07]) + 0.00000e+00, 2.49990e-03, 4.55602e-03, 7.14526e-03, 1.04505e-02, + 1.48300e-02, 2.00104e-02, 2.49394e-02, 2.92989e-02, 3.43998e-02, + 4.02999e-02, 4.73019e-02, 5.54982e-02, 6.51999e-02, 7.64969e-02, + 8.97968e-02, 1.04298e-01, 1.19995e-01, 1.37999e-01, 1.61895e-01, + 1.90005e-01, 2.09610e-01, 2.31192e-01, 2.54997e-01, 2.79989e-01, + 3.05012e-01, 3.25008e-01, 3.52994e-01, 3.90001e-01, 4.31579e-01, + 4.75017e-01, 5.20011e-01, 5.54990e-01, 5.94993e-01, 6.24999e-01, + 7.19999e-01, 8.00371e-01, 8.80024e-01, 9.19978e-01, 9.44022e-01, + 9.63960e-01, 9.81959e-01, 9.96501e-01, 1.00904e+00, 1.02101e+00, + 1.03499e+00, 1.07799e+00, 1.09198e+00, 1.10395e+00, 1.11605e+00, + 1.12997e+00, 1.14797e+00, 1.16999e+00, 1.21397e+00, 1.25094e+00, + 1.29304e+00, 1.33095e+00, 1.38098e+00, 1.41001e+00, 1.44397e+00, + 1.51998e+00, 1.58803e+00, 1.66895e+00, 1.77997e+00, 1.90008e+00, + 1.98992e+00, 2.07010e+00, 2.15695e+00, 2.21709e+00, 2.27299e+00, + 2.33006e+00, 2.46994e+00, 2.55000e+00, 2.59009e+00, 2.62005e+00, + 2.64004e+00, 2.70012e+00, 2.71990e+00, 2.74092e+00, 2.77512e+00, + 2.88405e+00, 3.14211e+00, 3.54307e+00, 3.71209e+00, 3.88217e+00, + 4.00000e+00, 4.21983e+00, 4.30981e+00, 4.41980e+00, 4.76785e+00, + 4.93323e+00, 5.10997e+00, 5.21008e+00, 5.32011e+00, 5.38003e+00, + 5.41025e+00, 5.48817e+00, 5.53004e+00, 5.61979e+00, 5.72015e+00, + 5.80021e+00, 5.96014e+00, 6.05991e+00, 6.16011e+00, 6.28016e+00, + 6.35978e+00, 6.43206e+00, 6.48178e+00, 6.51492e+00, 6.53907e+00, + 6.55609e+00, 6.57184e+00, 6.58829e+00, 6.60611e+00, 6.63126e+00, + 6.71668e+00, 6.74225e+00, 6.75981e+00, 6.77605e+00, 6.79165e+00, + 6.81070e+00, 6.83526e+00, 6.87021e+00, 6.91778e+00, 6.99429e+00, + 7.13987e+00, 7.38015e+00, 7.60035e+00, 7.73994e+00, 7.83965e+00, + 7.97008e+00, 8.13027e+00, 8.30032e+00, 8.52407e+00, 8.67369e+00, + 8.80038e+00, 8.97995e+00, 9.14031e+00, 9.50002e+00, 1.05793e+01, + 1.08038e+01, 1.10529e+01, 1.12694e+01, 1.15894e+01, 1.17094e+01, + 1.18153e+01, 1.19795e+01, 1.21302e+01, 1.23086e+01, 1.24721e+01, + 1.26000e+01, 1.33297e+01, 1.35460e+01, 1.40496e+01, 1.42505e+01, + 1.44702e+01, 1.45952e+01, 1.47301e+01, 1.48662e+01, 1.57792e+01, + 1.60498e+01, 1.65501e+01, 1.68305e+01, 1.74457e+01, 1.75648e+01, + 1.77590e+01, 1.79591e+01, 1.90848e+01, 1.91997e+01, 1.93927e+01, + 1.95974e+01, 2.00734e+01, 2.02751e+01, 2.04175e+01, 2.05199e+01, + 2.06021e+01, 2.06847e+01, 2.07676e+01, 2.09763e+01, 2.10604e+01, + 2.11448e+01, 2.12296e+01, 2.13360e+01, 2.14859e+01, 2.17018e+01, + 2.20011e+01, 2.21557e+01, 2.23788e+01, 2.25356e+01, 2.46578e+01, + 2.78852e+01, 3.16930e+01, 3.30855e+01, 3.45392e+01, 3.56980e+01, + 3.60568e+01, 3.64191e+01, 3.68588e+01, 3.73038e+01, 3.77919e+01, + 3.87874e+01, 3.97295e+01, 4.12270e+01, 4.21441e+01, 4.31246e+01, + 4.41721e+01, 4.52904e+01, 4.62053e+01, 4.75173e+01, 4.92591e+01, + 5.17847e+01, 5.29895e+01, 5.40600e+01, 5.70595e+01, 5.99250e+01, + 6.23083e+01, 6.36306e+01, 6.45923e+01, 6.50460e+01, 6.55029e+01, + 6.58312e+01, 6.61612e+01, 6.64929e+01, 6.68261e+01, 6.90682e+01, + 7.18869e+01, 7.35595e+01, 7.63322e+01, 7.93679e+01, 8.39393e+01, + 8.87741e+01, 9.33256e+01, 9.73287e+01, 1.00594e+02, 1.01098e+02, + 1.01605e+02, 1.02115e+02, 1.03038e+02, 1.05646e+02, 1.10288e+02, + 1.12854e+02, 1.15480e+02, 1.16524e+02, 1.17577e+02, 1.20554e+02, + 1.26229e+02, 1.32701e+02, 1.39504e+02, 1.46657e+02, 1.54176e+02, + 1.63056e+02, 1.67519e+02, 1.75229e+02, 1.83295e+02, 1.84952e+02, + 1.86251e+02, 1.87559e+02, 1.88877e+02, 1.90204e+02, 1.93078e+02, + 1.95996e+02, 2.00958e+02, 2.12108e+02, 2.24325e+02, 2.35590e+02, + 2.41796e+02, 2.56748e+02, 2.68297e+02, 2.76468e+02, 2.84888e+02, + 2.88327e+02, 2.95922e+02, 3.19928e+02, 3.35323e+02, 3.53575e+02, + 3.71703e+02, 3.90760e+02, 4.19094e+02, 4.53999e+02, 5.01746e+02, + 5.39204e+02, 5.77146e+02, 5.92941e+02, 6.00099e+02, 6.12834e+02, + 6.46837e+02, 6.77287e+02, 7.48517e+02, 8.32218e+02, 9.09681e+02, + 9.82494e+02, 1.06432e+03, 1.13467e+03, 1.34358e+03, 1.58620e+03, + 1.81183e+03, 2.08410e+03, 2.39729e+03, 2.70024e+03, 2.99618e+03, + 3.48107e+03, 4.09735e+03, 5.00451e+03, 6.11252e+03, 7.46585e+03, + 9.11881e+03, 1.11377e+04, 1.36037e+04, 1.48997e+04, 1.62005e+04, + 1.85847e+04, 2.26994e+04, 2.49991e+04, 2.61001e+04, 2.73944e+04, + 2.92810e+04, 3.34596e+04, 3.69786e+04, 4.08677e+04, 4.99159e+04, + 5.51656e+04, 6.73794e+04, 8.22974e+04, 9.46645e+04, 1.15624e+05, + 1.22773e+05, 1.40000e+05, 1.64999e+05, 1.95008e+05, 2.30014e+05, + 2.67826e+05, 3.20646e+05, 3.83884e+05, 4.12501e+05, 4.56021e+05, + 4.94002e+05, 5.78443e+05, 7.06511e+05, 8.60006e+05, 9.51119e+05, + 1.05115e+06, 1.16205e+06, 1.28696e+06, 1.33694e+06, 1.40577e+06, + 1.63654e+06, 1.90139e+06, 2.23130e+06, 2.72531e+06, 3.32871e+06, + 4.06569e+06, 4.96585e+06, 6.06530e+06, 6.70319e+06, 7.40817e+06, + 8.18730e+06, 9.04836e+06, 9.99999e+06, 1.16183e+07, 1.38403e+07, + 1.49182e+07, 1.96403e+07]) GROUP_STRUCTURES['CCFE-709'] = np.array([ 1.e-5, 1.0471e-5, 1.0965e-5, 1.1482e-5, 1.2023e-5, 1.2589e-5, 1.3183e-5, 1.3804e-5, 1.4454e-5, 1.5136e-5, From ce1aca5d6f3288b3bec50034c2267a5725f63b3e Mon Sep 17 00:00:00 2001 From: guillaume Date: Sun, 17 Mar 2019 21:47:15 -0400 Subject: [PATCH 067/165] Fix indent, add citations --- openmc/mgxs/__init__.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/openmc/mgxs/__init__.py b/openmc/mgxs/__init__.py index 4c17efce4..350039e52 100644 --- a/openmc/mgxs/__init__.py +++ b/openmc/mgxs/__init__.py @@ -8,12 +8,12 @@ from openmc.mgxs.mdgxs import * GROUP_STRUCTURES = {} """Dictionary of commonly used energy group structures: - "CASMO-X" (where X is 2, 4, 8, 16, 25, 40 or 70) from the CASMO_ lattice -physics code -- "XMAS-172_" designed for LWR analysis (Sartori_ 1990, Santamarina et al. 2004) + physics code +- "XMAS-172_" designed for LWR analysis ([SAR1990]_, [SAN2004]_) - "SHEM-361_" designed for LWR analysis to eliminate self-shielding calculations -of thermal resonances (Hfaiedh et al. 2005, Santamarina 2007, Hebert et al. 2008) + of thermal resonances ([HFA2005]_, [SAN2007]_, [HEB2008]_) - activation_ energy group structures "VITAMIN-J-175", "TRIPOLI-315", -"CCFE-709_" and "UKAEA-1102_" + "CCFE-709_" and "UKAEA-1102_" .. _CASMO: https://www.studsvik.com/SharepointFiles/CASMO-5%20Development%20and%20Applications.pdf .. _XMAS-172: https://www-nds.iaea.org/wimsd/energy.htm @@ -21,6 +21,22 @@ of thermal resonances (Hfaiedh et al. 2005, Santamarina 2007, Hebert et al. 2008 .. _activation: https://fispact.ukaea.uk/wiki/Keyword:GETXS .. _CCFE-709: https://fispact.ukaea.uk/wiki/CCFE-709_group_structure .. _UKAEA-1102: https://fispact.ukaea.uk/wiki/UKAEA-1102_group_structure +.. [SAR1990] Sartori, E., OECD/NEA Data Bank: Standard Energy Group Structures + of Cross Section Libraries for Reactor Shielding, Reactor Cell and Fusion + Neutronics Applications: VITAMIN-J, ECCO-33, ECCO-2000 and XMAS JEF/DOC-315 + Revision 3 - DRAFT (December 11, 1990). +.. [SAN2004] Santamarina, A., Collignon, C., & Garat, C. (2004). French + calculation schemes for light water reactor analysis. United States: + American Nuclear Society - ANS. +.. [HFA2005] Hfaiedh, N. & Santamarina, A., "Determination of the Optimized + SHEM Mesh for Neutron Transport Calculations," Proc. Top. Mtg. in + Mathematics & Computations, Supercomputing, Reactor Physics and Nuclear and + Biological Applications, September 12-15, Avignon, France, 2005. +.. [SAN2007] Santamarina, A. & Hfaiedh, N. (2007). The SHEM energy mesh for + accurate fuel depletion and BUC calculations. +.. [HEB2008] Hébert, Alain & Santamarina, Alain. (2008). Refinement of the + Santamarina-Hfaiedh energy mesh between 22.5 eV and 11.4 keV. International + Conference on the Physics of Reactors 2008, PHYSOR 08. 2. 929-938. """ GROUP_STRUCTURES['CASMO-2'] = np.array([ From 55d9a5f33a8f4eda1d235eba7af39efb0716de13 Mon Sep 17 00:00:00 2001 From: Giud Date: Sun, 17 Mar 2019 23:22:20 -0400 Subject: [PATCH 068/165] Update __init__.py --- openmc/mgxs/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openmc/mgxs/__init__.py b/openmc/mgxs/__init__.py index 350039e52..e505c7ebc 100644 --- a/openmc/mgxs/__init__.py +++ b/openmc/mgxs/__init__.py @@ -33,7 +33,9 @@ GROUP_STRUCTURES = {} Mathematics & Computations, Supercomputing, Reactor Physics and Nuclear and Biological Applications, September 12-15, Avignon, France, 2005. .. [SAN2007] Santamarina, A. & Hfaiedh, N. (2007). The SHEM energy mesh for - accurate fuel depletion and BUC calculations. + accurate fuel depletion and BUC calculations. Proceedings of the International + Conference on Safety Criticality ICNC 2007, St Peterburg (Russia), Vol. I pp. + 446-452. .. [HEB2008] Hébert, Alain & Santamarina, Alain. (2008). Refinement of the Santamarina-Hfaiedh energy mesh between 22.5 eV and 11.4 keV. International Conference on the Physics of Reactors 2008, PHYSOR 08. 2. 929-938. From 4048a47fc44a49fbd4f32592beed365021629f2c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 09:23:14 -0500 Subject: [PATCH 069/165] Addressing some change requests from @promano. --- src/dagmc.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 456f9f279..5e4e237c0 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -89,8 +89,7 @@ bool write_uwuw_materials_xml() { return found_uwuw_mats; } -void legacy_assign_material(const std::string& mat_string, - DAGCell* c) +void legacy_assign_material(const std::string& mat_string, DAGCell* c) { bool mat_found_by_name = false; // attempt to find a material with a matching name @@ -116,7 +115,7 @@ void legacy_assign_material(const std::string& mat_string, try { auto id = std::stoi(mat_string); c->material_.emplace_back(id); - } catch (...) { + } catch (const std::invalid_argument&) { std::stringstream err_msg; err_msg << "No material " << mat_string << " found for volume (cell) " << c->id_; @@ -128,11 +127,11 @@ void legacy_assign_material(const std::string& mat_string, Material* m = model::materials[model::material_map[c->material_[0]]].get(); std::stringstream msg; msg << "DAGMC material " << mat_string << " was assigned"; - if (mat_found_by_name) { - msg << " using material name: " << m->name_; - } else { - msg << " using material id: " << m->id_; - } + if (mat_found_by_name) { + msg << " using material name: " << m->name_; + } else { + msg << " using material id: " << m->id_; + } write_message(msg.str(), 10); } } From 1d78df26eb4256535ddeada1dc1eb5317ee578e7 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 11 Mar 2019 10:14:17 -0500 Subject: [PATCH 070/165] Generalizing slice operation. Using templates to specialize data returned. --- include/openmc/plot.h | 12 ++- src/plot.cpp | 171 ++++++++++++++++++++++++++---------------- 2 files changed, 117 insertions(+), 66 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 8a9e4e74d..63246b265 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -53,6 +53,7 @@ struct RGBColor { typedef xt::xtensor ImageData; typedef xt::xtensor IdData; +typedef xt::xtensor PropertyData; enum class PlotType { slice = 1, @@ -73,8 +74,17 @@ enum class PlotColorBy { //=============================================================================== // Plot class //=============================================================================== -struct PlotBase { +class PlotBase { + public: + IdData get_id_map() const; + PropertyData get_property_map() const; + + private: + template + D generate_data() const; + // Members + public: Position origin_; //!< Plot origin in geometry Position width_; //!< Plot width in geometry PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) diff --git a/src/plot.cpp b/src/plot.cpp index 729b2db48..95f7acad7 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -29,6 +29,34 @@ namespace openmc { const RGBColor WHITE {255, 255, 255}; constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level constexpr int NOT_FOUND {-1}; + +struct id_setter { + void operator()(const Particle& p, IdData& ids, int y, int x, int level) { + Cell* c = model::cells[p.coord_[level].cell].get(); + ids(y,x,0) = c->id_; + if (c->type_ == FILL_UNIVERSE || p.material_ == MATERIAL_VOID) { + ids(y,x,1) = NOT_FOUND; + } else { + Material* m = model::materials[p.material_].get(); + ids(y,x,1) = m->id_; + } + } +}; + +struct property_setter { + void operator()(const Particle& p, PropertyData& props, int y, int x, int level) { + Cell* c = model::cells[p.coord_[level].cell].get(); + props(y,x,0) = (p.sqrtkT_ * p.sqrtkT_) * K_BOLTZMANN; + if (c->type_ == FILL_UNIVERSE || p.material_ == MATERIAL_VOID) { + props(y,x, 1) = NOT_FOUND; + } else { + Material* m = model::materials[p.material_].get(); + props(y,x,1) = m->density_gpcc_; + } + } +}; + + //============================================================================== // Global variables //============================================================================== @@ -637,6 +665,82 @@ Plot::Plot(pugi::xml_node plot_node) set_mask(plot_node); } // End Plot constructor +template +D PlotBase::generate_data() const { + + size_t width = pixels_[0]; + size_t height = pixels_[1]; + + // get pixel size + double in_pixel = (width_[0])/static_cast(width); + double out_pixel = (width_[1])/static_cast(height); + + // size data array + D data({height, width, 2}, NOT_FOUND); + + // setup basis indices and initial position centered on pixel + int in_i, out_i; + Position xyz = origin_; + switch(basis_) { + case PlotBasis::xy : + in_i = 0; + out_i = 1; + break; + case PlotBasis::xz : + in_i = 0; + out_i = 2; + break; + case PlotBasis::yz : + in_i = 1; + out_i = 2; + break; + } + + // set initial position + xyz[in_i] = origin_[in_i] - width_[0] / 2. + in_pixel / 2.; + xyz[out_i] = origin_[out_i] + width_[1] / 2. - out_pixel / 2.; + + // arbitrary direction + Direction dir = {0.5, 0.5, 0.5}; + +#pragma omp parallel +{ + Particle p; + p.r() = xyz; + p.u() = dir; + p.coord_[0].universe = model::root_universe; + int level = level_; + int j{}; + + #pragma omp for + for (int y = 0; y < height; y++) { + p.r()[out_i] = xyz[out_i] - out_pixel * y; + for (int x = 0; x < width; x++) { + p.r()[in_i] = xyz[in_i] + in_pixel * x; + p.n_coord_ = 1; + // local variables + bool found_cell = find_cell(&p, 0); + j = p.n_coord_ - 1; + if (level >=0) {j = level + 1;} + if (found_cell) { + setter()(p, data, y, x, j); + Cell* c = model::cells[p.coord_[j].cell].get(); + } + } // inner for + } // outer for + } // omp parallel + + return data; +} + +IdData PlotBase::get_id_map() const { + return generate_data(); +} + +PropertyData PlotBase::get_property_map() const { + return generate_data(); +} + //============================================================================== // POSITION_RGB computes the red/green/blue values for a given plot with the // current particle's position @@ -963,73 +1067,10 @@ extern "C" int openmc_id_map(const void* plot, int32_t* data_out) return OPENMC_E_INVALID_ARGUMENT; } - size_t width = plt->pixels_[0]; - size_t height = plt->pixels_[1]; - - // get pixel size - double in_pixel = (plt->width_[0])/static_cast(width); - double out_pixel = (plt->width_[1])/static_cast(height); - - // size data array - IdData data({height, width, 2}, NOT_FOUND); - - // setup basis indices and initial position centered on pixel - int in_i, out_i; - Position xyz = plt->origin_; - switch(plt->basis_) { - case PlotBasis::xy : - in_i = 0; - out_i = 1; - break; - case PlotBasis::xz : - in_i = 0; - out_i = 2; - break; - case PlotBasis::yz : - in_i = 1; - out_i = 2; - break; - } - - // set initial position - xyz[in_i] = plt->origin_[in_i] - plt->width_[0] / 2. + in_pixel / 2.; - xyz[out_i] = plt->origin_[out_i] + plt->width_[1] / 2. - out_pixel / 2.; - - // arbitrary direction - Direction dir = {0.5, 0.5, 0.5}; - - #pragma omp parallel - { - Particle p; - p.r() = xyz; - p.u() = dir; - p.coord_[0].universe = model::root_universe; - int level = plt->level_; - int j{}; - - #pragma omp for - for (int y = 0; y < height; y++) { - p.r()[out_i] = xyz[out_i] - out_pixel * y; - for (int x = 0; x < width; x++) { - p.r()[in_i] = xyz[in_i] + in_pixel * x; - p.n_coord_ = 1; - // local variables - bool found_cell = find_cell(&p, 0); - j = p.n_coord_ - 1; - if (level >=0) {j = level + 1;} - if (found_cell) { - Cell* c = model::cells[p.coord_[j].cell].get(); - data(y,x,0) = c->id_; - if (c->type_ != FILL_UNIVERSE && p.material_ != MATERIAL_VOID) { - data(y,x,1) = model::materials[p.material_]->id_; - } - } - } // inner for - } // outer for - } // omp parallel + auto ids = plt->get_id_map(); // write id data to array - std::copy(data.begin(), data.end(), data_out); + std::copy(ids.begin(), ids.end(), data_out); return 0; } From b9a57b02d453324b70024aa78681c12a98c2d2dc Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 11 Mar 2019 10:55:54 -0500 Subject: [PATCH 071/165] Exposing properties via capi and Python interface. --- include/openmc/capi.h | 3 ++- openmc/capi/plot.py | 23 +++++++++++++++++++++++ src/plot.cpp | 20 +++++++++++++++++++- tests/unit_tests/test_capi.py | 21 +++++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 5d07edb21..5e74446f1 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -70,7 +70,8 @@ extern "C" { int openmc_next_batch(int* status); int openmc_nuclide_name(int index, const char** name); int openmc_plot_geometry(); - int openmc_id_map(const void* slice, int32_t* data_out); + int openmc_id_map(const void* slice, int32_t *data_out); + int openmc_property_map(void* slice, double *data_out); int openmc_reset(); int openmc_run(); void openmc_set_seed(int64_t new_seed); diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 78fcef912..e8d1c06b4 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -218,3 +218,26 @@ def id_map(plot): _dll.openmc_id_map(POINTER(_PlotBase)(plot), img_data.ctypes.data_as(POINTER(c_int32))) return img_data + + +def property_map(plot): + """ + Generate a 2-D map of (cell_temperature, material_density). Used for + in-memory image generation. + + Parameters + ---------- + plot : An openmc.capi.plot._PlotBase object describing the slice of the + model to be generated + + Returns + ------- + property_map : a NumPy array with shape (vertical pixels, horizontal pixels, 2) + of OpenMC property ids with dtype float + + """ + prop_data = np.zeros((plot.vRes, plot.hRes, 2), + dtype=np.dtype('float')) + _dll.openmc_property_map(POINTER(_PlotBase)(plot), + prop_data.ctypes.data_as(POINTER(c_double))) + return prop_data diff --git a/src/plot.cpp b/src/plot.cpp index 95f7acad7..5a35ceb40 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -46,7 +46,7 @@ struct id_setter { struct property_setter { void operator()(const Particle& p, PropertyData& props, int y, int x, int level) { Cell* c = model::cells[p.coord_[level].cell].get(); - props(y,x,0) = (p.sqrtkT_ * p.sqrtkT_) * K_BOLTZMANN; + props(y,x,0) = (p.sqrtkT_ * p.sqrtkT_) / K_BOLTZMANN; if (c->type_ == FILL_UNIVERSE || p.material_ == MATERIAL_VOID) { props(y,x, 1) = NOT_FOUND; } else { @@ -1075,4 +1075,22 @@ extern "C" int openmc_id_map(const void* plot, int32_t* data_out) return 0; } +extern "C" int openmc_property_map(void* plot, double* data_out) { + + auto plt = reinterpret_cast(plot); + if (!plt) { + set_errmsg("Invalid slice pointer passed to openmc_id_map"); + return OPENMC_E_INVALID_ARGUMENT; + } + + PropertyData data = plt->get_property_map(); + + // write id data to array + size_t i = 0; + for (auto v : data) { data_out[i++] = v; } + + return 0; +} + + } // namespace openmc diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 97d18531b..1d2fb2ecb 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -419,3 +419,24 @@ def test_id_map(capi_init): ids = openmc.capi.plot.id_map(s) assert np.array_equal(expected_ids, ids) + +def test_property_map(capi_init): + expected_properties = np.array( + [[(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)], + [ (293.6, 6.55), (293.6, 10.29769), (293.6, 6.55)], + [(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)]], dtype='float') + + # create a plot object + s = openmc.capi.plot._PlotBase() + s.width = 1.26 + s.height = 1.26 + s.vRes = 3 + s.hRes = 3 + s.origin = (0.0, 0.0, 0.0) + s.basis = 'xy' + s.level = -1 + + properties = openmc.capi.plot.property_map(s) + print(properties) + print(expected_properties) + assert np.allclose(expected_properties, properties, atol=1e-04) From cdaad6ad5461f3d2bf2ed7f24d5fd327946733ef Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 12 Mar 2019 14:41:02 -0500 Subject: [PATCH 072/165] Making pointer for property_map const and fixing property_map tests. --- include/openmc/capi.h | 2 +- openmc/capi/plot.py | 2 +- src/plot.cpp | 9 ++++----- tests/unit_tests/test_capi.py | 6 ++---- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 5e74446f1..617153b6c 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -71,7 +71,7 @@ extern "C" { int openmc_nuclide_name(int index, const char** name); int openmc_plot_geometry(); int openmc_id_map(const void* slice, int32_t *data_out); - int openmc_property_map(void* slice, double *data_out); + int openmc_property_map(const void* slice, double *data_out); int openmc_reset(); int openmc_run(); void openmc_set_seed(int64_t new_seed); diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index e8d1c06b4..c950f278b 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -236,7 +236,7 @@ def property_map(plot): of OpenMC property ids with dtype float """ - prop_data = np.zeros((plot.vRes, plot.hRes, 2), + prop_data = np.zeros((plot.v_res, plot.h_res, 2), dtype=np.dtype('float')) _dll.openmc_property_map(POINTER(_PlotBase)(plot), prop_data.ctypes.data_as(POINTER(c_double))) diff --git a/src/plot.cpp b/src/plot.cpp index 5a35ceb40..45782b802 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -1075,19 +1075,18 @@ extern "C" int openmc_id_map(const void* plot, int32_t* data_out) return 0; } -extern "C" int openmc_property_map(void* plot, double* data_out) { +extern "C" int openmc_property_map(const void* plot, double* data_out) { - auto plt = reinterpret_cast(plot); + auto plt = reinterpret_cast(plot); if (!plt) { set_errmsg("Invalid slice pointer passed to openmc_id_map"); return OPENMC_E_INVALID_ARGUMENT; } - PropertyData data = plt->get_property_map(); + PropertyData props = plt->get_property_map(); // write id data to array - size_t i = 0; - for (auto v : data) { data_out[i++] = v; } + std::copy(props.begin(), props.end(), data_out); return 0; } diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 1d2fb2ecb..14dac21fc 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -430,13 +430,11 @@ def test_property_map(capi_init): s = openmc.capi.plot._PlotBase() s.width = 1.26 s.height = 1.26 - s.vRes = 3 - s.hRes = 3 + s.v_res = 3 + s.h_res = 3 s.origin = (0.0, 0.0, 0.0) s.basis = 'xy' s.level = -1 properties = openmc.capi.plot.property_map(s) - print(properties) - print(expected_properties) assert np.allclose(expected_properties, properties, atol=1e-04) From 49ee1c4048dc1efc42e2b72a464ecb25d1dc162e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 12 Mar 2019 17:37:27 -0500 Subject: [PATCH 073/165] Making datasets structs with set_value methods instead of templating setters. --- include/openmc/plot.h | 27 ++++++++++++++++--- src/plot.cpp | 63 ++++++++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 34 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 63246b265..b879dbe36 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -51,9 +51,30 @@ struct RGBColor { uint8_t red, green, blue; }; + typedef xt::xtensor ImageData; -typedef xt::xtensor IdData; -typedef xt::xtensor PropertyData; + +struct IdData { + // Constructor + IdData(int h_res, int v_res); + + // Methods + void set_value(int y, int x, const Particle& p, int level); + + // Members + xt::xtensor data; +}; + +struct PropertyData { + // Constructor + PropertyData(int h_res, int v_res); + + // Methods + void set_value(int y, int x, const Particle& p, int level); + + // Members + xt::xtensor data; +}; enum class PlotType { slice = 1, @@ -80,7 +101,7 @@ class PlotBase { PropertyData get_property_map() const; private: - template + template D generate_data() const; // Members diff --git a/src/plot.cpp b/src/plot.cpp index 45782b802..cbdae30d5 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -28,34 +28,35 @@ namespace openmc { const RGBColor WHITE {255, 255, 255}; constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level -constexpr int NOT_FOUND {-1}; +constexpr int32_t NOT_FOUND {-1}; -struct id_setter { - void operator()(const Particle& p, IdData& ids, int y, int x, int level) { - Cell* c = model::cells[p.coord_[level].cell].get(); - ids(y,x,0) = c->id_; - if (c->type_ == FILL_UNIVERSE || p.material_ == MATERIAL_VOID) { - ids(y,x,1) = NOT_FOUND; - } else { - Material* m = model::materials[p.material_].get(); - ids(y,x,1) = m->id_; - } +IdData::IdData(int h_res, int v_res) { + data = xt::xtensor({v_res, h_res, 2}, NOT_FOUND); +} + +void +IdData::set_value(int y, int x, const Particle& p, int level) { + Cell* c = model::cells[p.coord_[level].cell].get(); + data(y,x,0) = c->id_; + if (c->type_ != FILL_UNIVERSE && p.material_ != MATERIAL_VOID) { + Material* m = model::materials[p.material_].get(); + data(y,x,1) = m->id_; } -}; +} -struct property_setter { - void operator()(const Particle& p, PropertyData& props, int y, int x, int level) { - Cell* c = model::cells[p.coord_[level].cell].get(); - props(y,x,0) = (p.sqrtkT_ * p.sqrtkT_) / K_BOLTZMANN; - if (c->type_ == FILL_UNIVERSE || p.material_ == MATERIAL_VOID) { - props(y,x, 1) = NOT_FOUND; - } else { - Material* m = model::materials[p.material_].get(); - props(y,x,1) = m->density_gpcc_; - } +PropertyData::PropertyData(int h_res, int v_res) { + data = xt::xtensor({v_res, h_res, 2}, NOT_FOUND); +} + +void +PropertyData::set_value(int y, int x, const Particle& p, int level) { + Cell* c = model::cells[p.coord_[level].cell].get(); + data(y,x,0) = (p.sqrtkT_ * p.sqrtkT_) / K_BOLTZMANN; + if (c->type_ != FILL_UNIVERSE && p.material_ != MATERIAL_VOID) { + Material* m = model::materials[p.material_].get(); + data(y,x,1) = m->density_gpcc_; } -}; - +} //============================================================================== // Global variables @@ -665,7 +666,7 @@ Plot::Plot(pugi::xml_node plot_node) set_mask(plot_node); } // End Plot constructor -template +template D PlotBase::generate_data() const { size_t width = pixels_[0]; @@ -676,7 +677,7 @@ D PlotBase::generate_data() const { double out_pixel = (width_[1])/static_cast(height); // size data array - D data({height, width, 2}, NOT_FOUND); + D data(width, height); // setup basis indices and initial position centered on pixel int in_i, out_i; @@ -723,7 +724,7 @@ D PlotBase::generate_data() const { j = p.n_coord_ - 1; if (level >=0) {j = level + 1;} if (found_cell) { - setter()(p, data, y, x, j); + data.set_value(y, x, p, j); Cell* c = model::cells[p.coord_[j].cell].get(); } } // inner for @@ -734,11 +735,11 @@ D PlotBase::generate_data() const { } IdData PlotBase::get_id_map() const { - return generate_data(); + return generate_data(); } PropertyData PlotBase::get_property_map() const { - return generate_data(); + return generate_data(); } //============================================================================== @@ -1070,7 +1071,7 @@ extern "C" int openmc_id_map(const void* plot, int32_t* data_out) auto ids = plt->get_id_map(); // write id data to array - std::copy(ids.begin(), ids.end(), data_out); + std::copy(ids.data.begin(), ids.data.end(), data_out); return 0; } @@ -1086,7 +1087,7 @@ extern "C" int openmc_property_map(const void* plot, double* data_out) { PropertyData props = plt->get_property_map(); // write id data to array - std::copy(props.begin(), props.end(), data_out); + std::copy(props.data.begin(), props.data.end(), data_out); return 0; } From eb95c91a2dbe1c8375b72cdc74259259275edc2c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 12 Mar 2019 18:15:04 -0500 Subject: [PATCH 074/165] Replacing plot loop in create_ppm with new get_id_map method. --- src/plot.cpp | 104 ++++++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index cbdae30d5..ccd96fde4 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -129,57 +129,69 @@ void create_ppm(Plot pl) size_t width = pl.pixels_[0]; size_t height = pl.pixels_[1]; - double in_pixel = (pl.width_[0])/static_cast(width); - double out_pixel = (pl.width_[1])/static_cast(height); + // double in_pixel = (pl.width_[0])/static_cast(width); + // double out_pixel = (pl.width_[1])/static_cast(height); - ImageData data; - data.resize({width, height}); + ImageData data({width, height}, pl.not_found_); - int in_i, out_i; - Position r; - switch(pl.basis_) { - case PlotBasis::xy : - in_i = 0; - out_i = 1; - r.x = pl.origin_[0] - pl.width_[0] / 2.; - r.y = pl.origin_[1] + pl.width_[1] / 2.; - r.z = pl.origin_[2]; - break; - case PlotBasis::xz : - in_i = 0; - out_i = 2; - r.x = pl.origin_[0] - pl.width_[0] / 2.; - r.y = pl.origin_[1]; - r.z = pl.origin_[2] + pl.width_[1] / 2.; - break; - case PlotBasis::yz : - in_i = 1; - out_i = 2; - r.x = pl.origin_[0]; - r.y = pl.origin_[1] - pl.width_[0] / 2.; - r.z = pl.origin_[2] + pl.width_[1] / 2.; - break; - } +// int in_i, out_i; +// Position r; +// switch(pl.basis_) { +// case PlotBasis::xy : +// in_i = 0; +// out_i = 1; +// r.x = pl.origin_[0] - pl.width_[0] / 2.; +// r.y = pl.origin_[1] + pl.width_[1] / 2.; +// r.z = pl.origin_[2]; +// break; +// case PlotBasis::xz : +// in_i = 0; +// out_i = 2; +// r.x = pl.origin_[0] - pl.width_[0] / 2.; +// r.y = pl.origin_[1]; +// r.z = pl.origin_[2] + pl.width_[1] / 2.; +// break; +// case PlotBasis::yz : +// in_i = 1; +// out_i = 2; +// r.x = pl.origin_[0]; +// r.y = pl.origin_[1] - pl.width_[0] / 2.; +// r.z = pl.origin_[2] + pl.width_[1] / 2.; +// break; +// } - Direction u {0.7071, 0.7071, 0.0}; +// Direction u {0.5, 0.5, 0.5}; - #pragma omp parallel - { - Particle p; - p.r() = r; - p.u() = u; - p.coord_[0].universe = model::root_universe; +// #pragma omp parallel +// { +// Particle p; +// p.r() = r; +// p.u() = u; +// p.coord_[0].universe = model::root_universe; - #pragma omp for - for (int y = 0; y < height; y++) { - p.r()[out_i] = r[out_i] - out_pixel * y; - for (int x = 0; x < width; x++) { - // local variables - RGBColor rgb; - int id; - p.r()[in_i] = r[in_i] + in_pixel * x; - position_rgb(p, pl, rgb, id); - data(x,y) = rgb; +// #pragma omp for +// for (int y = 0; y < height; y++) { +// p.r()[out_i] = r[out_i] - out_pixel * y; +// for (int x = 0; x < width; x++) { +// // local variables +// RGBColor rgb; +// int id; +// p.r()[in_i] = r[in_i] + in_pixel * x; +// position_rgb(p, pl, rgb, id); +// data(x,y) = rgb; +// } +// } +// } + + auto ids = pl.get_id_map(); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + RGBColor color; + if (PlotColorBy::cells == pl.color_by_) { + data(x,y) = pl.colors_[model::cell_map[ids.data(y,x,0)]]; + } else if (PlotColorBy::mats == pl.color_by_) { + data(x,y) = pl.colors_[model::material_map[ids.data(y,x,1)]]; } } } From 4c50cbcda8686d43da6c9b19909077ee3d97eba9 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 12 Mar 2019 20:35:21 -0500 Subject: [PATCH 075/165] Removing original loop from create_ppm. --- src/plot.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plot.cpp b/src/plot.cpp index ccd96fde4..da3bdf549 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -4,6 +4,8 @@ #include #include +#include "xtensor/xview.hpp" + #include "openmc/cell.h" #include "openmc/constants.h" #include "openmc/file_utils.h" @@ -132,7 +134,8 @@ void create_ppm(Plot pl) // double in_pixel = (pl.width_[0])/static_cast(width); // double out_pixel = (pl.width_[1])/static_cast(height); - ImageData data({width, height}, pl.not_found_); + ImageData data({width, height}); + xt::view(data, xt::all(), xt::all()) = pl.not_found_; // int in_i, out_i; // Position r; From 09258c5b79c6d66d1735a824dcdb5cfc670008c9 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 13 Mar 2019 15:19:01 -0500 Subject: [PATCH 076/165] Plots working as before using the single loop. --- include/openmc/plot.h | 4 +-- src/plot.cpp | 76 ++++++++++--------------------------------- 2 files changed, 19 insertions(+), 61 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index b879dbe36..54035fd85 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -88,8 +88,8 @@ enum class PlotBasis { }; enum class PlotColorBy { - cells = 1, - mats = 2 + cells = 0, + mats = 1 }; //=============================================================================== diff --git a/src/plot.cpp b/src/plot.cpp index da3bdf549..5e960b8d2 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -30,6 +30,7 @@ namespace openmc { const RGBColor WHITE {255, 255, 255}; constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level +constexpr int32_t VOID {-2}; constexpr int32_t NOT_FOUND {-1}; IdData::IdData(int h_res, int v_res) { @@ -40,7 +41,10 @@ void IdData::set_value(int y, int x, const Particle& p, int level) { Cell* c = model::cells[p.coord_[level].cell].get(); data(y,x,0) = c->id_; - if (c->type_ != FILL_UNIVERSE && p.material_ != MATERIAL_VOID) { + if (p.material_ == MATERIAL_VOID) { + data(y,x,1) = VOID; + return; + } else if (c->type_ != FILL_UNIVERSE) { Material* m = model::materials[p.material_].get(); data(y,x,1) = m->id_; } @@ -131,73 +135,27 @@ void create_ppm(Plot pl) size_t width = pl.pixels_[0]; size_t height = pl.pixels_[1]; - // double in_pixel = (pl.width_[0])/static_cast(width); - // double out_pixel = (pl.width_[1])/static_cast(height); - ImageData data({width, height}); xt::view(data, xt::all(), xt::all()) = pl.not_found_; -// int in_i, out_i; -// Position r; -// switch(pl.basis_) { -// case PlotBasis::xy : -// in_i = 0; -// out_i = 1; -// r.x = pl.origin_[0] - pl.width_[0] / 2.; -// r.y = pl.origin_[1] + pl.width_[1] / 2.; -// r.z = pl.origin_[2]; -// break; -// case PlotBasis::xz : -// in_i = 0; -// out_i = 2; -// r.x = pl.origin_[0] - pl.width_[0] / 2.; -// r.y = pl.origin_[1]; -// r.z = pl.origin_[2] + pl.width_[1] / 2.; -// break; -// case PlotBasis::yz : -// in_i = 1; -// out_i = 2; -// r.x = pl.origin_[0]; -// r.y = pl.origin_[1] - pl.width_[0] / 2.; -// r.z = pl.origin_[2] + pl.width_[1] / 2.; -// break; -// } - -// Direction u {0.5, 0.5, 0.5}; - -// #pragma omp parallel -// { -// Particle p; -// p.r() = r; -// p.u() = u; -// p.coord_[0].universe = model::root_universe; - -// #pragma omp for -// for (int y = 0; y < height; y++) { -// p.r()[out_i] = r[out_i] - out_pixel * y; -// for (int x = 0; x < width; x++) { -// // local variables -// RGBColor rgb; -// int id; -// p.r()[in_i] = r[in_i] + in_pixel * x; -// position_rgb(p, pl, rgb, id); -// data(x,y) = rgb; -// } -// } -// } - auto ids = pl.get_id_map(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - RGBColor color; + auto id = ids.data(y, x, pl.color_by_); + // no setting needed if not found + if (id == NOT_FOUND) { continue; } if (PlotColorBy::cells == pl.color_by_) { - data(x,y) = pl.colors_[model::cell_map[ids.data(y,x,0)]]; + data(x,y) = pl.colors_[model::cell_map[id]]; } else if (PlotColorBy::mats == pl.color_by_) { - data(x,y) = pl.colors_[model::material_map[ids.data(y,x,1)]]; - } - } - } + if (id == VOID) { + data(x,y) = WHITE; + continue; + } + data(x,y) = pl.colors_[model::material_map[id]]; + } // color_by if-else + } // x for loop + } // y for loop // draw mesh lines if present if (pl.index_meshlines_mesh_ >= 0) {draw_mesh_lines(pl, data);} From 898d1cfb7e1fcedfd55a71a6ed791fed0072faf4 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 13 Mar 2019 15:33:30 -0500 Subject: [PATCH 077/165] Using xtensor initializer constructor. --- src/plot.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index 5e960b8d2..b0731dede 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -135,11 +135,12 @@ void create_ppm(Plot pl) size_t width = pl.pixels_[0]; size_t height = pl.pixels_[1]; - ImageData data({width, height}); - xt::view(data, xt::all(), xt::all()) = pl.not_found_; + ImageData data({width, height}, pl.not_found_); + // generate ids for the plot auto ids = pl.get_id_map(); + // assign colors for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { auto id = ids.data(y, x, pl.color_by_); From 82229019af0944e7adc5113da4b1374da1fd1afd Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 13 Mar 2019 18:23:24 -0500 Subject: [PATCH 078/165] Updating plotting results now that locations are centered on pixels. --- tests/regression_tests/plot/results_true.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression_tests/plot/results_true.dat b/tests/regression_tests/plot/results_true.dat index 7f8fcc6a8..b3db3f33b 100644 --- a/tests/regression_tests/plot/results_true.dat +++ b/tests/regression_tests/plot/results_true.dat @@ -1 +1 @@ -30f435795c755b6fb28565a33c68e95415e5c09bca59f5549a6cbd2dd165bac9d90f5a599e12a5041cb927698abde562b7bac14175441c57b5c0dccd00544506 \ No newline at end of file +42839208bdd8c8db16f9eba5c755b422dd1e49a755cc4d75284f31a3c086353f0eb6bd9abed8c29816dffe988d1e1e4f0dfae5fb8ffc03521294c8262d919061 \ No newline at end of file From 68cb23a6c837f781067aa7cef57f7abad795dcee Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 16 Mar 2019 17:17:12 -0500 Subject: [PATCH 079/165] Updating property_map documentation. --- openmc/capi/plot.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index c950f278b..b686373b8 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -227,13 +227,14 @@ def property_map(plot): Parameters ---------- - plot : An openmc.capi.plot._PlotBase object describing the slice of the - model to be generated + plot : openmc.capi.plot._PlotBase + Object describing the slice of the model to be generated Returns ------- - property_map : a NumPy array with shape (vertical pixels, horizontal pixels, 2) - of OpenMC property ids with dtype float + property_map : numpy.ndarray + a NumPy array with shape (vertical pixels, horizontal pixels, 2) of + OpenMC property ids with dtype float """ prop_data = np.zeros((plot.v_res, plot.h_res, 2), From c8843d1572ed59ce0af6c064ad4dce637baeea0b Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 16 Mar 2019 17:17:40 -0500 Subject: [PATCH 080/165] Decrementing NOT_FOUND to avoid a clash with MATERIAL_VOID. --- src/plot.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index b0731dede..e1bc37657 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -30,8 +30,7 @@ namespace openmc { const RGBColor WHITE {255, 255, 255}; constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level -constexpr int32_t VOID {-2}; -constexpr int32_t NOT_FOUND {-1}; +constexpr int32_t NOT_FOUND {-2}; IdData::IdData(int h_res, int v_res) { data = xt::xtensor({v_res, h_res, 2}, NOT_FOUND); @@ -42,7 +41,7 @@ IdData::set_value(int y, int x, const Particle& p, int level) { Cell* c = model::cells[p.coord_[level].cell].get(); data(y,x,0) = c->id_; if (p.material_ == MATERIAL_VOID) { - data(y,x,1) = VOID; + data(y,x,1) = MATERIAL_VOID; return; } else if (c->type_ != FILL_UNIVERSE) { Material* m = model::materials[p.material_].get(); @@ -149,7 +148,7 @@ void create_ppm(Plot pl) if (PlotColorBy::cells == pl.color_by_) { data(x,y) = pl.colors_[model::cell_map[id]]; } else if (PlotColorBy::mats == pl.color_by_) { - if (id == VOID) { + if (id == MATERIAL_VOID) { data(x,y) = WHITE; continue; } @@ -750,7 +749,7 @@ void position_rgb(Particle p, Plot pl, RGBColor& rgb, int& id) } else if (p.material_ == MATERIAL_VOID) { // By default, color void cells white rgb = WHITE; - id = NOT_FOUND; + id = MATERIAL_VOID; } else { rgb = pl.colors_[p.material_]; id = model::materials[p.material_]->id_; @@ -1058,7 +1057,7 @@ extern "C" int openmc_property_map(const void* plot, double* data_out) { return OPENMC_E_INVALID_ARGUMENT; } - PropertyData props = plt->get_property_map(); + auto props = plt->get_property_map(); // write id data to array std::copy(props.data.begin(), props.data.end(), data_out); From 3ab8680d5eba1d754f20adc5067e19d22992e32a Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 16 Mar 2019 21:36:58 -0500 Subject: [PATCH 081/165] Updates to voxel plotting, need to investigate differences. --- include/openmc/plot.h | 2 ++ src/plot.cpp | 36 +++++++++++++-------------- tests/regression_tests/plot/plots.xml | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 54035fd85..a3b5ee4d8 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -98,6 +98,8 @@ enum class PlotColorBy { class PlotBase { public: IdData get_id_map() const; + xt::xtensor get_cell_ids() const; + PropertyData get_property_map() const; private: diff --git a/src/plot.cpp b/src/plot.cpp index e1bc37657..76af0da97 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -711,6 +711,11 @@ IdData PlotBase::get_id_map() const { return generate_data(); } +xt::xtensor PlotBase::get_cell_ids() const { + auto ids = get_id_map(); + return xt::flip(xt::view(ids.data, xt::all(), xt::all(), 0), 0); +} + PropertyData PlotBase::get_property_map() const { return generate_data(); } @@ -965,30 +970,23 @@ void create_voxel(Plot pl) int id; for (int z = 0; z < pl.pixels_[2]; z++) { pb.set_value(100.*(double)z/(double)(pl.pixels_[2]-1)); - for (int y = 0; y < pl.pixels_[1]; y++) { - for (int x = 0; x < pl.pixels_[0]; x++) { - // get voxel color - position_rgb(p, pl, rgb, id); - // write to plot data - data[y][x] = id; - // advance particle in x direction - p.r().x += vox[0]; - } - // advance particle in y direction - p.r().y += vox[1]; - p.r().x = ll[0]; - } - // advance particle in z direction - p.r().z += vox[2]; - p.r().y = ll[1]; - p.r().x = ll[0]; + PlotBase pltbase; + pltbase.width_ = pl.width_; + pltbase.origin_ = pl.origin_; + pltbase.basis_ = PlotBasis::xy; + pltbase.pixels_ = pl.pixels_; + pltbase.level_ = pl.level_; + + pl.origin_.z += ll.z + z * vox[2]; + + auto data = pltbase.get_cell_ids(); + // Write to HDF5 dataset - voxel_write_slice(z, dspace, dset, memspace, &(data[0])); + voxel_write_slice(z, dspace, dset, memspace, &(data(0,0))); } voxel_finalize(dspace, dset, memspace); file_close(file_id); - } void diff --git a/tests/regression_tests/plot/plots.xml b/tests/regression_tests/plot/plots.xml index ecfe69125..078666e75 100644 --- a/tests/regression_tests/plot/plots.xml +++ b/tests/regression_tests/plot/plots.xml @@ -24,7 +24,7 @@ - 100 100 10 + 500 500 500 0. 0. 0. 20 20 10 From d55f46f3744551d4f5bc33661edcb8ad050f6118 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 09:46:47 -0500 Subject: [PATCH 082/165] Correcting origin location. --- src/plot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot.cpp b/src/plot.cpp index 76af0da97..b8c16fefe 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -977,7 +977,7 @@ void create_voxel(Plot pl) pltbase.pixels_ = pl.pixels_; pltbase.level_ = pl.level_; - pl.origin_.z += ll.z + z * vox[2]; + pl.origin_.z = pl.origin_.z + z * vox[2]; auto data = pltbase.get_cell_ids(); From 506ecb9ee103be4a8d76179c068496d213c269c6 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 11:24:03 -0500 Subject: [PATCH 083/165] Reverting change to plots.xml. Updating z coordinate location. --- src/plot.cpp | 2 +- tests/regression_tests/plot/plots.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index b8c16fefe..9fd26f8a1 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -977,7 +977,7 @@ void create_voxel(Plot pl) pltbase.pixels_ = pl.pixels_; pltbase.level_ = pl.level_; - pl.origin_.z = pl.origin_.z + z * vox[2]; + pltbase.origin_.z = ll.z + z * vox[2]; auto data = pltbase.get_cell_ids(); diff --git a/tests/regression_tests/plot/plots.xml b/tests/regression_tests/plot/plots.xml index 078666e75..ecfe69125 100644 --- a/tests/regression_tests/plot/plots.xml +++ b/tests/regression_tests/plot/plots.xml @@ -24,7 +24,7 @@ - 500 500 500 + 100 100 10 0. 0. 0. 20 20 10 From 0270a4fe93bf8e289ffbb6578cbfebc6b6c2b527 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 11:36:17 -0500 Subject: [PATCH 084/165] Cleaning out unused variables in create_voxel. --- src/plot.cpp | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index 9fd26f8a1..585c8f43c 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -919,13 +919,6 @@ void create_voxel(Plot pl) // initial particle position Position ll = pl.origin_ - pl.width_ / 2.; - // allocate and initialize particle - Direction u {0.7071, 0.7071, 0.0}; - Particle p; - p.r() = ll; - p.u() = u; - p.coord_[0].universe = model::root_universe; - // Open binary plot file for writing std::ofstream of; std::string fname = std::string(pl.path_plot_); @@ -957,28 +950,22 @@ void create_voxel(Plot pl) hid_t dspace, dset, memspace; voxel_init(file_id, &(dims[0]), &dspace, &dset, &memspace); - // move to center of voxels - ll.x += vox[0] / 2.; - ll.y += vox[1] / 2.; - ll.z += vox[2] / 2.; - - int data[pl.pixels_[1]][pl.pixels_[0]]; + PlotBase pltbase; + pltbase.width_ = pl.width_; + pltbase.origin_ = pl.origin_; + pltbase.basis_ = PlotBasis::xy; + pltbase.pixels_ = pl.pixels_; + pltbase.level_ = -1; // all universes for voxel files ProgressBar pb; - - RGBColor rgb; - int id; for (int z = 0; z < pl.pixels_[2]; z++) { + // update progress bar pb.set_value(100.*(double)z/(double)(pl.pixels_[2]-1)); - PlotBase pltbase; - pltbase.width_ = pl.width_; - pltbase.origin_ = pl.origin_; - pltbase.basis_ = PlotBasis::xy; - pltbase.pixels_ = pl.pixels_; - pltbase.level_ = pl.level_; + // update z coordinate pltbase.origin_.z = ll.z + z * vox[2]; + // generate ids using plotbase auto data = pltbase.get_cell_ids(); // Write to HDF5 dataset From e4ab6db1a9f06c8ff58d7af1178d730eac31dd29 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 11:47:56 -0500 Subject: [PATCH 085/165] Updating plot/plot_voxel test results after change to NOT_FOUND = -2. --- tests/regression_tests/plot/results_true.dat | 2 +- tests/regression_tests/plot_voxel/results_true.dat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression_tests/plot/results_true.dat b/tests/regression_tests/plot/results_true.dat index b3db3f33b..18251e8d0 100644 --- a/tests/regression_tests/plot/results_true.dat +++ b/tests/regression_tests/plot/results_true.dat @@ -1 +1 @@ -42839208bdd8c8db16f9eba5c755b422dd1e49a755cc4d75284f31a3c086353f0eb6bd9abed8c29816dffe988d1e1e4f0dfae5fb8ffc03521294c8262d919061 \ No newline at end of file +6b3eb36488b995b42233e6b7c0164cf6c92a1823b3c91985b97fd076f86c0aad93fbdb74e70026f5f12c61a6aee52a09588171a7fd839511ee7d9efc3952beb2 \ No newline at end of file diff --git a/tests/regression_tests/plot_voxel/results_true.dat b/tests/regression_tests/plot_voxel/results_true.dat index 801621784..52222000f 100644 --- a/tests/regression_tests/plot_voxel/results_true.dat +++ b/tests/regression_tests/plot_voxel/results_true.dat @@ -1 +1 @@ -76274390783bf0fd54a63e3ee141e072e797a564935a16f22a97788bc051e33fd7160dd311f0c50e45b0b498701f6735a37fabacbf9f36903381d9e18759a684 \ No newline at end of file +ff596b17d2cd33f964a952279b824292272ab73f57ded94812286e6bce12b5c54852d5ccd1dd137fa6312101568c06510cd89f822469d6c904a17f96259e4d03 \ No newline at end of file From 9c48ee69a4dcce9983473a1e16e5cfe5f71a33a9 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 12:27:14 -0500 Subject: [PATCH 086/165] Removing now-unused function. --- include/openmc/plot.h | 2 -- src/plot.cpp | 13 +++++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index a3b5ee4d8..54035fd85 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -98,8 +98,6 @@ enum class PlotColorBy { class PlotBase { public: IdData get_id_map() const; - xt::xtensor get_cell_ids() const; - PropertyData get_property_map() const; private: diff --git a/src/plot.cpp b/src/plot.cpp index 585c8f43c..b61973d0e 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -711,11 +711,6 @@ IdData PlotBase::get_id_map() const { return generate_data(); } -xt::xtensor PlotBase::get_cell_ids() const { - auto ids = get_id_map(); - return xt::flip(xt::view(ids.data, xt::all(), xt::all(), 0), 0); -} - PropertyData PlotBase::get_property_map() const { return generate_data(); } @@ -909,7 +904,6 @@ void draw_mesh_lines(Plot pl, ImageData& data) void create_voxel(Plot pl) { - // compute voxel widths in each direction std::array vox; vox[0] = pl.width_[0]/(double)pl.pixels_[0]; @@ -966,10 +960,13 @@ void create_voxel(Plot pl) pltbase.origin_.z = ll.z + z * vox[2]; // generate ids using plotbase - auto data = pltbase.get_cell_ids(); + IdData ids = pltbase.get_id_map(); + + // select only cell ID data and flip the y-axis + xt::xtensor data1 = xt::flip(xt::view(ids.data, xt::all(), xt::all(), 0), 0); // Write to HDF5 dataset - voxel_write_slice(z, dspace, dset, memspace, &(data(0,0))); + voxel_write_slice(z, dspace, dset, memspace, &(data1(0,0))); } voxel_finalize(dspace, dset, memspace); From 45dd3ecc0601cd23f80de8ced9020eed9808db54 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 12:28:19 -0500 Subject: [PATCH 087/165] Updating some documentation. --- src/plot.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index b61973d0e..42634d358 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -893,11 +893,11 @@ void draw_mesh_lines(Plot pl, ImageData& data) // CREATE_VOXEL outputs a binary file that can be input into silomesh for 3D // geometry visualization. It works the same way as create_ppm by dragging a // particle across the geometry for the specified number of voxels. The first 3 -// int(4)'s in the binary are the number of x, y, and z voxels. The next 3 -// real(8)'s are the widths of the voxels in the x, y, and z directions. The -// next 3 real(8)'s are the x, y, and z coordinates of the lower left -// point. Finally the binary is filled with entries of four int(4)'s each. Each -// 'row' in the binary contains four int(4)'s: 3 for x,y,z position and 1 for +// int's in the binary are the number of x, y, and z voxels. The next 3 +// double's are the widths of the voxels in the x, y, and z directions. The +// next 3 double's are the x, y, and z coordinates of the lower left +// point. Finally the binary is filled with entries of four int's each. Each +// 'row' in the binary contains four int's: 3 for x,y,z position and 1 for // cell or material id. For 1 million voxels this produces a file of // approximately 15MB. // ============================================================================= From e696374a914e83ff9894ff633bb520c4c2bb9d12 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 19:26:08 -0500 Subject: [PATCH 088/165] Renaming the data attribute. --- include/openmc/plot.h | 4 ++-- src/plot.cpp | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 54035fd85..96c2f37ad 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -62,7 +62,7 @@ struct IdData { void set_value(int y, int x, const Particle& p, int level); // Members - xt::xtensor data; + xt::xtensor data_; }; struct PropertyData { @@ -73,7 +73,7 @@ struct PropertyData { void set_value(int y, int x, const Particle& p, int level); // Members - xt::xtensor data; + xt::xtensor data_; }; enum class PlotType { diff --git a/src/plot.cpp b/src/plot.cpp index 42634d358..202e8e99a 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -33,33 +33,33 @@ constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level constexpr int32_t NOT_FOUND {-2}; IdData::IdData(int h_res, int v_res) { - data = xt::xtensor({v_res, h_res, 2}, NOT_FOUND); + data_ = xt::xtensor({v_res, h_res, 2}, NOT_FOUND); } void IdData::set_value(int y, int x, const Particle& p, int level) { Cell* c = model::cells[p.coord_[level].cell].get(); - data(y,x,0) = c->id_; + data_(y,x,0) = c->id_; if (p.material_ == MATERIAL_VOID) { - data(y,x,1) = MATERIAL_VOID; + data_(y,x,1) = MATERIAL_VOID; return; } else if (c->type_ != FILL_UNIVERSE) { Material* m = model::materials[p.material_].get(); - data(y,x,1) = m->id_; + data_(y,x,1) = m->id_; } } PropertyData::PropertyData(int h_res, int v_res) { - data = xt::xtensor({v_res, h_res, 2}, NOT_FOUND); + data_ = xt::xtensor({v_res, h_res, 2}, NOT_FOUND); } void PropertyData::set_value(int y, int x, const Particle& p, int level) { Cell* c = model::cells[p.coord_[level].cell].get(); - data(y,x,0) = (p.sqrtkT_ * p.sqrtkT_) / K_BOLTZMANN; + data_(y,x,0) = (p.sqrtkT_ * p.sqrtkT_) / K_BOLTZMANN; if (c->type_ != FILL_UNIVERSE && p.material_ != MATERIAL_VOID) { Material* m = model::materials[p.material_].get(); - data(y,x,1) = m->density_gpcc_; + data_(y,x,1) = m->density_gpcc_; } } @@ -142,7 +142,7 @@ void create_ppm(Plot pl) // assign colors for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - auto id = ids.data(y, x, pl.color_by_); + auto id = ids.data_(y, x, pl.color_by_); // no setting needed if not found if (id == NOT_FOUND) { continue; } if (PlotColorBy::cells == pl.color_by_) { @@ -963,7 +963,7 @@ void create_voxel(Plot pl) IdData ids = pltbase.get_id_map(); // select only cell ID data and flip the y-axis - xt::xtensor data1 = xt::flip(xt::view(ids.data, xt::all(), xt::all(), 0), 0); + xt::xtensor data1 = xt::flip(xt::view(ids.data_, xt::all(), xt::all(), 0), 0); // Write to HDF5 dataset voxel_write_slice(z, dspace, dset, memspace, &(data1(0,0))); @@ -1026,7 +1026,7 @@ extern "C" int openmc_id_map(const void* plot, int32_t* data_out) auto ids = plt->get_id_map(); // write id data to array - std::copy(ids.data.begin(), ids.data.end(), data_out); + std::copy(ids.data_.begin(), ids.data_.end(), data_out); return 0; } @@ -1042,7 +1042,7 @@ extern "C" int openmc_property_map(const void* plot, double* data_out) { auto props = plt->get_property_map(); // write id data to array - std::copy(props.data.begin(), props.data.end(), data_out); + std::copy(props.data_.begin(), props.data_.end(), data_out); return 0; } From 2c598129dad2c58a75b48feb18dd96d51eab94eb Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 19:27:47 -0500 Subject: [PATCH 089/165] Removing position_rgb function. --- include/openmc/plot.h | 7 ------- src/plot.cpp | 47 ------------------------------------------- 2 files changed, 54 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 96c2f37ad..28e6734eb 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -162,13 +162,6 @@ void draw_mesh_lines(Plot pl, ImageData& data); //! \param[out] image data associated with the plot object void output_ppm(Plot pl, const ImageData& data); -//! Get the rgb color for a given particle position in a plot -//! \param[in] particle with position for current pixel -//! \param[in] plot object -//! \param[out] rgb color -//! \param[out] cell or material id for particle position -void position_rgb(Particle p, Plot pl, RGBColor& rgb, int& id); - //! Initialize a voxel file //! \param[in] id of an open hdf5 file //! \param[in] dimensions of the voxel file (dx, dy, dz) diff --git a/src/plot.cpp b/src/plot.cpp index 202e8e99a..edb50ed09 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -715,53 +715,6 @@ PropertyData PlotBase::get_property_map() const { return generate_data(); } -//============================================================================== -// POSITION_RGB computes the red/green/blue values for a given plot with the -// current particle's position -//============================================================================== - - -void position_rgb(Particle p, Plot pl, RGBColor& rgb, int& id) -{ - p.n_coord_ = 1; - - bool found_cell = find_cell(&p, 0); - - int j = p.n_coord_ - 1; - - if (settings::check_overlaps) {check_cell_overlap(&p);} - - // Set coordinate level if specified - if (pl.level_ >= 0) {j = pl.level_ + 1;} - - if (!found_cell) { - // If no cell, revert to default color - rgb = pl.not_found_; - id = NOT_FOUND; - } else { - if (PlotColorBy::mats == pl.color_by_) { - // Assign color based on material - const auto& c = model::cells[p.coord_[j].cell]; - if (c->type_ == FILL_UNIVERSE) { - // If we stopped on a middle universe level, treat as if not found - rgb = pl.not_found_; - id = NOT_FOUND; - } else if (p.material_ == MATERIAL_VOID) { - // By default, color void cells white - rgb = WHITE; - id = MATERIAL_VOID; - } else { - rgb = pl.colors_[p.material_]; - id = model::materials[p.material_]->id_; - } - } else if (PlotColorBy::cells == pl.color_by_) { - // Assign color based on cell - rgb = pl.colors_[p.coord_[j].cell]; - id = model::cells[p.coord_[j].cell]->id_; - } - } // endif found_cell -} - //============================================================================== // OUTPUT_PPM writes out a previously generated image to a PPM file //============================================================================== From 076dca84a26362d7d3f9385dfe01afd6dbe2c072 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 19:30:46 -0500 Subject: [PATCH 090/165] Cleaning up some numpy docstring formatting. --- openmc/capi/plot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index b686373b8..edb2e42a3 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -223,7 +223,7 @@ def id_map(plot): def property_map(plot): """ Generate a 2-D map of (cell_temperature, material_density). Used for - in-memory image generation. + in-memory image generation. Parameters ---------- @@ -233,7 +233,7 @@ def property_map(plot): Returns ------- property_map : numpy.ndarray - a NumPy array with shape (vertical pixels, horizontal pixels, 2) of + A NumPy array with shape (vertical pixels, horizontal pixels, 2) of OpenMC property ids with dtype float """ From 2d144e21acebccb563db72d3e6021fbc38b53d86 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 17 Mar 2019 19:36:34 -0500 Subject: [PATCH 091/165] Updating/adding some docstrings. --- include/openmc/plot.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 28e6734eb..08797c33b 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -51,10 +51,10 @@ struct RGBColor { uint8_t red, green, blue; }; - typedef xt::xtensor ImageData; -struct IdData { +struct IdData +{ // Constructor IdData(int h_res, int v_res); @@ -62,10 +62,11 @@ struct IdData { void set_value(int y, int x, const Particle& p, int level); // Members - xt::xtensor data_; + xt::xtensor data_; //!< 2D array of cell & material ids }; -struct PropertyData { +struct PropertyData +{ // Constructor PropertyData(int h_res, int v_res); @@ -73,7 +74,7 @@ struct PropertyData { void set_value(int y, int x, const Particle& p, int level); // Members - xt::xtensor data_; + xt::xtensor data_; //!< 2D array of temperature & density data }; enum class PlotType { @@ -95,7 +96,9 @@ enum class PlotColorBy { //=============================================================================== // Plot class //=============================================================================== -class PlotBase { +class PlotBase +{ + // Methods public: IdData get_id_map() const; PropertyData get_property_map() const; From 44654e775923a78168847aac1b7ba0aaa02e4abd Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 09:17:30 -0500 Subject: [PATCH 092/165] A couple capi.plot module fixes and an added test. --- openmc/capi/plot.py | 3 +-- tests/unit_tests/test_capi.py | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index edb2e42a3..7e429be6c 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -1,7 +1,6 @@ from ctypes import c_int, c_int32, c_double, Structure, POINTER from . import _dll -from .core import _DLLGlobal from .error import _error_handler import numpy as np @@ -31,7 +30,7 @@ class _Position(Structure): elif idx == 2: return self.z else: - raise IndexError("{} index is invalid for _Position".format(key)) + raise IndexError("{} index is invalid for _Position".format(idx)) def __setitem__(self, idx, val): if idx == 0: diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 14dac21fc..dc3812fe0 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -438,3 +438,26 @@ def test_property_map(capi_init): properties = openmc.capi.plot.property_map(s) assert np.allclose(expected_properties, properties, atol=1e-04) + + +def test_position(capi_init): + + pos = openmc.capi.plot._Position(1.0, 1.0, 1.0) + + assert pos[0] == 1.0 + assert pos[1] == 1.0 + assert pos[2] == 1.0 + + pos[0] = 1.3 + pos[1] = 1.3 + pos[2] = 1.3 + + assert pos[0] == 1.3 + assert pos[1] == 1.3 + assert pos[2] == 1.3 + + with pytest.raises(IndexError) as e: + pos[3] = 1.3 + + with pytest.raises(IndexError) as e: + pos[-1] = 1.3 From 2b1d2917f74e37907abe40a5d2b575be843a55d5 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 09:48:21 -0500 Subject: [PATCH 093/165] Addressing some comments from @promano in the PR. --- include/openmc/plot.h | 6 ++---- openmc/capi/plot.py | 16 +++++++++------- src/plot.cpp | 12 ++++++------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 08797c33b..f6f8c7ea7 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -53,8 +53,7 @@ struct RGBColor { typedef xt::xtensor ImageData; -struct IdData -{ +struct IdData { // Constructor IdData(int h_res, int v_res); @@ -65,8 +64,7 @@ struct IdData xt::xtensor data_; //!< 2D array of cell & material ids }; -struct PropertyData -{ +struct PropertyData { // Constructor PropertyData(int h_res, int v_res); diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 7e429be6c..f9873f4bd 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -214,14 +214,18 @@ def id_map(plot): """ img_data = np.zeros((plot.v_res, plot.h_res, 2), dtype=np.dtype('int32')) - _dll.openmc_id_map(POINTER(_PlotBase)(plot), - img_data.ctypes.data_as(POINTER(c_int32))) + _dll.openmc_id_map(plot, img_data.ctypes.data_as(POINTER(c_int32))) return img_data +_dll.openmc_id_map.argtypes = [POINTER(_PlotBase), POINTER(c_double)] +_dll.openmc_id_map.restype = c_int +_dll.openmc_id_map.errcheck = _error_handler + + def property_map(plot): """ - Generate a 2-D map of (cell_temperature, material_density). Used for + Generate a 2-D map of cell temperature and material density. Used for in-memory image generation. Parameters @@ -236,8 +240,6 @@ def property_map(plot): OpenMC property ids with dtype float """ - prop_data = np.zeros((plot.v_res, plot.h_res, 2), - dtype=np.dtype('float')) - _dll.openmc_property_map(POINTER(_PlotBase)(plot), - prop_data.ctypes.data_as(POINTER(c_double))) + prop_data = np.zeros((plot.v_res, plot.h_res, 2)) + _dll.openmc_property_map(plot, prop_data.ctypes.data_as(POINTER(c_double))) return prop_data diff --git a/src/plot.cpp b/src/plot.cpp index edb50ed09..9b5f5c3bc 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -32,9 +32,9 @@ const RGBColor WHITE {255, 255, 255}; constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level constexpr int32_t NOT_FOUND {-2}; -IdData::IdData(int h_res, int v_res) { - data_ = xt::xtensor({v_res, h_res, 2}, NOT_FOUND); -} +IdData::IdData(int h_res, int v_res) + : data_({v_res, h_res, 2}, NOT_FOUND) +{ } void IdData::set_value(int y, int x, const Particle& p, int level) { @@ -49,9 +49,9 @@ IdData::set_value(int y, int x, const Particle& p, int level) { } } -PropertyData::PropertyData(int h_res, int v_res) { - data_ = xt::xtensor({v_res, h_res, 2}, NOT_FOUND); -} +PropertyData::PropertyData(int h_res, int v_res) + : data_({v_res, h_res, 2}, NOT_FOUND) +{ } void PropertyData::set_value(int y, int x, const Particle& p, int level) { From 805c336597822d8c5281c5c19824ef796d12aa30 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 10:07:18 -0500 Subject: [PATCH 094/165] Updating template parameter, moving generate_dat def to header, renaming generate_data->gen_map and removing additional indirection. --- include/openmc/plot.h | 78 +++++++++++++++++++++++++++++++++++---- src/plot.cpp | 85 ++----------------------------------------- 2 files changed, 75 insertions(+), 88 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index f6f8c7ea7..2e56c9658 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -10,6 +10,8 @@ #include "hdf5.h" #include "openmc/position.h" #include "openmc/constants.h" +#include "openmc/cell.h" +#include "openmc/geometry.h" #include "openmc/particle.h" #include "openmc/xml_interface.h" @@ -96,14 +98,8 @@ enum class PlotColorBy { //=============================================================================== class PlotBase { - // Methods public: - IdData get_id_map() const; - PropertyData get_property_map() const; - - private: - template - D generate_data() const; + template T get_map() const; // Members public: @@ -114,6 +110,74 @@ class PlotBase int level_; //!< Plot universe level }; +template +T PlotBase::get_map() const { + + size_t width = pixels_[0]; + size_t height = pixels_[1]; + + // get pixel size + double in_pixel = (width_[0])/static_cast(width); + double out_pixel = (width_[1])/static_cast(height); + + // size data array + T data(width, height); + + // setup basis indices and initial position centered on pixel + int in_i, out_i; + Position xyz = origin_; + switch(basis_) { + case PlotBasis::xy : + in_i = 0; + out_i = 1; + break; + case PlotBasis::xz : + in_i = 0; + out_i = 2; + break; + case PlotBasis::yz : + in_i = 1; + out_i = 2; + break; + } + + // set initial position + xyz[in_i] = origin_[in_i] - width_[0] / 2. + in_pixel / 2.; + xyz[out_i] = origin_[out_i] + width_[1] / 2. - out_pixel / 2.; + + // arbitrary direction + Direction dir = {0.5, 0.5, 0.5}; + + #pragma omp parallel + { + Particle p; + p.r() = xyz; + p.u() = dir; + p.coord_[0].universe = model::root_universe; + int level = level_; + int j{}; + + #pragma omp for + for (int y = 0; y < height; y++) { + p.r()[out_i] = xyz[out_i] - out_pixel * y; + for (int x = 0; x < width; x++) { + p.r()[in_i] = xyz[in_i] + in_pixel * x; + p.n_coord_ = 1; + // local variables + bool found_cell = find_cell(&p, 0); + j = p.n_coord_ - 1; + if (level >=0) {j = level + 1;} + if (found_cell) { + data.set_value(y, x, p, j); + Cell* c = model::cells[p.coord_[j].cell].get(); + } + } // inner for + } // outer for + } // omp parallel + + return data; +} + class Plot : public PlotBase { diff --git a/src/plot.cpp b/src/plot.cpp index 9b5f5c3bc..0d43d1b8d 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -6,7 +6,6 @@ #include "xtensor/xview.hpp" -#include "openmc/cell.h" #include "openmc/constants.h" #include "openmc/file_utils.h" #include "openmc/geometry.h" @@ -137,7 +136,7 @@ void create_ppm(Plot pl) ImageData data({width, height}, pl.not_found_); // generate ids for the plot - auto ids = pl.get_id_map(); + auto ids = pl.get_map(); // assign colors for (int y = 0; y < height; y++) { @@ -639,82 +638,6 @@ Plot::Plot(pugi::xml_node plot_node) set_mask(plot_node); } // End Plot constructor -template -D PlotBase::generate_data() const { - - size_t width = pixels_[0]; - size_t height = pixels_[1]; - - // get pixel size - double in_pixel = (width_[0])/static_cast(width); - double out_pixel = (width_[1])/static_cast(height); - - // size data array - D data(width, height); - - // setup basis indices and initial position centered on pixel - int in_i, out_i; - Position xyz = origin_; - switch(basis_) { - case PlotBasis::xy : - in_i = 0; - out_i = 1; - break; - case PlotBasis::xz : - in_i = 0; - out_i = 2; - break; - case PlotBasis::yz : - in_i = 1; - out_i = 2; - break; - } - - // set initial position - xyz[in_i] = origin_[in_i] - width_[0] / 2. + in_pixel / 2.; - xyz[out_i] = origin_[out_i] + width_[1] / 2. - out_pixel / 2.; - - // arbitrary direction - Direction dir = {0.5, 0.5, 0.5}; - -#pragma omp parallel -{ - Particle p; - p.r() = xyz; - p.u() = dir; - p.coord_[0].universe = model::root_universe; - int level = level_; - int j{}; - - #pragma omp for - for (int y = 0; y < height; y++) { - p.r()[out_i] = xyz[out_i] - out_pixel * y; - for (int x = 0; x < width; x++) { - p.r()[in_i] = xyz[in_i] + in_pixel * x; - p.n_coord_ = 1; - // local variables - bool found_cell = find_cell(&p, 0); - j = p.n_coord_ - 1; - if (level >=0) {j = level + 1;} - if (found_cell) { - data.set_value(y, x, p, j); - Cell* c = model::cells[p.coord_[j].cell].get(); - } - } // inner for - } // outer for - } // omp parallel - - return data; -} - -IdData PlotBase::get_id_map() const { - return generate_data(); -} - -PropertyData PlotBase::get_property_map() const { - return generate_data(); -} - //============================================================================== // OUTPUT_PPM writes out a previously generated image to a PPM file //============================================================================== @@ -913,7 +836,7 @@ void create_voxel(Plot pl) pltbase.origin_.z = ll.z + z * vox[2]; // generate ids using plotbase - IdData ids = pltbase.get_id_map(); + IdData ids = pltbase.get_map(); // select only cell ID data and flip the y-axis xt::xtensor data1 = xt::flip(xt::view(ids.data_, xt::all(), xt::all(), 0), 0); @@ -976,7 +899,7 @@ extern "C" int openmc_id_map(const void* plot, int32_t* data_out) return OPENMC_E_INVALID_ARGUMENT; } - auto ids = plt->get_id_map(); + auto ids = plt->get_map(); // write id data to array std::copy(ids.data_.begin(), ids.data_.end(), data_out); @@ -992,7 +915,7 @@ extern "C" int openmc_property_map(const void* plot, double* data_out) { return OPENMC_E_INVALID_ARGUMENT; } - auto props = plt->get_property_map(); + auto props = plt->get_map(); // write id data to array std::copy(props.data_.begin(), props.data_.end(), data_out); From 378268bb37b6ec3a6aa49a0ca8a2ff0ba3c270cf Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 10:09:28 -0500 Subject: [PATCH 095/165] Lassoing stars. --- include/openmc/capi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 617153b6c..8815d243a 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -70,8 +70,8 @@ extern "C" { int openmc_next_batch(int* status); int openmc_nuclide_name(int index, const char** name); int openmc_plot_geometry(); - int openmc_id_map(const void* slice, int32_t *data_out); - int openmc_property_map(const void* slice, double *data_out); + int openmc_id_map(const void* slice, int32_t* data_out); + int openmc_property_map(const void* slice, double* data_out); int openmc_reset(); int openmc_run(); void openmc_set_seed(int64_t new_seed); From 190c8aa71241de2ee48d5f1feb7514590198a087 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 10:30:45 -0500 Subject: [PATCH 096/165] Fixing dll definitions for openmc_property_map. --- openmc/capi/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index f9873f4bd..44c7ad383 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -218,9 +218,9 @@ def id_map(plot): return img_data -_dll.openmc_id_map.argtypes = [POINTER(_PlotBase), POINTER(c_double)] -_dll.openmc_id_map.restype = c_int -_dll.openmc_id_map.errcheck = _error_handler +_dll.openmc_property_map.argtypes = [POINTER(_PlotBase), POINTER(c_double)] +_dll.openmc_property_map.restype = c_int +_dll.openmc_property_map.errcheck = _error_handler def property_map(plot): From 656df47365fca097daf88cb6237cd3d8bd1a7cc7 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 14:16:56 -0500 Subject: [PATCH 097/165] Addressing a couple style issues. --- include/openmc/plot.h | 10 ++++------ openmc/capi/plot.py | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 2e56c9658..91ac9ec20 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -96,13 +96,12 @@ enum class PlotColorBy { //=============================================================================== // Plot class //=============================================================================== -class PlotBase -{ - public: +class PlotBase { +public: template T get_map() const; // Members - public: +public: Position origin_; //!< Plot origin in geometry Position width_; //!< Plot width in geometry PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) @@ -178,8 +177,7 @@ T PlotBase::get_map() const { return data; } -class Plot : public PlotBase -{ +class Plot : public PlotBase { public: // Constructor diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 44c7ad383..766ff95dc 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -197,7 +197,7 @@ _dll.openmc_id_map.errcheck = _error_handler def id_map(plot): """ - Generate a 2-D map of (cell_id, material_id). Used for in-memory image + Generate a 2-D map of cell and material IDs. Used for in-memory image generation. Parameters @@ -225,7 +225,7 @@ _dll.openmc_property_map.errcheck = _error_handler def property_map(plot): """ - Generate a 2-D map of cell temperature and material density. Used for + Generate a 2-D map of cell temperatures and material densities. Used for in-memory image generation. Parameters From 2e2ec4a4121b1fa12754b9f3393b804710161597 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 14:47:44 -0500 Subject: [PATCH 098/165] Addressing narrowing warning. --- include/openmc/plot.h | 6 +++--- src/plot.cpp | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 91ac9ec20..12f5cfab9 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -57,7 +57,7 @@ typedef xt::xtensor ImageData; struct IdData { // Constructor - IdData(int h_res, int v_res); + IdData(size_t h_res, size_t v_res); // Methods void set_value(int y, int x, const Particle& p, int level); @@ -68,7 +68,7 @@ struct IdData { struct PropertyData { // Constructor - PropertyData(int h_res, int v_res); + PropertyData(size_t h_res, size_t v_res); // Methods void set_value(int y, int x, const Particle& p, int level); @@ -105,7 +105,7 @@ public: Position origin_; //!< Plot origin in geometry Position width_; //!< Plot width in geometry PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) - std::array pixels_; //!< Plot size in pixels + std::array pixels_; //!< Plot size in pixels int level_; //!< Plot universe level }; diff --git a/src/plot.cpp b/src/plot.cpp index 0d43d1b8d..ba769d611 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -31,7 +31,7 @@ const RGBColor WHITE {255, 255, 255}; constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level constexpr int32_t NOT_FOUND {-2}; -IdData::IdData(int h_res, int v_res) +IdData::IdData(size_t h_res, size_t v_res) : data_({v_res, h_res, 2}, NOT_FOUND) { } @@ -48,7 +48,7 @@ IdData::set_value(int y, int x, const Particle& p, int level) { } } -PropertyData::PropertyData(int h_res, int v_res) +PropertyData::PropertyData(size_t h_res, size_t v_res) : data_({v_res, h_res, 2}, NOT_FOUND) { } @@ -807,7 +807,9 @@ void create_voxel(Plot pl) // Write current date and time write_attribute(file_id, "date_and_time", time_stamp().c_str()); hsize_t three = 3; - write_attribute(file_id, "num_voxels", pl.pixels_); + std::array pixels; + std::copy(pl.pixels_.begin(), pl.pixels_.end(), pixels.begin()); + write_attribute(file_id, "num_voxels", pixels); write_attribute(file_id, "voxel_width", vox); write_attribute(file_id, "lower_left", ll); From f6192dfc9e2037a2621f5bffc5f00b92f1020256 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 15:14:47 -0500 Subject: [PATCH 099/165] Updates to mirror changes in pixels_ type in plot.cpp. --- openmc/capi/plot.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openmc/capi/plot.py b/openmc/capi/plot.py index 766ff95dc..9ff398f5c 100644 --- a/openmc/capi/plot.py +++ b/openmc/capi/plot.py @@ -1,4 +1,4 @@ -from ctypes import c_int, c_int32, c_double, Structure, POINTER +from ctypes import c_int, c_size_t, c_int32, c_double, Structure, POINTER from . import _dll from .error import _error_handler @@ -57,7 +57,7 @@ class _PlotBase(Structure): The width of the plot along the x, y, and z axes, respectively basis_ : c_int The axes basis of the plot view. - pixels_ : c_int[3] + pixels_ : c_size_t[3] The resolution of the plot in the horizontal and vertical dimensions level_ : c_int The universe level for the plot view @@ -73,9 +73,9 @@ class _PlotBase(Structure): basis : string One of {'xy', 'xz', 'yz'} indicating the horizontal and vertical axes of the plot. - h_res : float + h_res : int The horizontal resolution of the plot in pixels - v_res : float + v_res : int The vertical resolution of the plot in pixels level : int The universe level for the plot (default: -1 -> all universes shown) @@ -83,7 +83,7 @@ class _PlotBase(Structure): _fields_ = [('origin_', _Position), ('width_', _Position), ('basis_', c_int), - ('pixels_', 3*c_int), + ('pixels_', 3*c_size_t), ('level_', c_int)] def __init__(self): From abd417c5f6835a28d11bd9950f112f3a854d052d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 18 Mar 2019 15:38:25 -0500 Subject: [PATCH 100/165] Updating other signatures to match new pixels_ type. --- include/openmc/plot.h | 4 ++-- src/plot.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 12f5cfab9..73bcd1d36 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -60,7 +60,7 @@ struct IdData { IdData(size_t h_res, size_t v_res); // Methods - void set_value(int y, int x, const Particle& p, int level); + void set_value(size_t y, size_t x, const Particle& p, int level); // Members xt::xtensor data_; //!< 2D array of cell & material ids @@ -71,7 +71,7 @@ struct PropertyData { PropertyData(size_t h_res, size_t v_res); // Methods - void set_value(int y, int x, const Particle& p, int level); + void set_value(size_t y, size_t x, const Particle& p, int level); // Members xt::xtensor data_; //!< 2D array of temperature & density data diff --git a/src/plot.cpp b/src/plot.cpp index ba769d611..02fb42d76 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -36,7 +36,7 @@ IdData::IdData(size_t h_res, size_t v_res) { } void -IdData::set_value(int y, int x, const Particle& p, int level) { +IdData::set_value(size_t y, size_t x, const Particle& p, int level) { Cell* c = model::cells[p.coord_[level].cell].get(); data_(y,x,0) = c->id_; if (p.material_ == MATERIAL_VOID) { @@ -53,7 +53,7 @@ PropertyData::PropertyData(size_t h_res, size_t v_res) { } void -PropertyData::set_value(int y, int x, const Particle& p, int level) { +PropertyData::set_value(size_t y, size_t x, const Particle& p, int level) { Cell* c = model::cells[p.coord_[level].cell].get(); data_(y,x,0) = (p.sqrtkT_ * p.sqrtkT_) / K_BOLTZMANN; if (c->type_ != FILL_UNIVERSE && p.material_ != MATERIAL_VOID) { @@ -139,8 +139,8 @@ void create_ppm(Plot pl) auto ids = pl.get_map(); // assign colors - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { + for (size_t y = 0; y < height; y++) { + for (size_t x = 0; x < width; x++) { auto id = ids.data_(y, x, pl.color_by_); // no setting needed if not found if (id == NOT_FOUND) { continue; } From 43914d42049724f0841ff5818fda005f475a1ecd Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 19 Mar 2019 08:41:11 -0500 Subject: [PATCH 101/165] Re-correcting direction and updating _Position tests. --- include/openmc/plot.h | 2 +- tests/unit_tests/test_capi.py | 20 +++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 73bcd1d36..2752add9c 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -145,7 +145,7 @@ T PlotBase::get_map() const { xyz[out_i] = origin_[out_i] + width_[1] / 2. - out_pixel / 2.; // arbitrary direction - Direction dir = {0.5, 0.5, 0.5}; + Direction dir = {0.7071, 0.7071, 0.0}; #pragma omp parallel { diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index dc3812fe0..be88072d9 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -442,22 +442,12 @@ def test_property_map(capi_init): def test_position(capi_init): - pos = openmc.capi.plot._Position(1.0, 1.0, 1.0) + pos = openmc.capi.plot._Position(1.0, 2.0, 3.0) - assert pos[0] == 1.0 - assert pos[1] == 1.0 - assert pos[2] == 1.0 + assert tuple(pos) == (1.0, 2.0, 3.0) pos[0] = 1.3 - pos[1] = 1.3 - pos[2] = 1.3 + pos[1] = 2.3 + pos[2] = 3.3 - assert pos[0] == 1.3 - assert pos[1] == 1.3 - assert pos[2] == 1.3 - - with pytest.raises(IndexError) as e: - pos[3] = 1.3 - - with pytest.raises(IndexError) as e: - pos[-1] = 1.3 + assert tuple(pos) == (1.3, 2.3, 3.3) From 8a8b7b2c0ac9d6c0896cfae560a65476e8cd4df9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 18 Mar 2019 09:12:37 -0500 Subject: [PATCH 102/165] Move cross section caches into Particle class --- include/openmc/material.h | 6 +- include/openmc/nuclide.h | 82 +--------- include/openmc/particle.h | 202 ++++++++++++++++++------- include/openmc/photon.h | 23 +-- include/openmc/physics.h | 11 +- include/openmc/tallies/tally_scoring.h | 6 +- include/openmc/thermal.h | 2 +- src/material.cpp | 49 +++--- src/nuclide.cpp | 124 ++++++++------- src/particle.cpp | 30 ++-- src/particle_restart.cpp | 14 -- src/photon.cpp | 12 +- src/physics.cpp | 111 +++++++------- src/physics_mg.cpp | 18 +-- src/simulation.cpp | 14 -- src/tallies/derivative.cpp | 142 ++++++++--------- src/tallies/tally_scoring.cpp | 184 +++++++++++----------- 17 files changed, 495 insertions(+), 535 deletions(-) diff --git a/include/openmc/material.h b/include/openmc/material.h index 932945ffc..3109f6d78 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -47,7 +47,7 @@ public: explicit Material(pugi::xml_node material_node); // Methods - void calculate_xs(const Particle& p) const; + void calculate_xs(Particle& p) const; //! Assign thermal scattering tables to specific nuclides within the material //! so the code knows when to apply bound thermal scattering data @@ -104,8 +104,8 @@ private: //! Normalize density void normalize_density(); - void calculate_neutron_xs(const Particle& p) const; - void calculate_photon_xs(const Particle& p) const; + void calculate_neutron_xs(Particle& p) const; + void calculate_photon_xs(Particle& p) const; }; //============================================================================== diff --git a/include/openmc/nuclide.h b/include/openmc/nuclide.h index c8b34d08e..4be898a64 100644 --- a/include/openmc/nuclide.h +++ b/include/openmc/nuclide.h @@ -13,6 +13,7 @@ #include "openmc/constants.h" #include "openmc/endf.h" +#include "openmc/particle.h" #include "openmc/reaction.h" #include "openmc/reaction_product.h" #include "openmc/urr.h" @@ -20,69 +21,6 @@ namespace openmc { -//============================================================================== -// Constants -//============================================================================== - -constexpr double CACHE_INVALID {-1.0}; - -//============================================================================== -//! Cached microscopic cross sections for a particular nuclide at the current -//! energy -//============================================================================== - -struct NuclideMicroXS { - // Microscopic cross sections in barns - double total; //!< total cross section - double absorption; //!< absorption (disappearance) - double fission; //!< fission - double nu_fission; //!< neutron production from fission - - double elastic; //!< If sab_frac is not 1 or 0, then this value is - //!< averaged over bound and non-bound nuclei - double thermal; //!< Bound thermal elastic & inelastic scattering - double thermal_elastic; //!< Bound thermal elastic scattering - double photon_prod; //!< microscopic photon production xs - - // Cross sections for depletion reactions (note that these are not stored in - // macroscopic cache) - double reaction[DEPLETION_RX.size()]; - - // Indicies and factors needed to compute cross sections from the data tables - int index_grid; //!< Index on nuclide energy grid - int index_temp; //!< Temperature index for nuclide - double interp_factor; //!< Interpolation factor on nuc. energy grid - int index_sab {-1}; //!< Index in sab_tables - int index_temp_sab; //!< Temperature index for sab_tables - double sab_frac; //!< Fraction of atoms affected by S(a,b) - bool use_ptable; //!< In URR range with probability tables? - - // Energy and temperature last used to evaluate these cross sections. If - // these values have changed, then the cross sections must be re-evaluated. - double last_E {0.0}; //!< Last evaluated energy - double last_sqrtkT {0.0}; //!< Last temperature in sqrt(Boltzmann constant - //!< * temperature (eV)) -}; - -//============================================================================== -// MATERIALMACROXS contains cached macroscopic cross sections for the material a -// particle is traveling through -//============================================================================== - -struct MaterialMacroXS { - double total; //!< macroscopic total xs - double absorption; //!< macroscopic absorption xs - double fission; //!< macroscopic fission xs - double nu_fission; //!< macroscopic production xs - double photon_prod; //!< macroscopic photon production xs - - // Photon cross sections - double coherent; //!< macroscopic coherent xs - double incoherent; //!< macroscopic incoherent xs - double photoelectric; //!< macroscopic photoelectric xs - double pair_production; //!< macroscopic pair production xs -}; - //============================================================================== // Data for a nuclide //============================================================================== @@ -102,14 +40,13 @@ public: //! Initialize logarithmic grid for energy searches void init_grid(); - void calculate_xs(int i_sab, double E, int i_log_union, - double sqrtkT, double sab_frac); + void calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle& p); - void calculate_sab_xs(int i_sab, double E, double sqrtkT, double sab_frac); + void calculate_sab_xs(int i_sab, double sab_frac, Particle& p); // Methods double nu(double E, EmissionMode mode, int group=0) const; - void calculate_elastic_xs() const; + void calculate_elastic_xs(Particle& p) const; //! Determines the microscopic 0K elastic cross section at a trial relative //! energy used in resonance scattering @@ -117,7 +54,7 @@ public: //! \brief Determines cross sections in the unresolved resonance range //! from probability tables. - void calculate_urr_xs(int i_temp, double E) const; + void calculate_urr_xs(int i_temp, Particle& p) const; // Data members std::string name_; //!< Name of nuclide, e.g. "U235" @@ -194,15 +131,6 @@ extern std::unordered_map nuclide_map; } // namespace data -namespace simulation { - -// Cross section caches -extern NuclideMicroXS* micro_xs; -extern MaterialMacroXS material_xs; -#pragma omp threadprivate(micro_xs, material_xs) - -} // namespace simulation - //============================================================================== // Non-member functions //============================================================================== diff --git a/include/openmc/particle.h b/include/openmc/particle.h index 2cb30a44f..e971c30da 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -6,9 +6,11 @@ #include #include +#include // for unique_ptr #include #include +#include "openmc/constants.h" #include "openmc/position.h" namespace openmc { @@ -33,6 +35,8 @@ constexpr int MAX_LOST_PARTICLES {10}; // Maximum number of lost particles, relative to the total number of particles constexpr double REL_MAX_LOST_PARTICLES {1.0e-6}; +constexpr double CACHE_INVALID {-1.0}; + //============================================================================== // Class declarations //============================================================================== @@ -52,12 +56,88 @@ struct LocalCoord { void reset(); }; +//============================================================================== +//! Cached microscopic cross sections for a particular nuclide at the current +//! energy +//============================================================================== + +struct NuclideMicroXS { + // Microscopic cross sections in barns + double total; //!< total cross section + double absorption; //!< absorption (disappearance) + double fission; //!< fission + double nu_fission; //!< neutron production from fission + + double elastic; //!< If sab_frac is not 1 or 0, then this value is + //!< averaged over bound and non-bound nuclei + double thermal; //!< Bound thermal elastic & inelastic scattering + double thermal_elastic; //!< Bound thermal elastic scattering + double photon_prod; //!< microscopic photon production xs + + // Cross sections for depletion reactions (note that these are not stored in + // macroscopic cache) + double reaction[DEPLETION_RX.size()]; + + // Indicies and factors needed to compute cross sections from the data tables + int index_grid; //!< Index on nuclide energy grid + int index_temp; //!< Temperature index for nuclide + double interp_factor; //!< Interpolation factor on nuc. energy grid + int index_sab {-1}; //!< Index in sab_tables + int index_temp_sab; //!< Temperature index for sab_tables + double sab_frac; //!< Fraction of atoms affected by S(a,b) + bool use_ptable; //!< In URR range with probability tables? + + // Energy and temperature last used to evaluate these cross sections. If + // these values have changed, then the cross sections must be re-evaluated. + double last_E {0.0}; //!< Last evaluated energy + double last_sqrtkT {0.0}; //!< Last temperature in sqrt(Boltzmann constant + //!< * temperature (eV)) +}; + +//============================================================================== +//! Cached microscopic photon cross sections for a particular element at the +//! current energy +//============================================================================== + +struct ElementMicroXS { + int index_grid; //!< index on element energy grid + double last_E {0.0}; //!< last evaluated energy in [eV] + double interp_factor; //!< interpolation factor on energy grid + double total; //!< microscopic total photon xs + double coherent; //!< microscopic coherent xs + double incoherent; //!< microscopic incoherent xs + double photoelectric; //!< microscopic photoelectric xs + double pair_production; //!< microscopic pair production xs +}; + +//============================================================================== +// MATERIALMACROXS contains cached macroscopic cross sections for the material a +// particle is traveling through +//============================================================================== + +struct MaterialMacroXS { + double total; //!< macroscopic total xs + double absorption; //!< macroscopic absorption xs + double fission; //!< macroscopic fission xs + double nu_fission; //!< macroscopic production xs + double photon_prod; //!< macroscopic photon production xs + + // Photon cross sections + double coherent; //!< macroscopic coherent xs + double incoherent; //!< macroscopic incoherent xs + double photoelectric; //!< macroscopic photoelectric xs + double pair_production; //!< macroscopic pair production xs +}; + //============================================================================ //! State of a particle being transported through geometry //============================================================================ class Particle { public: + //========================================================================== + // Aliases and type definitions + //! Particle types enum class Type { neutron, photon, electron, positron @@ -73,9 +153,76 @@ public: Type particle; }; + //========================================================================== // Constructors + Particle(); + //========================================================================== + // Methods and accessors + + // Accessors for position in global coordinates + Position& r() { return coord_[0].r; } + const Position& r() const { return coord_[0].r; } + + // Accessors for position in local coordinates + Position& r_local() { return coord_[n_coord_ - 1].r; } + const Position& r_local() const { return coord_[n_coord_ - 1].r; } + + // Accessors for direction in global coordinates + Direction& u() { return coord_[0].u; } + const Direction& u() const { return coord_[0].u; } + + // Accessors for direction in local coordinates + Direction& u_local() { return coord_[n_coord_ - 1].u; } + const Direction& u_local() const { return coord_[n_coord_ - 1].u; } + + //! resets all coordinate levels for the particle + void clear(); + + //! create a secondary particle + // + //! stores the current phase space attributes of the particle in the + //! secondary bank and increments the number of sites in the secondary bank. + //! \param u Direction of the secondary particle + //! \param E Energy of the secondary particle in [eV] + //! \param type Particle type + void create_secondary(Direction u, double E, Type type); + + //! initialize from a source site + // + //! initializes a particle from data stored in a source site. The source + //! site may have been produced from an external source, from fission, or + //! simply as a secondary particle. + //! \param src Source site data + void from_source(const Bank* src); + + //! Transport a particle from birth to death + void transport(); + + //! Cross a surface and handle boundary conditions + void cross_surface(); + + //! mark a particle as lost and create a particle restart file + //! \param message A warning message to display + void mark_as_lost(const char* message); + + void mark_as_lost(const std::string& message) + {mark_as_lost(message.c_str());} + + void mark_as_lost(const std::stringstream& message) + {mark_as_lost(message.str());} + + //! create a particle restart HDF5 file + void write_restart() const; + + //========================================================================== + // Data members + + std::vector micro_xs_; + std::vector micro_photon_xs_; + MaterialMacroXS material_xs_; + int64_t id_; //!< Unique ID Type type_ {Type::neutron}; //!< Particle type (n, p, e, etc.) @@ -139,61 +286,6 @@ public: // Secondary particles created int64_t n_secondary_ {}; Bank secondary_bank_[MAX_SECONDARY]; - - // Accessors for position in global coordinates - Position& r() { return coord_[0].r; } - const Position& r() const { return coord_[0].r; } - - // Accessors for position in local coordinates - Position& r_local() { return coord_[n_coord_ - 1].r; } - const Position& r_local() const { return coord_[n_coord_ - 1].r; } - - // Accessors for direction in global coordinates - Direction& u() { return coord_[0].u; } - const Direction& u() const { return coord_[0].u; } - - // Accessors for direction in local coordinates - Direction& u_local() { return coord_[n_coord_ - 1].u; } - const Direction& u_local() const { return coord_[n_coord_ - 1].u; } - - //! resets all coordinate levels for the particle - void clear(); - - //! create a secondary particle - // - //! stores the current phase space attributes of the particle in the - //! secondary bank and increments the number of sites in the secondary bank. - //! \param u Direction of the secondary particle - //! \param E Energy of the secondary particle in [eV] - //! \param type Particle type - void create_secondary(Direction u, double E, Type type); - - //! initialize from a source site - // - //! initializes a particle from data stored in a source site. The source - //! site may have been produced from an external source, from fission, or - //! simply as a secondary particle. - //! \param src Source site data - void from_source(const Bank* src); - - //! Transport a particle from birth to death - void transport(); - - //! Cross a surface and handle boundary conditions - void cross_surface(); - - //! mark a particle as lost and create a particle restart file - //! \param message A warning message to display - void mark_as_lost(const char* message); - - void mark_as_lost(const std::string& message) - {mark_as_lost(message.c_str());} - - void mark_as_lost(const std::stringstream& message) - {mark_as_lost(message.str());} - - //! create a particle restart HDF5 file - void write_restart() const; }; } // namespace openmc diff --git a/include/openmc/photon.h b/include/openmc/photon.h index 7c20a716d..902d24232 100644 --- a/include/openmc/photon.h +++ b/include/openmc/photon.h @@ -42,7 +42,7 @@ public: PhotonInteraction(hid_t group, int i_element); // Methods - void calculate_xs(double E) const; + void calculate_xs(Particle& p) const; void compton_scatter(double alpha, bool doppler, double* alpha_out, double* mu, int* i_shell) const; @@ -98,22 +98,6 @@ private: void compton_doppler(double alpha, double mu, double* E_out, int* i_shell) const; }; -//============================================================================== -//! Cached microscopic photon cross sections for a particular element at the -//! current energy -//============================================================================== - -struct ElementMicroXS { - int index_grid; //!< index on element energy grid - double last_E {0.0}; //!< last evaluated energy in [eV] - double interp_factor; //!< interpolation factor on energy grid - double total; //!< microscopic total photon xs - double coherent; //!< microscopic coherent xs - double incoherent; //!< microscopic incoherent xs - double photoelectric; //!< microscopic photoelectric xs - double pair_production; //!< microscopic pair production xs -}; - //============================================================================== // Non-member functions //============================================================================== @@ -136,11 +120,6 @@ extern std::unordered_map element_map; } // namespace data -namespace simulation { -extern ElementMicroXS* micro_photon_xs; -#pragma omp threadprivate(micro_photon_xs) -} // namespace simulation - } // namespace openmc #endif // OPENMC_PHOTON_H diff --git a/include/openmc/physics.h b/include/openmc/physics.h index a7dd20aad..5c8d64f5f 100644 --- a/include/openmc/physics.h +++ b/include/openmc/physics.h @@ -51,20 +51,19 @@ void create_fission_sites(Particle* p, int i_nuclide, const Reaction* rx, int sample_element(Particle* p); -Reaction* sample_fission(int i_nuclide, double E); +Reaction* sample_fission(int i_nuclide, const Particle* p); -void sample_photon_product(int i_nuclide, double E, int* i_rx, int* i_product); +void sample_photon_product(int i_nuclide, const Particle* p, int* i_rx, int* i_product); void absorption(Particle* p, int i_nuclide); void scatter(Particle*, int i_nuclide); //! Treats the elastic scattering of a neutron with a target. -void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, double& E, - Direction& u, double& mu_lab); +void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, + Particle* p); -void sab_scatter(int i_nuclide, int i_sab, double& E, - Direction& u, double& mu); +void sab_scatter(int i_nuclide, int i_sab, Particle* p); //! samples the target velocity. The constant cross section free gas model is //! the default method. Methods for correctly accounting for the energy diff --git a/include/openmc/tallies/tally_scoring.h b/include/openmc/tallies/tally_scoring.h index af03b1aa2..2c5a29c17 100644 --- a/include/openmc/tallies/tally_scoring.h +++ b/include/openmc/tallies/tally_scoring.h @@ -59,14 +59,14 @@ private: //! since collisions do not occur in voids. // //! \param p The particle being tracked -void score_collision_tally(const Particle* p); +void score_collision_tally(Particle* p); //! Score tallies based on a simple count of events (for continuous energy). // //! Analog tallies are triggered at every collision, not every event. // //! \param p The particle being tracked -void score_analog_tally_ce(const Particle* p); +void score_analog_tally_ce(Particle* p); //! Score tallies based on a simple count of events (for multigroup). // @@ -83,7 +83,7 @@ void score_analog_tally_mg(const Particle* p); // //! \param p The particle being tracked //! \param distance The distance in [cm] traveled by the particle -void score_tracklength_tally(const Particle* p, double distance); +void score_tracklength_tally(Particle* p, double distance); //! Score surface or mesh-surface tallies for particle currents. // diff --git a/include/openmc/thermal.h b/include/openmc/thermal.h index 624cf31bd..b737f005b 100644 --- a/include/openmc/thermal.h +++ b/include/openmc/thermal.h @@ -10,7 +10,7 @@ #include "xtensor/xtensor.hpp" #include "openmc/hdf5_interface.h" -#include "openmc/nuclide.h" +#include "openmc/particle.h" namespace openmc { diff --git a/src/material.cpp b/src/material.cpp index da68a536d..0d2fe4bbc 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -729,13 +729,13 @@ void Material::init_nuclide_index() } } -void Material::calculate_xs(const Particle& p) const +void Material::calculate_xs(Particle& p) const { // Set all material macroscopic cross sections to zero - simulation::material_xs.total = 0.0; - simulation::material_xs.absorption = 0.0; - simulation::material_xs.fission = 0.0; - simulation::material_xs.nu_fission = 0.0; + p.material_xs_.total = 0.0; + p.material_xs_.absorption = 0.0; + p.material_xs_.fission = 0.0; + p.material_xs_.nu_fission = 0.0; if (p.type_ == Particle::Type::neutron) { this->calculate_neutron_xs(p); @@ -744,7 +744,7 @@ void Material::calculate_xs(const Particle& p) const } } -void Material::calculate_neutron_xs(const Particle& p) const +void Material::calculate_neutron_xs(Particle& p) const { // Find energy index on energy grid int neutron = static_cast(Particle::Type::neutron); @@ -792,13 +792,12 @@ void Material::calculate_neutron_xs(const Particle& p) const int i_nuclide = nuclide_[i]; // Calculate microscopic cross section for this nuclide - const auto& micro {simulation::micro_xs[i_nuclide]}; + const auto& micro {p.micro_xs_[i_nuclide]}; if (p.E_ != micro.last_E || p.sqrtkT_ != micro.last_sqrtkT || i_sab != micro.index_sab || sab_frac != micro.sab_frac) { - data::nuclides[i_nuclide]->calculate_xs(i_sab, p.E_, i_grid, - p.sqrtkT_, sab_frac); + data::nuclides[i_nuclide]->calculate_xs(i_sab, i_grid, sab_frac, p); } // ====================================================================== @@ -808,19 +807,19 @@ void Material::calculate_neutron_xs(const Particle& p) const double atom_density = atom_density_(i); // Add contributions to cross sections - simulation::material_xs.total += atom_density * micro.total; - simulation::material_xs.absorption += atom_density * micro.absorption; - simulation::material_xs.fission += atom_density * micro.fission; - simulation::material_xs.nu_fission += atom_density * micro.nu_fission; + p.material_xs_.total += atom_density * micro.total; + p.material_xs_.absorption += atom_density * micro.absorption; + p.material_xs_.fission += atom_density * micro.fission; + p.material_xs_.nu_fission += atom_density * micro.nu_fission; } } -void Material::calculate_photon_xs(const Particle& p) const +void Material::calculate_photon_xs(Particle& p) const { - simulation::material_xs.coherent = 0.0; - simulation::material_xs.incoherent = 0.0; - simulation::material_xs.photoelectric = 0.0; - simulation::material_xs.pair_production = 0.0; + p.material_xs_.coherent = 0.0; + p.material_xs_.incoherent = 0.0; + p.material_xs_.photoelectric = 0.0; + p.material_xs_.pair_production = 0.0; // Add contribution from each nuclide in material for (int i = 0; i < nuclide_.size(); ++i) { @@ -831,9 +830,9 @@ void Material::calculate_photon_xs(const Particle& p) const int i_element = element_[i]; // Calculate microscopic cross section for this nuclide - const auto& micro {simulation::micro_photon_xs[i_element]}; + const auto& micro {p.micro_photon_xs_[i_element]}; if (p.E_ != micro.last_E) { - data::elements[i_element].calculate_xs(p.E_); + data::elements[i_element].calculate_xs(p); } // ======================================================================== @@ -843,11 +842,11 @@ void Material::calculate_photon_xs(const Particle& p) const double atom_density = atom_density_(i); // Add contributions to material macroscopic cross sections - simulation::material_xs.total += atom_density * micro.total; - simulation::material_xs.coherent += atom_density * micro.coherent; - simulation::material_xs.incoherent += atom_density * micro.incoherent; - simulation::material_xs.photoelectric += atom_density * micro.photoelectric; - simulation::material_xs.pair_production += atom_density * micro.pair_production; + p.material_xs_.total += atom_density * micro.total; + p.material_xs_.coherent += atom_density * micro.coherent; + p.material_xs_.incoherent += atom_density * micro.incoherent; + p.material_xs_.photoelectric += atom_density * micro.photoelectric; + p.material_xs_.pair_production += atom_density * micro.pair_production; } } diff --git a/src/nuclide.cpp b/src/nuclide.cpp index cd2461186..87965dfc3 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -34,11 +34,6 @@ std::vector> nuclides; std::unordered_map nuclide_map; } // namespace data -namespace simulation { -NuclideMicroXS* micro_xs; -MaterialMacroXS material_xs; -} // namespace simulation - //============================================================================== // Nuclide implementation //============================================================================== @@ -461,10 +456,10 @@ double Nuclide::nu(double E, EmissionMode mode, int group) const } } -void Nuclide::calculate_elastic_xs() const +void Nuclide::calculate_elastic_xs(Particle& p) const { // Get temperature index, grid index, and interpolation factor - auto& micro = simulation::micro_xs[i_nuclide_]; + auto& micro {p.micro_xs_[i_nuclide_]}; int i_temp = micro.index_temp; int i_grid = micro.index_grid; double f = micro.interp_factor; @@ -498,42 +493,41 @@ double Nuclide::elastic_xs_0K(double E) const return (1.0 - f)*elastic_0K_[i_grid] + f*elastic_0K_[i_grid + 1]; } -void Nuclide::calculate_xs(int i_sab, double E, int i_log_union, - double sqrtkT, double sab_frac) +void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle& p) { - auto& micro_xs = simulation::micro_xs[i_nuclide_]; + auto& micro {p.micro_xs_[i_nuclide_]}; // Initialize cached cross sections to zero - micro_xs.elastic = CACHE_INVALID; - micro_xs.thermal = 0.0; - micro_xs.thermal_elastic = 0.0; + micro.elastic = CACHE_INVALID; + micro.thermal = 0.0; + micro.thermal_elastic = 0.0; // Check to see if there is multipole data present at this energy bool use_mp = false; if (multipole_) { - use_mp = (E >= multipole_->E_min_ && E <= multipole_->E_max_); + use_mp = (p.E_ >= multipole_->E_min_ && p.E_ <= multipole_->E_max_); } // Evaluate multipole or interpolate if (use_mp) { // Call multipole kernel double sig_s, sig_a, sig_f; - std::tie(sig_s, sig_a, sig_f) = multipole_->evaluate(E, sqrtkT); + std::tie(sig_s, sig_a, sig_f) = multipole_->evaluate(p.E_, p.sqrtkT_); - micro_xs.total = sig_s + sig_a; - micro_xs.elastic = sig_s; - micro_xs.absorption = sig_a; - micro_xs.fission = sig_f; - micro_xs.nu_fission = fissionable_ ? - sig_f * this->nu(E, EmissionMode::total) : 0.0; + micro.total = sig_s + sig_a; + micro.elastic = sig_s; + micro.absorption = sig_a; + micro.fission = sig_f; + micro.nu_fission = fissionable_ ? + sig_f * this->nu(p.E_, EmissionMode::total) : 0.0; if (simulation::need_depletion_rx) { // Only non-zero reaction is (n,gamma) - micro_xs.reaction[0] = sig_a - sig_f; + micro.reaction[0] = sig_a - sig_f; // Set all other reaction cross sections to zero for (int i = 1; i < DEPLETION_RX.size(); ++i) { - micro_xs.reaction[i] = 0.0; + micro.reaction[i] = 0.0; } } @@ -547,13 +541,13 @@ void Nuclide::calculate_xs(int i_sab, double E, int i_log_union, // resonance range, so the value here does not matter. index_temp is // set to -1 to force a segfault in case a developer messes up and tries // to use it with multipole. - micro_xs.index_temp = -1; - micro_xs.index_grid = -1; - micro_xs.interp_factor = 0.0; + micro.index_temp = -1; + micro.index_grid = -1; + micro.interp_factor = 0.0; } else { // Find the appropriate temperature index. - double kT = sqrtkT*sqrtkT; + double kT = p.sqrtkT_*p.sqrtkT_; double f; int i_temp = -1; switch (settings::temperature_method) { @@ -590,9 +584,9 @@ void Nuclide::calculate_xs(int i_sab, double E, int i_log_union, const auto& xs {xs_[i_temp]}; int i_grid; - if (E < grid.energy.front()) { + if (p.E_ < grid.energy.front()) { i_grid = 0; - } else if (E > grid.energy.back()) { + } else if (p.E_ > grid.energy.back()) { i_grid = grid.energy.size() - 2; } else { // Determine bounding indices based on which equal log-spaced @@ -601,49 +595,49 @@ void Nuclide::calculate_xs(int i_sab, double E, int i_log_union, int i_high = grid.grid_index[i_log_union + 1] + 1; // Perform binary search over reduced range - i_grid = i_low + lower_bound_index(&grid.energy[i_low], &grid.energy[i_high], E); + i_grid = i_low + lower_bound_index(&grid.energy[i_low], &grid.energy[i_high], p.E_); } // check for rare case where two energy points are the same if (grid.energy[i_grid] == grid.energy[i_grid + 1]) ++i_grid; // calculate interpolation factor - f = (E - grid.energy[i_grid]) / + f = (p.E_ - grid.energy[i_grid]) / (grid.energy[i_grid + 1]- grid.energy[i_grid]); - micro_xs.index_temp = i_temp; - micro_xs.index_grid = i_grid; - micro_xs.interp_factor = f; + micro.index_temp = i_temp; + micro.index_grid = i_grid; + micro.interp_factor = f; // Calculate microscopic nuclide total cross section - micro_xs.total = (1.0 - f)*xs(i_grid, XS_TOTAL) + micro.total = (1.0 - f)*xs(i_grid, XS_TOTAL) + f*xs(i_grid + 1, XS_TOTAL); // Calculate microscopic nuclide absorption cross section - micro_xs.absorption = (1.0 - f)*xs(i_grid, XS_ABSORPTION) + micro.absorption = (1.0 - f)*xs(i_grid, XS_ABSORPTION) + f*xs(i_grid + 1, XS_ABSORPTION); if (fissionable_) { // Calculate microscopic nuclide total cross section - micro_xs.fission = (1.0 - f)*xs(i_grid, XS_FISSION) + micro.fission = (1.0 - f)*xs(i_grid, XS_FISSION) + f*xs(i_grid + 1, XS_FISSION); // Calculate microscopic nuclide nu-fission cross section - micro_xs.nu_fission = (1.0 - f)*xs(i_grid, XS_NU_FISSION) + micro.nu_fission = (1.0 - f)*xs(i_grid, XS_NU_FISSION) + f*xs(i_grid + 1, XS_NU_FISSION); } else { - micro_xs.fission = 0.0; - micro_xs.nu_fission = 0.0; + micro.fission = 0.0; + micro.nu_fission = 0.0; } // Calculate microscopic nuclide photon production cross section - micro_xs.photon_prod = (1.0 - f)*xs(i_grid, XS_PHOTON_PROD) + micro.photon_prod = (1.0 - f)*xs(i_grid, XS_PHOTON_PROD) + f*xs(i_grid + 1, XS_PHOTON_PROD); // Depletion-related reactions if (simulation::need_depletion_rx) { // Initialize all reaction cross sections to zero - for (double& xs_i : micro_xs.reaction) { + for (double& xs_i : micro.reaction) { xs_i = 0.0; } @@ -658,14 +652,14 @@ void Nuclide::calculate_xs(int i_sab, double E, int i_log_union, // Physics says that (n,gamma) is not a threshold reaction, so we don't // need to specifically check its threshold index if (j == 0) { - micro_xs.reaction[0] = (1.0 - f)*rx_xs[i_grid] + micro.reaction[0] = (1.0 - f)*rx_xs[i_grid] + f*rx_xs[i_grid + 1]; continue; } int threshold = rx->xs_[i_temp].threshold; if (i_grid >= threshold) { - micro_xs.reaction[j] = (1.0 - f)*rx_xs[i_grid - threshold] + + micro.reaction[j] = (1.0 - f)*rx_xs[i_grid - threshold] + f*rx_xs[i_grid - threshold + 1]; } else if (j >= 3) { // One can show that the the threshold for (n,(x+1)n) is always @@ -680,35 +674,35 @@ void Nuclide::calculate_xs(int i_sab, double E, int i_log_union, } // Initialize sab treatment to false - micro_xs.index_sab = C_NONE; - micro_xs.sab_frac = 0.0; + micro.index_sab = C_NONE; + micro.sab_frac = 0.0; // Initialize URR probability table treatment to false - micro_xs.use_ptable = false; + micro.use_ptable = false; // If there is S(a,b) data for this nuclide, we need to set the sab_scatter // and sab_elastic cross sections and correct the total and elastic cross // sections. - if (i_sab >= 0) this->calculate_sab_xs(i_sab, E, sqrtkT, sab_frac); + if (i_sab >= 0) this->calculate_sab_xs(i_sab, sab_frac, p); // If the particle is in the unresolved resonance range and there are // probability tables, we need to determine cross sections from the table if (settings::urr_ptables_on && urr_present_ && !use_mp) { - int n = urr_data_[micro_xs.index_temp].n_energy_; - if ((E > urr_data_[micro_xs.index_temp].energy_(0)) && - (E < urr_data_[micro_xs.index_temp].energy_(n-1))) { - this->calculate_urr_xs(micro_xs.index_temp, E); + int n = urr_data_[micro.index_temp].n_energy_; + if ((p.E_ > urr_data_[micro.index_temp].energy_(0)) && + (p.E_ < urr_data_[micro.index_temp].energy_(n-1))) { + this->calculate_urr_xs(micro.index_temp, p); } } - micro_xs.last_E = E; - micro_xs.last_sqrtkT = sqrtkT; + micro.last_E = p.E_; + micro.last_sqrtkT = p.sqrtkT_; } -void Nuclide::calculate_sab_xs(int i_sab, double E, double sqrtkT, double sab_frac) +void Nuclide::calculate_sab_xs(int i_sab, double sab_frac, Particle& p) { - auto& micro {simulation::micro_xs[i_nuclide_]}; + auto& micro {p.micro_xs_[i_nuclide_]}; // Set flag that S(a,b) treatment should be used for scattering micro.index_sab = i_sab; @@ -717,14 +711,14 @@ void Nuclide::calculate_sab_xs(int i_sab, double E, double sqrtkT, double sab_fr int i_temp; double elastic; double inelastic; - data::thermal_scatt[i_sab]->calculate_xs(E, sqrtkT, &i_temp, &elastic, &inelastic); + data::thermal_scatt[i_sab]->calculate_xs(p.E_, p.sqrtkT_, &i_temp, &elastic, &inelastic); // Store the S(a,b) cross sections. micro.thermal = sab_frac * (elastic + inelastic); micro.thermal_elastic = sab_frac * elastic; // Calculate free atom elastic cross section - this->calculate_elastic_xs(); + this->calculate_elastic_xs(p); // Correct total and elastic cross sections micro.total = micro.total + micro.thermal - sab_frac*micro.elastic; @@ -735,9 +729,9 @@ void Nuclide::calculate_sab_xs(int i_sab, double E, double sqrtkT, double sab_fr micro.sab_frac = sab_frac; } -void Nuclide::calculate_urr_xs(int i_temp, double E) const +void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const { - auto& micro = simulation::micro_xs[i_nuclide_]; + auto& micro = p.micro_xs_[i_nuclide_]; micro.use_ptable = true; // Create a shorthand for the URR data @@ -745,7 +739,7 @@ void Nuclide::calculate_urr_xs(int i_temp, double E) const // Determine the energy table int i_energy = 0; - while (E >= urr.energy_(i_energy + 1)) {++i_energy;}; + while (p.E_ >= urr.energy_(i_energy + 1)) {++i_energy;}; // Sample the probability table using the cumulative distribution @@ -773,7 +767,7 @@ void Nuclide::calculate_urr_xs(int i_temp, double E) const double f; if (urr.interp_ == Interpolation::lin_lin) { // Determine the interpolation factor on the table - f = (E - urr.energy_(i_energy)) / + f = (p.E_ - urr.energy_(i_energy)) / (urr.energy_(i_energy + 1) - urr.energy_(i_energy)); elastic = (1. - f) * urr.prob_(i_energy, URR_ELASTIC, i_low) + @@ -784,7 +778,7 @@ void Nuclide::calculate_urr_xs(int i_temp, double E) const f * urr.prob_(i_energy + 1, URR_N_GAMMA, i_up); } else if (urr.interp_ == Interpolation::log_log) { // Determine interpolation factor on the table - f = std::log(E / urr.energy_(i_energy)) / + f = std::log(p.E_ / urr.energy_(i_energy)) / std::log(urr.energy_(i_energy + 1) / urr.energy_(i_energy)); // Calculate the elastic cross section/factor @@ -838,7 +832,7 @@ void Nuclide::calculate_urr_xs(int i_temp, double E) const // Multiply by smooth cross-section if needed if (urr.multiply_smooth_) { - calculate_elastic_xs(); + calculate_elastic_xs(p); elastic *= micro.elastic; capture *= (micro.absorption - micro.fission); fission *= micro.fission; @@ -858,7 +852,7 @@ void Nuclide::calculate_urr_xs(int i_temp, double E) const // Determine nu-fission cross-section if (fissionable_) { - micro.nu_fission = nu(E, EmissionMode::total) * micro.fission; + micro.nu_fission = nu(p.E_, EmissionMode::total) * micro.fission; } } diff --git a/src/particle.cpp b/src/particle.cpp index ca7fccfe7..f5084cd1c 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -15,6 +15,7 @@ #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" +#include "openmc/photon.h" #include "openmc/physics.h" #include "openmc/physics_mg.h" #include "openmc/random_lcg.h" @@ -55,6 +56,10 @@ Particle::Particle() for (int& n : n_delayed_bank_) { n = 0; } + + // Create microscopic cross section caches + micro_xs_.resize(data::nuclides.size()); + micro_photon_xs_.resize(data::elements.size()); } void @@ -130,9 +135,7 @@ Particle::transport() // Force calculation of cross-sections by setting last energy to zero if (settings::run_CE) { - for (int i = 0; i < data::nuclides.size(); ++i) { - simulation::micro_xs[i].last_E = 0.0; - } + for (auto& micro : micro_xs_) micro.last_E = 0.0; } // Prepare to write out particle track. @@ -186,18 +189,17 @@ Particle::transport() } else { // Get the MG data calculate_xs_c(material_, g_, sqrtkT_, this->u_local(), - simulation::material_xs.total, simulation::material_xs.absorption, - simulation::material_xs.nu_fission); + material_xs_.total, material_xs_.absorption, material_xs_.nu_fission); // Finally, update the particle group while we have already checked // for if multi-group g_last_ = g_; } } else { - simulation::material_xs.total = 0.0; - simulation::material_xs.absorption = 0.0; - simulation::material_xs.fission = 0.0; - simulation::material_xs.nu_fission = 0.0; + material_xs_.total = 0.0; + material_xs_.absorption = 0.0; + material_xs_.fission = 0.0; + material_xs_.nu_fission = 0.0; } // Find the distance to the nearest boundary @@ -213,10 +215,10 @@ Particle::transport() if (type_ == Particle::Type::electron || type_ == Particle::Type::positron) { d_collision = 0.0; - } else if (simulation::material_xs.total == 0.0) { + } else if (material_xs_.total == 0.0) { d_collision = INFINITY; } else { - d_collision = -std::log(prn()) / simulation::material_xs.total; + d_collision = -std::log(prn()) / material_xs_.total; } // Select smaller of the two distances @@ -235,7 +237,7 @@ Particle::transport() // Score track-length estimate of k-eff if (settings::run_mode == RUN_MODE_EIGENVALUE && type_ == Particle::Type::neutron) { - global_tally_tracklength += wgt_ * distance * simulation::material_xs.nu_fission; + global_tally_tracklength += wgt_ * distance * material_xs_.nu_fission; } // Score flux derivative accumulators for differential tallies. @@ -278,8 +280,8 @@ Particle::transport() // Score collision estimate of keff if (settings::run_mode == RUN_MODE_EIGENVALUE && type_ == Particle::Type::neutron) { - global_tally_collision += wgt_ * simulation::material_xs.nu_fission - / simulation::material_xs.total; + global_tally_collision += wgt_ * material_xs_.nu_fission + / material_xs_.total; } // Score surface current tallies -- this has to be done before the collision diff --git a/src/particle_restart.cpp b/src/particle_restart.cpp index 0cface319..0bc677cfd 100644 --- a/src/particle_restart.cpp +++ b/src/particle_restart.cpp @@ -71,13 +71,6 @@ void run_particle_restart() // Set verbosity high settings::verbosity = 10; - // Create cross section caches - #pragma omp parallel - { - simulation::micro_xs = new NuclideMicroXS[data::nuclides.size()]; - simulation::micro_photon_xs = new ElementMicroXS[data::elements.size()]; - } - // Initialize the particle to be tracked Particle p; @@ -105,13 +98,6 @@ void run_particle_restart() // Write output if particle made it print_particle(&p); - - // Clear cross section caches - #pragma omp parallel - { - delete[] simulation::micro_xs; - delete[] simulation::micro_photon_xs; - } } } // namespace openmc diff --git a/src/photon.cpp b/src/photon.cpp index d977d62ac..9841e9e3b 100644 --- a/src/photon.cpp +++ b/src/photon.cpp @@ -32,10 +32,6 @@ std::unordered_map element_map; } // namespace data -namespace simulation { -ElementMicroXS* micro_photon_xs; -} // namespace simulation - //============================================================================== // PhotonInteraction implementation //============================================================================== @@ -433,12 +429,12 @@ void PhotonInteraction::compton_doppler(double alpha, double mu, *i_shell = shell; } -void PhotonInteraction::calculate_xs(double E) const +void PhotonInteraction::calculate_xs(Particle& p) const { // Perform binary search on the element energy grid in order to determine // which points to interpolate between int n_grid = energy_.size(); - double log_E = std::log(E); + double log_E = std::log(p.E_); int i_grid; if (log_E <= energy_[0]) { i_grid = 0; @@ -456,7 +452,7 @@ void PhotonInteraction::calculate_xs(double E) const // calculate interpolation factor double f = (log_E - energy_(i_grid)) / (energy_(i_grid+1) - energy_(i_grid)); - auto& xs {simulation::micro_photon_xs[i_element_]}; + auto& xs {p.micro_photon_xs_[i_element_]}; xs.index_grid = i_grid; xs.interp_factor = f; @@ -490,7 +486,7 @@ void PhotonInteraction::calculate_xs(double E) const // Calculate microscopic total cross section xs.total = xs.coherent + xs.incoherent + xs.photoelectric + xs.pair_production; - xs.last_E = E; + xs.last_E = p.E_; } double PhotonInteraction::rayleigh_scatter(double alpha) const diff --git a/src/physics.cpp b/src/physics.cpp index 858aae8f4..029ab18c8 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -89,7 +89,7 @@ void sample_neutron_reaction(Particle* p) const auto& nuc {data::nuclides[i_nuclide]}; if (nuc->fissionable_) { - Reaction* rx = sample_fission(i_nuclide, p->E_); + Reaction* rx = sample_fission(i_nuclide, p); if (settings::run_mode == RUN_MODE_EIGENVALUE) { create_fission_sites(p, i_nuclide, rx, simulation::fission_bank.data(), &simulation::n_bank, simulation::fission_bank.size()); @@ -110,7 +110,7 @@ void sample_neutron_reaction(Particle* p) // If survival biasing is being used, the following subroutine adjusts the // weight of the particle. Otherwise, it checks to see if absorption occurs - if (simulation::micro_xs[i_nuclide].absorption > 0.0) { + if (p->micro_xs_[i_nuclide].absorption > 0.0) { absorption(p, i_nuclide); } else { p->wgt_absorb_ = 0.0; @@ -146,8 +146,8 @@ create_fission_sites(Particle* p, int i_nuclide, const Reaction* rx, double weight = settings::ufs_on ? ufs_get_weight(p) : 1.0; // Determine the expected number of neutrons produced - double nu_t = p->wgt_ / simulation::keff * weight * simulation::micro_xs[ - i_nuclide].nu_fission / simulation::micro_xs[i_nuclide].total; + double nu_t = p->wgt_ / simulation::keff * weight * p->micro_xs_[ + i_nuclide].nu_fission / p->micro_xs_[i_nuclide].total; // Sample the number of neutrons produced int nu = static_cast(nu_t); @@ -227,7 +227,7 @@ void sample_photon_reaction(Particle* p) // Sample element within material int i_element = sample_element(p); p->event_nuclide_ = i_element; - const auto& micro {simulation::micro_photon_xs[i_element]}; + const auto& micro {p->micro_photon_xs_[i_element]}; const auto& element {data::elements[i_element]}; // Calculate photon energy over electron rest mass equivalent @@ -408,7 +408,7 @@ void sample_positron_reaction(Particle* p) int sample_nuclide(const Particle* p) { // Sample cumulative distribution function - double cutoff = prn() * simulation::material_xs.total; + double cutoff = prn() * p->material_xs_.total; // Get pointers to nuclide/density arrays const auto& mat {model::materials[p->material_]}; @@ -421,7 +421,7 @@ int sample_nuclide(const Particle* p) double atom_density = mat->atom_density_[i]; // Increment probability to compare to cutoff - prob += atom_density * simulation::micro_xs[i_nuclide].total; + prob += atom_density * p->micro_xs_[i_nuclide].total; if (prob >= cutoff) return i_nuclide; } @@ -433,7 +433,7 @@ int sample_nuclide(const Particle* p) int sample_element(Particle* p) { // Sample cumulative distribution function - double cutoff = prn() * simulation::material_xs.total; + double cutoff = prn() * p->material_xs_.total; // Get pointers to elements, densities const auto& mat {model::materials[p->material_]}; @@ -454,7 +454,7 @@ int sample_element(Particle* p) double atom_density = mat->atom_density_[i]; // Determine microscopic cross section - double sigma = atom_density * simulation::micro_photon_xs[i_element].total; + double sigma = atom_density * p->micro_photon_xs_[i_element].total; // Increment probability to compare to cutoff prob += sigma; @@ -464,7 +464,7 @@ int sample_element(Particle* p) return i_element; } -Reaction* sample_fission(int i_nuclide, double E) +Reaction* sample_fission(int i_nuclide, const Particle* p) { // Get pointer to nuclide const auto& nuc {data::nuclides[i_nuclide]}; @@ -472,23 +472,23 @@ Reaction* sample_fission(int i_nuclide, double E) // If we're in the URR, by default use the first fission reaction. We also // default to the first reaction if we know that there are no partial fission // reactions - if (simulation::micro_xs[i_nuclide].use_ptable || !nuc->has_partial_fission_) { + if (p->micro_xs_[i_nuclide].use_ptable || !nuc->has_partial_fission_) { return nuc->fission_rx_[0]; } // Check to see if we are in a windowed multipole range. WMP only supports // the first fission reaction. if (nuc->multipole_) { - if (E >= nuc->multipole_->E_min_ && E <= nuc->multipole_->E_max_) { + if (p->E_ >= nuc->multipole_->E_min_ && p->E_ <= nuc->multipole_->E_max_) { return nuc->fission_rx_[0]; } } // Get grid index and interpolatoin factor and sample fission cdf - int i_temp = simulation::micro_xs[i_nuclide].index_temp; - int i_grid = simulation::micro_xs[i_nuclide].index_grid; - double f = simulation::micro_xs[i_nuclide].interp_factor; - double cutoff = prn() * simulation::micro_xs[i_nuclide].fission; + int i_temp = p->micro_xs_[i_nuclide].index_temp; + int i_grid = p->micro_xs_[i_nuclide].index_grid; + double f = p->micro_xs_[i_nuclide].interp_factor; + double cutoff = prn() * p->micro_xs_[i_nuclide].fission; double prob = 0.0; // Loop through each partial fission reaction type @@ -509,13 +509,13 @@ Reaction* sample_fission(int i_nuclide, double E) throw std::runtime_error{"No fission reaction was sampled for " + nuc->name_}; } -void sample_photon_product(int i_nuclide, double E, int* i_rx, int* i_product) +void sample_photon_product(int i_nuclide, const Particle* p, int* i_rx, int* i_product) { // Get grid index and interpolation factor and sample photon production cdf - int i_temp = simulation::micro_xs[i_nuclide].index_temp; - int i_grid = simulation::micro_xs[i_nuclide].index_grid; - double f = simulation::micro_xs[i_nuclide].interp_factor; - double cutoff = prn() * simulation::micro_xs[i_nuclide].photon_prod; + int i_temp = p->micro_xs_[i_nuclide].index_temp; + int i_grid = p->micro_xs_[i_nuclide].index_grid; + double f = p->micro_xs_[i_nuclide].interp_factor; + double cutoff = prn() * p->micro_xs_[i_nuclide].photon_prod; double prob = 0.0; // Loop through each reaction type @@ -534,7 +534,7 @@ void sample_photon_product(int i_nuclide, double E, int* i_rx, int* i_product) for (int j = 0; j < rx->products_.size(); ++j) { if (rx->products_[j].particle_ == Particle::Type::photon) { // add to cumulative probability - prob += (*rx->products_[j].yield_)(E) * xs; + prob += (*rx->products_[j].yield_)(p->E_) * xs; *i_rx = i; *i_product = j; @@ -548,8 +548,8 @@ void absorption(Particle* p, int i_nuclide) { if (settings::survival_biasing) { // Determine weight absorbed in survival biasing - p->wgt_absorb_ = p->wgt_ * simulation::micro_xs[i_nuclide].absorption / - simulation::micro_xs[i_nuclide].total; + p->wgt_absorb_ = p->wgt_ * p->micro_xs_[i_nuclide].absorption / + p->micro_xs_[i_nuclide].total; // Adjust weight of particle by probability of absorption p->wgt_ -= p->wgt_absorb_; @@ -557,17 +557,17 @@ void absorption(Particle* p, int i_nuclide) // Score implicit absorption estimate of keff if (settings::run_mode == RUN_MODE_EIGENVALUE) { - global_tally_absorption += p->wgt_absorb_ * simulation::micro_xs[ - i_nuclide].nu_fission / simulation::micro_xs[i_nuclide].absorption; + global_tally_absorption += p->wgt_absorb_ * p->micro_xs_[ + i_nuclide].nu_fission / p->micro_xs_[i_nuclide].absorption; } } else { // See if disappearance reaction happens - if (simulation::micro_xs[i_nuclide].absorption > - prn() * simulation::micro_xs[i_nuclide].total) { + if (p->micro_xs_[i_nuclide].absorption > + prn() * p->micro_xs_[i_nuclide].total) { // Score absorption estimate of keff if (settings::run_mode == RUN_MODE_EIGENVALUE) { - global_tally_absorption += p->wgt_ * simulation::micro_xs[ - i_nuclide].nu_fission / simulation::micro_xs[i_nuclide].absorption; + global_tally_absorption += p->wgt_ * p->micro_xs_[ + i_nuclide].nu_fission / p->micro_xs_[i_nuclide].absorption; } p->alive_ = false; @@ -584,7 +584,7 @@ void scatter(Particle* p, int i_nuclide) // Get pointer to nuclide and grid index/interpolation factor const auto& nuc {data::nuclides[i_nuclide]}; - const auto& micro {simulation::micro_xs[i_nuclide]}; + const auto& micro {p->micro_xs_[i_nuclide]}; int i_temp = micro.index_temp; int i_grid = micro.index_grid; double f = micro.interp_factor; @@ -596,7 +596,7 @@ void scatter(Particle* p, int i_nuclide) // Calculate elastic cross section if it wasn't precalculated if (micro.elastic == CACHE_INVALID) { - nuc->calculate_elastic_xs(); + nuc->calculate_elastic_xs(*p); } double prob = micro.elastic - micro.thermal; @@ -608,8 +608,7 @@ void scatter(Particle* p, int i_nuclide) double kT = nuc->multipole_ ? p->sqrtkT_*p->sqrtkT_ : nuc->kTs_[i_temp]; // Perform collision physics for elastic scattering - elastic_scatter(i_nuclide, *nuc->reactions_[0], kT, - p->E_, p->u(), p->mu_); + elastic_scatter(i_nuclide, *nuc->reactions_[0], kT, p); p->event_mt_ = ELASTIC; sampled = true; @@ -620,7 +619,7 @@ void scatter(Particle* p, int i_nuclide) // ======================================================================= // S(A,B) SCATTERING - sab_scatter(i_nuclide, micro.index_sab, p->E_, p->u(), p->mu_); + sab_scatter(i_nuclide, micro.index_sab, p); p->event_mt_ = ELASTIC; sampled = true; @@ -678,23 +677,23 @@ void scatter(Particle* p, int i_nuclide) } } -void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, double& E, - Direction& u, double& mu_lab) +void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, + Particle* p) { // get pointer to nuclide const auto& nuc {data::nuclides[i_nuclide]}; - double vel = std::sqrt(E); + double vel = std::sqrt(p->E_); double awr = nuc->awr_; // Neutron velocity in LAB - Direction v_n = vel*u; + Direction v_n = vel*p->u(); // Sample velocity of target nucleus Direction v_t {}; - if (!simulation::micro_xs[i_nuclide].use_ptable) { - v_t = sample_target_velocity(nuc.get(), E, u, v_n, - simulation::micro_xs[i_nuclide].elastic, kT); + if (!p->micro_xs_[i_nuclide].use_ptable) { + v_t = sample_target_velocity(nuc.get(), p->E_, p->u(), v_n, + p->micro_xs_[i_nuclide].elastic, kT); } // Velocity of center-of-mass @@ -712,7 +711,7 @@ void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, double& E, auto& d = rx.products_[0].distribution_[0]; auto d_ = dynamic_cast(d.get()); if (d_) { - mu_cm = d_->angle().sample(E); + mu_cm = d_->angle().sample(p->E_); } else { mu_cm = 2.0*prn() - 1.0; } @@ -728,35 +727,35 @@ void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, double& E, // Transform back to LAB frame v_n += v_cm; - E = v_n.dot(v_n); - vel = std::sqrt(E); + p->E_ = v_n.dot(v_n); + vel = std::sqrt(p->E_); // compute cosine of scattering angle in LAB frame by taking dot product of // neutron's pre- and post-collision angle - mu_lab = u.dot(v_n) / vel; + p->mu_ = p->u().dot(v_n) / vel; // Set energy and direction of particle in LAB frame - u = v_n / vel; + p->u() = v_n / vel; // Because of floating-point roundoff, it may be possible for mu_lab to be // outside of the range [-1,1). In these cases, we just set mu_lab to exactly // -1 or 1 - if (std::abs(mu_lab) > 1.0) mu_lab = std::copysign(1.0, mu_lab); + if (std::abs(p->mu_) > 1.0) p->mu_ = std::copysign(1.0, p->mu_); } -void sab_scatter(int i_nuclide, int i_sab, double& E, Direction& u, double& mu) +void sab_scatter(int i_nuclide, int i_sab, Particle* p) { // Determine temperature index - const auto& micro {simulation::micro_xs[i_nuclide]}; + const auto& micro {p->micro_xs_[i_nuclide]}; int i_temp = micro.index_temp_sab; // Sample energy and angle double E_out; - data::thermal_scatt[i_sab]->data_[i_temp].sample(micro, E, &E_out, &mu); + data::thermal_scatt[i_sab]->data_[i_temp].sample(micro, p->E_, &E_out, &p->mu_); // Set energy to outgoing, change direction of particle - E = E_out; - u = rotate_angle(u, mu, nullptr); + p->E_ = E_out; + p->u() = rotate_angle(p->u(), p->mu_, nullptr); } Direction sample_target_velocity(const Nuclide* nuc, double E, Direction u, @@ -1105,8 +1104,8 @@ void inelastic_scatter(const Nuclide* nuc, const Reaction* rx, Particle* p) void sample_secondary_photons(Particle* p, int i_nuclide) { // Sample the number of photons produced - double y_t = p->wgt_ * simulation::micro_xs[i_nuclide].photon_prod / - simulation::micro_xs[i_nuclide].total; + double y_t = p->wgt_ * p->micro_xs_[i_nuclide].photon_prod / + p->micro_xs_[i_nuclide].total; int y = static_cast(y_t); if (prn() <= y_t - y) ++y; @@ -1115,7 +1114,7 @@ void sample_secondary_photons(Particle* p, int i_nuclide) // Sample the reaction and product int i_rx; int i_product; - sample_photon_product(i_nuclide, p->E_, &i_rx, &i_product); + sample_photon_product(i_nuclide, p, &i_rx, &i_product); // Sample the outgoing energy and angle auto& rx = data::nuclides[i_nuclide]->reactions_[i_rx]; diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index fa6365a3a..9565a627c 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -60,7 +60,7 @@ sample_reaction(Particle* p) // If survival biasing is being used, the following subroutine adjusts the // weight of the particle. Otherwise, it checks to see if absorption occurs. - if (simulation::material_xs.absorption > 0.) { + if (p->material_xs_.absorption > 0.) { absorption(p); } else { p->wgt_absorb_ = 0.; @@ -113,7 +113,7 @@ create_fission_sites(Particle* p, Particle::Bank* bank_array, int64_t* size_bank // Determine the expected number of neutrons produced double nu_t = p->wgt_ / simulation::keff * weight * - simulation::material_xs.nu_fission / simulation::material_xs.total; + p->material_xs_.nu_fission / p->material_xs_.total; // Sample the number of neutrons produced int nu = static_cast(nu_t); @@ -204,7 +204,7 @@ absorption(Particle* p) if (settings::survival_biasing) { // Determine weight absorbed in survival biasing p->wgt_absorb_ = p->wgt_ * - simulation::material_xs.absorption / simulation::material_xs.total; + p->material_xs_.absorption / p->material_xs_.total; // Adjust weight of particle by the probability of absorption p->wgt_ -= p->wgt_absorb_; @@ -213,14 +213,14 @@ absorption(Particle* p) // Score implicit absorpion estimate of keff #pragma omp atomic global_tally_absorption += p->wgt_absorb_ * - simulation::material_xs.nu_fission / - simulation::material_xs.absorption; + p->material_xs_.nu_fission / + p->material_xs_.absorption; } else { - if (simulation::material_xs.absorption > - prn() * simulation::material_xs.total) { + if (p->material_xs_.absorption > + prn() * p->material_xs_.total) { #pragma omp atomic - global_tally_absorption += p->wgt_ * simulation::material_xs.nu_fission / - simulation::material_xs.absorption; + global_tally_absorption += p->wgt_ * p->material_xs_.nu_fission / + p->material_xs_.absorption; p->alive_ = false; p->event_ = EVENT_ABSORB; } diff --git a/src/simulation.cpp b/src/simulation.cpp index 7d30ccea9..b4db5e0e6 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -78,13 +78,6 @@ int openmc_simulation_init() mat->init_nuclide_index(); } - // Create cross section caches - #pragma omp parallel - { - simulation::micro_xs = new NuclideMicroXS[data::nuclides.size()]; - simulation::micro_photon_xs = new ElementMicroXS[data::elements.size()]; - } - // Reset global variables -- this is done before loading state point (as that // will potentially populate k_generation and entropy) simulation::current_batch = 0; @@ -133,13 +126,6 @@ int openmc_simulation_finalize() mat->mat_nuclide_index_.clear(); } - // Clear cross section caches - #pragma omp parallel - { - delete[] simulation::micro_xs; - delete[] simulation::micro_photon_xs; - } - // Increment total number of generations simulation::total_gen += simulation::current_batch*settings::gen_per_batch; diff --git a/src/tallies/derivative.cpp b/src/tallies/derivative.cpp index 315cc081e..411995fd7 100644 --- a/src/tallies/derivative.cpp +++ b/src/tallies/derivative.cpp @@ -221,12 +221,12 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, switch (score_bin) { case SCORE_TOTAL: - if (i_nuclide == -1 && simulation::material_xs.total > 0.0) { + if (i_nuclide == -1 && p->material_xs_.total > 0.0) { score *= flux_deriv - + simulation::micro_xs[deriv.diff_nuclide].total - / simulation::material_xs.total; + + p->micro_xs_[deriv.diff_nuclide].total + / p->material_xs_.total; } else if (i_nuclide == deriv.diff_nuclide - && simulation::micro_xs[i_nuclide].total) { + && p->micro_xs_[i_nuclide].total) { score *= flux_deriv + 1. / atom_density; } else { score *= flux_deriv; @@ -234,13 +234,13 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, break; case SCORE_SCATTER: - if (i_nuclide == -1 && (simulation::material_xs.total - - simulation::material_xs.absorption) > 0.0) { + if (i_nuclide == -1 && (p->material_xs_.total + - p->material_xs_.absorption) > 0.0) { score *= flux_deriv - + (simulation::micro_xs[deriv.diff_nuclide].total - - simulation::micro_xs[deriv.diff_nuclide].absorption) - / (simulation::material_xs.total - - simulation::material_xs.absorption); + + (p->micro_xs_[deriv.diff_nuclide].total + - p->micro_xs_[deriv.diff_nuclide].absorption) + / (p->material_xs_.total + - p->material_xs_.absorption); } else if (i_nuclide == deriv.diff_nuclide) { score *= flux_deriv + 1. / atom_density; } else { @@ -249,12 +249,12 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, break; case SCORE_ABSORPTION: - if (i_nuclide == -1 && simulation::material_xs.absorption > 0.0) { + if (i_nuclide == -1 && p->material_xs_.absorption > 0.0) { score *= flux_deriv - + simulation::micro_xs[deriv.diff_nuclide].absorption - / simulation::material_xs.absorption; + + p->micro_xs_[deriv.diff_nuclide].absorption + / p->material_xs_.absorption; } else if (i_nuclide == deriv.diff_nuclide - && simulation::micro_xs[i_nuclide].absorption) { + && p->micro_xs_[i_nuclide].absorption) { score *= flux_deriv + 1. / atom_density; } else { score *= flux_deriv; @@ -262,12 +262,12 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, break; case SCORE_FISSION: - if (i_nuclide == -1 && simulation::material_xs.fission > 0.0) { + if (i_nuclide == -1 && p->material_xs_.fission > 0.0) { score *= flux_deriv - + simulation::micro_xs[deriv.diff_nuclide].fission - / simulation::material_xs.fission; + + p->micro_xs_[deriv.diff_nuclide].fission + / p->material_xs_.fission; } else if (i_nuclide == deriv.diff_nuclide - && simulation::micro_xs[i_nuclide].fission) { + && p->micro_xs_[i_nuclide].fission) { score *= flux_deriv + 1. / atom_density; } else { score *= flux_deriv; @@ -275,12 +275,12 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, break; case SCORE_NU_FISSION: - if (i_nuclide == -1 && simulation::material_xs.nu_fission > 0.0) { + if (i_nuclide == -1 && p->material_xs_.nu_fission > 0.0) { score *= flux_deriv - + simulation::micro_xs[deriv.diff_nuclide].nu_fission - / simulation::material_xs.nu_fission; + + p->micro_xs_[deriv.diff_nuclide].nu_fission + / p->material_xs_.nu_fission; } else if (i_nuclide == deriv.diff_nuclide - && simulation::micro_xs[i_nuclide].nu_fission) { + && p->micro_xs_[i_nuclide].nu_fission) { score *= flux_deriv + 1. / atom_density; } else { score *= flux_deriv; @@ -331,64 +331,64 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, switch (score_bin) { case SCORE_TOTAL: - if (simulation::micro_xs[p->event_nuclide_].total) { + if (p->micro_xs_[p->event_nuclide_].total) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + (dsig_s + dsig_a) * material.atom_density_(i) - / simulation::material_xs.total; + / p->material_xs_.total; } else { score *= flux_deriv; } break; case SCORE_SCATTER: - if (simulation::micro_xs[p->event_nuclide_].total - - simulation::micro_xs[p->event_nuclide_].absorption) { + if (p->micro_xs_[p->event_nuclide_].total + - p->micro_xs_[p->event_nuclide_].absorption) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + dsig_s * material.atom_density_(i) - / (simulation::material_xs.total - - simulation::material_xs.absorption); + / (p->material_xs_.total + - p->material_xs_.absorption); } else { score *= flux_deriv; } break; case SCORE_ABSORPTION: - if (simulation::micro_xs[p->event_nuclide_].absorption) { + if (p->micro_xs_[p->event_nuclide_].absorption) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + dsig_a * material.atom_density_(i) - / simulation::material_xs.absorption; + / p->material_xs_.absorption; } else { score *= flux_deriv; } break; case SCORE_FISSION: - if (simulation::micro_xs[p->event_nuclide_].fission) { + if (p->micro_xs_[p->event_nuclide_].fission) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + dsig_f * material.atom_density_(i) - / simulation::material_xs.fission; + / p->material_xs_.fission; } else { score *= flux_deriv; } break; case SCORE_NU_FISSION: - if (simulation::micro_xs[p->event_nuclide_].fission) { - double nu = simulation::micro_xs[p->event_nuclide_].nu_fission - / simulation::micro_xs[p->event_nuclide_].fission; + if (p->micro_xs_[p->event_nuclide_].fission) { + double nu = p->micro_xs_[p->event_nuclide_].nu_fission + / p->micro_xs_[p->event_nuclide_].fission; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + nu * dsig_f * material.atom_density_(i) - / simulation::material_xs.nu_fission; + / p->material_xs_.nu_fission; } else { score *= flux_deriv; } @@ -413,141 +413,141 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, switch (score_bin) { case SCORE_TOTAL: - if (i_nuclide == -1 && simulation::material_xs.total > 0.0) { + if (i_nuclide == -1 && p->material_xs_.total > 0.0) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && simulation::micro_xs[i_nuc].total) { + && p->micro_xs_[i_nuc].total) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += (dsig_s + dsig_a) * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / simulation::material_xs.total; - } else if (simulation::micro_xs[i_nuclide].total) { + score *= flux_deriv + cum_dsig / p->material_xs_.total; + } else if (p->micro_xs_[i_nuclide].total) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv - + (dsig_s + dsig_a) / simulation::micro_xs[i_nuclide].total; + + (dsig_s + dsig_a) / p->micro_xs_[i_nuclide].total; } else { score *= flux_deriv; } break; case SCORE_SCATTER: - if (i_nuclide == -1 && (simulation::material_xs.total - - simulation::material_xs.absorption)) { + if (i_nuclide == -1 && (p->material_xs_.total + - p->material_xs_.absorption)) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && (simulation::micro_xs[i_nuc].total - - simulation::micro_xs[i_nuc].absorption)) { + && (p->micro_xs_[i_nuc].total + - p->micro_xs_[i_nuc].absorption)) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += dsig_s * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / (simulation::material_xs.total - - simulation::material_xs.absorption); - } else if (simulation::micro_xs[i_nuclide].total - - simulation::micro_xs[i_nuclide].absorption) { + score *= flux_deriv + cum_dsig / (p->material_xs_.total + - p->material_xs_.absorption); + } else if (p->micro_xs_[i_nuclide].total + - p->micro_xs_[i_nuclide].absorption) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); - score *= flux_deriv + dsig_s / (simulation::micro_xs[i_nuclide].total - - simulation::micro_xs[i_nuclide].absorption); + score *= flux_deriv + dsig_s / (p->micro_xs_[i_nuclide].total + - p->micro_xs_[i_nuclide].absorption); } else { score *= flux_deriv; } break; case SCORE_ABSORPTION: - if (i_nuclide == -1 && simulation::material_xs.absorption > 0.0) { + if (i_nuclide == -1 && p->material_xs_.absorption > 0.0) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && simulation::micro_xs[i_nuc].absorption) { + && p->micro_xs_[i_nuc].absorption) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += dsig_a * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / simulation::material_xs.absorption; - } else if (simulation::micro_xs[i_nuclide].absorption) { + score *= flux_deriv + cum_dsig / p->material_xs_.absorption; + } else if (p->micro_xs_[i_nuclide].absorption) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv - + dsig_a / simulation::micro_xs[i_nuclide].absorption; + + dsig_a / p->micro_xs_[i_nuclide].absorption; } else { score *= flux_deriv; } break; case SCORE_FISSION: - if (i_nuclide == -1 && simulation::material_xs.fission > 0.0) { + if (i_nuclide == -1 && p->material_xs_.fission > 0.0) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && simulation::micro_xs[i_nuc].fission) { + && p->micro_xs_[i_nuc].fission) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += dsig_f * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / simulation::material_xs.fission; - } else if (simulation::micro_xs[i_nuclide].fission) { + score *= flux_deriv + cum_dsig / p->material_xs_.fission; + } else if (p->micro_xs_[i_nuclide].fission) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv - + dsig_f / simulation::micro_xs[i_nuclide].fission; + + dsig_f / p->micro_xs_[i_nuclide].fission; } else { score *= flux_deriv; } break; case SCORE_NU_FISSION: - if (i_nuclide == -1 && simulation::material_xs.nu_fission > 0.0) { + if (i_nuclide == -1 && p->material_xs_.nu_fission > 0.0) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && simulation::micro_xs[i_nuc].fission) { - double nu = simulation::micro_xs[i_nuc].nu_fission - / simulation::micro_xs[i_nuc].fission; + && p->micro_xs_[i_nuc].fission) { + double nu = p->micro_xs_[i_nuc].nu_fission + / p->micro_xs_[i_nuc].fission; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += nu * dsig_f * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / simulation::material_xs.nu_fission; - } else if (simulation::micro_xs[i_nuclide].fission) { + score *= flux_deriv + cum_dsig / p->material_xs_.nu_fission; + } else if (p->micro_xs_[i_nuclide].fission) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv - + dsig_f / simulation::micro_xs[i_nuclide].fission; + + dsig_f / p->micro_xs_[i_nuclide].fission; } else { score *= flux_deriv; } @@ -582,7 +582,7 @@ score_track_derivative(const Particle* p, double distance) // phi is proportional to e^(-Sigma_tot * dist) // (1 / phi) * (d_phi / d_rho) = - (d_Sigma_tot / d_rho) * dist // (1 / phi) * (d_phi / d_rho) = - Sigma_tot / rho * dist - deriv.flux_deriv -= distance * simulation::material_xs.total + deriv.flux_deriv -= distance * p->material_xs_.total / material.density_gpcc_; break; @@ -591,7 +591,7 @@ score_track_derivative(const Particle* p, double distance) // (1 / phi) * (d_phi / d_N) = - (d_Sigma_tot / d_N) * dist // (1 / phi) * (d_phi / d_N) = - sigma_tot * dist deriv.flux_deriv -= distance - * simulation::micro_xs[deriv.diff_nuclide].total; + * p->micro_xs_[deriv.diff_nuclide].total; break; case DIFF_TEMPERATURE: @@ -660,7 +660,7 @@ void score_collision_derivative(const Particle* p) // phi is proportional to Sigma_s // (1 / phi) * (d_phi / d_T) = (d_Sigma_s / d_T) / Sigma_s // (1 / phi) * (d_phi / d_T) = (d_sigma_s / d_T) / sigma_s - const auto& micro_xs {simulation::micro_xs[i_nuc]}; + const auto& micro_xs {p->micro_xs_[i_nuc]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index ed4d09254..57e810dfd 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -317,7 +317,7 @@ score_fission_eout(const Particle* p, int i_tally, int i_score, int score_bin) //! is not used for analog tallies. void -score_general_ce(const Particle* p, int i_tally, int start_index, +score_general_ce(Particle* p, int i_tally, int start_index, int filter_index, int i_nuclide, double atom_density, double flux) { auto& tally {*model::tallies[i_tally]}; @@ -349,7 +349,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, if (p->type_ == Particle::Type::neutron || p->type_ == Particle::Type::photon) { - score *= flux / simulation::material_xs.total; + score *= flux / p->material_xs_.total; } else { score = 0.; } @@ -373,9 +373,9 @@ score_general_ce(const Particle* p, int i_tally, int start_index, } else { if (i_nuclide >= 0) { - score = simulation::micro_xs[i_nuclide].total * atom_density * flux; + score = p->micro_xs_[i_nuclide].total * atom_density * flux; } else { - score = simulation::material_xs.total * flux; + score = p->material_xs_.total * flux; } } break; @@ -393,7 +393,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, } else { score = p->wgt_last_; } - score *= flux / simulation::material_xs.total; + score *= flux / p->material_xs_.total; } else { score = flux; } @@ -411,11 +411,11 @@ score_general_ce(const Particle* p, int i_tally, int start_index, score = p->wgt_last_ * flux; } else { if (i_nuclide >= 0) { - score = (simulation::micro_xs[i_nuclide].total - - simulation::micro_xs[i_nuclide].absorption) * atom_density * flux; + score = (p->micro_xs_[i_nuclide].total + - p->micro_xs_[i_nuclide].absorption) * atom_density * flux; } else { - score = (simulation::material_xs.total - - simulation::material_xs.absorption) * flux; + score = (p->material_xs_.total + - p->material_xs_.absorption) * flux; } } break; @@ -458,26 +458,26 @@ score_general_ce(const Particle* p, int i_tally, int start_index, } } else { if (i_nuclide >= 0) { - score = simulation::micro_xs[i_nuclide].absorption * atom_density + score = p->micro_xs_[i_nuclide].absorption * atom_density * flux; } else { - score = simulation::material_xs.absorption * flux; + score = p->material_xs_.absorption * flux; } } break; case SCORE_FISSION: - if (simulation::material_xs.absorption == 0) continue; + if (p->material_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing) { // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // fission - if (simulation::micro_xs[p->event_nuclide_].absorption > 0) { + if (p->micro_xs_[p->event_nuclide_].absorption > 0) { score = p->wgt_absorb_ - * simulation::micro_xs[p->event_nuclide_].fission - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + * p->micro_xs_[p->event_nuclide_].fission + / p->micro_xs_[p->event_nuclide_].absorption * flux; } else { score = 0.; } @@ -488,21 +488,21 @@ score_general_ce(const Particle* p, int i_tally, int start_index, // weight entering the collision as the estimate for the fission // reaction rate score = p->wgt_last_ - * simulation::micro_xs[p->event_nuclide_].fission - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + * p->micro_xs_[p->event_nuclide_].fission + / p->micro_xs_[p->event_nuclide_].absorption * flux; } } else { if (i_nuclide >= 0) { - score = simulation::micro_xs[i_nuclide].fission * atom_density * flux; + score = p->micro_xs_[i_nuclide].fission * atom_density * flux; } else { - score = simulation::material_xs.fission * flux; + score = p->material_xs_.fission * flux; } } break; case SCORE_NU_FISSION: - if (simulation::material_xs.absorption == 0) continue; + if (p->material_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing || p->fission_) { if (tally.energyout_filter_ != C_NONE) { @@ -516,10 +516,10 @@ score_general_ce(const Particle* p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // nu-fission - if (simulation::micro_xs[p->event_nuclide_].absorption > 0) { + if (p->micro_xs_[p->event_nuclide_].absorption > 0) { score = p->wgt_absorb_ - * simulation::micro_xs[p->event_nuclide_].nu_fission - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + * p->micro_xs_[p->event_nuclide_].nu_fission + / p->micro_xs_[p->event_nuclide_].absorption * flux; } else { score = 0.; } @@ -535,17 +535,17 @@ score_general_ce(const Particle* p, int i_tally, int start_index, } } else { if (i_nuclide >= 0) { - score = simulation::micro_xs[i_nuclide].nu_fission * atom_density + score = p->micro_xs_[i_nuclide].nu_fission * atom_density * flux; } else { - score = simulation::material_xs.nu_fission * flux; + score = p->material_xs_.nu_fission * flux; } } break; case SCORE_PROMPT_NU_FISSION: - if (simulation::material_xs.absorption == 0) continue; + if (p->material_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing || p->fission_) { if (tally.energyout_filter_ != C_NONE) { @@ -559,12 +559,12 @@ score_general_ce(const Particle* p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // prompt-nu-fission - if (simulation::micro_xs[p->event_nuclide_].absorption > 0) { + if (p->micro_xs_[p->event_nuclide_].absorption > 0) { score = p->wgt_absorb_ - * simulation::micro_xs[p->event_nuclide_].fission + * p->micro_xs_[p->event_nuclide_].fission * data::nuclides[p->event_nuclide_] ->nu(E, ReactionProduct::EmissionMode::prompt) - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + / p->micro_xs_[p->event_nuclide_].absorption * flux; } else { score = 0.; } @@ -583,7 +583,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, } } else { if (i_nuclide >= 0) { - score = simulation::micro_xs[i_nuclide].fission + score = p->micro_xs_[i_nuclide].fission * data::nuclides[i_nuclide] ->nu(E, ReactionProduct::EmissionMode::prompt) * atom_density * flux; @@ -595,7 +595,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; auto atom_density = material.atom_density_(i); - score += simulation::micro_xs[j_nuclide].fission + score += p->micro_xs_[j_nuclide].fission * data::nuclides[j_nuclide] ->nu(E, ReactionProduct::EmissionMode::prompt) * atom_density * flux; @@ -607,7 +607,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, case SCORE_DELAYED_NU_FISSION: - if (simulation::material_xs.absorption == 0) continue; + if (p->material_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing || p->fission_) { if (tally.energyout_filter_ != C_NONE) { @@ -621,7 +621,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission - if (simulation::micro_xs[p->event_nuclide_].absorption > 0 + if (p->micro_xs_[p->event_nuclide_].absorption > 0 && data::nuclides[p->event_nuclide_]->fissionable_) { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; @@ -634,8 +634,8 @@ score_general_ce(const Particle* p, int i_tally, int start_index, auto yield = data::nuclides[p->event_nuclide_] ->nu(E, ReactionProduct::EmissionMode::delayed, d); score = p->wgt_absorb_ * yield - * simulation::micro_xs[p->event_nuclide_].fission - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + * p->micro_xs_[p->event_nuclide_].fission + / p->micro_xs_[p->event_nuclide_].absorption * flux; score_fission_delayed_dg(i_tally, d_bin, score, score_index); } @@ -645,10 +645,10 @@ score_general_ce(const Particle* p, int i_tally, int start_index, // by multiplying the absorbed weight by the fraction of the // delayed-nu-fission xs to the absorption xs score = p->wgt_absorb_ - * simulation::micro_xs[p->event_nuclide_].fission + * p->micro_xs_[p->event_nuclide_].fission * data::nuclides[p->event_nuclide_] ->nu(E, ReactionProduct::EmissionMode::delayed) - / simulation::micro_xs[p->event_nuclide_].absorption *flux; + / p->micro_xs_[p->event_nuclide_].absorption *flux; } } } else { @@ -694,7 +694,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, auto d = filt.groups_[d_bin]; auto yield = data::nuclides[i_nuclide] ->nu(E, ReactionProduct::EmissionMode::delayed, d); - score = simulation::micro_xs[i_nuclide].fission * yield + score = p->micro_xs_[i_nuclide].fission * yield * atom_density * flux; score_fission_delayed_dg(i_tally, d_bin, score, score_index); } @@ -702,7 +702,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, } else { // If the delayed group filter is not present, compute the score // by multiplying the delayed-nu-fission macro xs by the flux - score = simulation::micro_xs[i_nuclide].fission + score = p->micro_xs_[i_nuclide].fission * data::nuclides[i_nuclide] ->nu(E, ReactionProduct::EmissionMode::delayed) * atom_density * flux; @@ -723,7 +723,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, auto d = filt.groups_[d_bin]; auto yield = data::nuclides[j_nuclide] ->nu(E, ReactionProduct::EmissionMode::delayed, d); - score = simulation::micro_xs[j_nuclide].fission * yield + score = p->micro_xs_[j_nuclide].fission * yield * atom_density * flux; score_fission_delayed_dg(i_tally, d_bin, score, score_index); @@ -738,7 +738,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; auto atom_density = material.atom_density_(i); - score += simulation::micro_xs[j_nuclide].fission + score += p->micro_xs_[j_nuclide].fission * data::nuclides[j_nuclide] ->nu(E, ReactionProduct::EmissionMode::delayed) * atom_density * flux; @@ -751,14 +751,14 @@ score_general_ce(const Particle* p, int i_tally, int start_index, case SCORE_DECAY_RATE: - if (simulation::material_xs.absorption == 0) continue; + if (p->material_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing) { // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (simulation::micro_xs[p->event_nuclide_].absorption > 0 + if (p->micro_xs_[p->event_nuclide_].absorption > 0 && nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; if (tally.delayedgroup_filter_ != C_NONE) { @@ -773,8 +773,8 @@ score_general_ce(const Particle* p, int i_tally, int start_index, = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); auto rate = rxn.products_[d].decay_rate_; score = p->wgt_absorb_ * yield - * simulation::micro_xs[p->event_nuclide_].fission - / simulation::micro_xs[p->event_nuclide_].absorption + * p->micro_xs_[p->event_nuclide_].fission + / p->micro_xs_[p->event_nuclide_].absorption * rate * flux; score_fission_delayed_dg(i_tally, d_bin, score, score_index); @@ -796,8 +796,8 @@ score_general_ce(const Particle* p, int i_tally, int start_index, = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d+1); auto rate = rxn.products_[d+1].decay_rate_; score += rate * p->wgt_absorb_ - * simulation::micro_xs[p->event_nuclide_].fission * yield - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + * p->micro_xs_[p->event_nuclide_].fission * yield + / p->micro_xs_[p->event_nuclide_].absorption * flux; } } } @@ -854,7 +854,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); auto rate = rxn.products_[d].decay_rate_; - score = simulation::micro_xs[i_nuclide].fission * yield * flux + score = p->micro_xs_[i_nuclide].fission * yield * flux * atom_density * rate; score_fission_delayed_dg(i_tally, d_bin, score, score_index); } @@ -870,7 +870,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d+1); auto rate = rxn.products_[d+1].decay_rate_; - score += simulation::micro_xs[i_nuclide].fission * flux + score += p->micro_xs_[i_nuclide].fission * flux * yield * atom_density * rate; } } @@ -894,7 +894,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); auto rate = rxn.products_[d].decay_rate_; - score = simulation::micro_xs[j_nuclide].fission * yield + score = p->micro_xs_[j_nuclide].fission * yield * flux * atom_density * rate; score_fission_delayed_dg(i_tally, d_bin, score, score_index); @@ -922,7 +922,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d+1); auto rate = rxn.products_[d+1].decay_rate_; - score += simulation::micro_xs[j_nuclide].fission + score += p->micro_xs_[j_nuclide].fission * yield * atom_density * flux * rate; } } @@ -935,7 +935,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, case SCORE_KAPPA_FISSION: - if (simulation::material_xs.absorption == 0.) continue; + if (p->material_xs_.absorption == 0.) continue; score = 0.; // Kappa-fission values are determined from the Q-value listed for the // fission cross section. @@ -945,12 +945,12 @@ score_general_ce(const Particle* p, int i_tally, int start_index, // calculate fraction of absorptions that would have resulted in // fission scaled by the Q-value const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (simulation::micro_xs[p->event_nuclide_].absorption > 0 + if (p->micro_xs_[p->event_nuclide_].absorption > 0 && nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; score = p->wgt_absorb_ * rxn.q_value_ - * simulation::micro_xs[p->event_nuclide_].fission - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + * p->micro_xs_[p->event_nuclide_].fission + / p->micro_xs_[p->event_nuclide_].absorption * flux; } } else { // Skip any non-absorption events @@ -959,12 +959,12 @@ score_general_ce(const Particle* p, int i_tally, int start_index, // weight entering the collision as the estimate for the fission // reaction rate const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (simulation::micro_xs[p->event_nuclide_].absorption > 0 + if (p->micro_xs_[p->event_nuclide_].absorption > 0 && nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; score = p->wgt_last_ * rxn.q_value_ - * simulation::micro_xs[p->event_nuclide_].fission - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + * p->micro_xs_[p->event_nuclide_].fission + / p->micro_xs_[p->event_nuclide_].absorption * flux; } } } else { @@ -972,7 +972,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, const auto& nuc {*data::nuclides[i_nuclide]}; if (nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; - score = rxn.q_value_ * simulation::micro_xs[i_nuclide].fission + score = rxn.q_value_ * p->micro_xs_[i_nuclide].fission * atom_density * flux; } } else { @@ -984,7 +984,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, const auto& nuc {*data::nuclides[j_nuclide]}; if (nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; - score += rxn.q_value_ * simulation::micro_xs[j_nuclide].fission + score += rxn.q_value_ * p->micro_xs_[j_nuclide].fission * atom_density * flux; } } @@ -1007,9 +1007,9 @@ score_general_ce(const Particle* p, int i_tally, int start_index, score = p->wgt_last_ * flux; } else { if (i_nuclide >= 0) { - if (simulation::micro_xs[i_nuclide].elastic == CACHE_INVALID) - data::nuclides[i_nuclide]->calculate_elastic_xs(); - score = simulation::micro_xs[i_nuclide].elastic * atom_density * flux; + if (p->micro_xs_[i_nuclide].elastic == CACHE_INVALID) + data::nuclides[i_nuclide]->calculate_elastic_xs(*p); + score = p->micro_xs_[i_nuclide].elastic * atom_density * flux; } else { score = 0.; if (p->material_ != MATERIAL_VOID) { @@ -1017,9 +1017,9 @@ score_general_ce(const Particle* p, int i_tally, int start_index, for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; auto atom_density = material.atom_density_(i); - if (simulation::micro_xs[j_nuclide].elastic == CACHE_INVALID) - data::nuclides[j_nuclide]->calculate_elastic_xs(); - score += simulation::micro_xs[j_nuclide].elastic * atom_density + if (p->micro_xs_[j_nuclide].elastic == CACHE_INVALID) + data::nuclides[j_nuclide]->calculate_elastic_xs(*p); + score += p->micro_xs_[j_nuclide].elastic * atom_density * flux; } } @@ -1030,7 +1030,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, case SCORE_FISS_Q_PROMPT: case SCORE_FISS_Q_RECOV: //continue; - if (simulation::material_xs.absorption == 0.) continue; + if (p->material_xs_.absorption == 0.) continue; score = 0.; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing) { @@ -1038,7 +1038,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, // calculate fraction of absorptions that would have resulted in // fission scaled by the Q-value const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (simulation::micro_xs[p->event_nuclide_].absorption > 0) { + if (p->micro_xs_[p->event_nuclide_].absorption > 0) { double q_value = 0.; if (score_bin == SCORE_FISS_Q_PROMPT) { if (nuc.fission_q_prompt_) @@ -1048,8 +1048,8 @@ score_general_ce(const Particle* p, int i_tally, int start_index, q_value = (*nuc.fission_q_recov_)(p->E_last_); } score = p->wgt_absorb_ * q_value - * simulation::micro_xs[p->event_nuclide_].fission - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + * p->micro_xs_[p->event_nuclide_].fission + / p->micro_xs_[p->event_nuclide_].absorption * flux; } } else { // Skip any non-absorption events @@ -1058,7 +1058,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, // weight entering the collision as the estimate for the fission // reaction rate const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (simulation::micro_xs[p->event_nuclide_].absorption > 0) { + if (p->micro_xs_[p->event_nuclide_].absorption > 0) { double q_value = 0.; if (score_bin == SCORE_FISS_Q_PROMPT) { if (nuc.fission_q_prompt_) @@ -1068,8 +1068,8 @@ score_general_ce(const Particle* p, int i_tally, int start_index, q_value = (*nuc.fission_q_recov_)(p->E_last_); } score = p->wgt_last_ * q_value - * simulation::micro_xs[p->event_nuclide_].fission - / simulation::micro_xs[p->event_nuclide_].absorption * flux; + * p->micro_xs_[p->event_nuclide_].fission + / p->micro_xs_[p->event_nuclide_].absorption * flux; } } } else { @@ -1083,7 +1083,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, if (nuc.fission_q_recov_) q_value = (*nuc.fission_q_recov_)(p->E_last_); } - score = q_value * simulation::micro_xs[i_nuclide].fission + score = q_value * p->micro_xs_[i_nuclide].fission * atom_density * flux; } else { if (p->material_ != MATERIAL_VOID) { @@ -1100,7 +1100,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, if (nuc.fission_q_recov_) q_value = (*nuc.fission_q_recov_)(p->E_last_); } - score += q_value * simulation::micro_xs[j_nuclide].fission + score += q_value * p->micro_xs_[j_nuclide].fission * atom_density * flux; } } @@ -1130,7 +1130,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, case N_4N: m = 5; break; } if (i_nuclide >= 0) { - score = simulation::micro_xs[i_nuclide].reaction[m] * atom_density + score = p->micro_xs_[i_nuclide].reaction[m] * atom_density * flux; } else { score = 0.; @@ -1139,7 +1139,7 @@ score_general_ce(const Particle* p, int i_tally, int start_index, for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; auto atom_density = material.atom_density_(i); - score += simulation::micro_xs[j_nuclide].reaction[m] + score += p->micro_xs_[j_nuclide].reaction[m] * atom_density * flux; } } @@ -1164,10 +1164,10 @@ score_general_ce(const Particle* p, int i_tally, int start_index, auto m = nuc.reaction_index_[score_bin]; if (m == C_NONE) continue; const auto& rxn {*nuc.reactions_[m]}; - auto i_temp = simulation::micro_xs[i_nuclide].index_temp; + auto i_temp = p->micro_xs_[i_nuclide].index_temp; if (i_temp >= 0) { // Can be false due to multipole - auto i_grid = simulation::micro_xs[i_nuclide].index_grid; - auto f = simulation::micro_xs[i_nuclide].interp_factor; + auto i_grid = p->micro_xs_[i_nuclide].index_grid; + auto f = p->micro_xs_[i_nuclide].interp_factor; const auto& xs {rxn.xs_[i_temp]}; if (i_grid >= xs.threshold) { score = ((1.0 - f) * xs.value[i_grid-xs.threshold] @@ -1184,10 +1184,10 @@ score_general_ce(const Particle* p, int i_tally, int start_index, auto m = nuc.reaction_index_[score_bin]; if (m == C_NONE) continue; const auto& rxn {*nuc.reactions_[m]}; - auto i_temp = simulation::micro_xs[j_nuclide].index_temp; + auto i_temp = p->micro_xs_[j_nuclide].index_temp; if (i_temp >= 0) { // Can be false due to multipole - auto i_grid = simulation::micro_xs[j_nuclide].index_grid; - auto f = simulation::micro_xs[j_nuclide].interp_factor; + auto i_grid = p->micro_xs_[j_nuclide].index_grid; + auto f = p->micro_xs_[j_nuclide].interp_factor; const auto& xs {rxn.xs_[i_temp]}; if (i_grid >= xs.threshold) { score += ((1.0 - f) * xs.value[i_grid-xs.threshold] @@ -1291,7 +1291,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, } else { score = p->wgt_last_; } - score *= flux / simulation::material_xs.total; + score *= flux / p->material_xs_.total; } else { score = flux; } @@ -1320,7 +1320,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, score = get_nuclide_xs(i_nuclide, MG_GET_XS_TOTAL, p_g) * atom_density * flux; } else { - score = simulation::material_xs.total * flux; + score = p->material_xs_.total * flux; } } break; @@ -1438,7 +1438,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, score = atom_density * flux * get_nuclide_xs(i_nuclide, MG_GET_XS_ABSORPTION, p_g); } else { - score = simulation::material_xs.absorption * flux; + score = p->material_xs_.absorption * flux; } } break; @@ -1920,7 +1920,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, //! Tally rates for when the user requests a tally on all nuclides. void -score_all_nuclides(const Particle* p, int i_tally, double flux, +score_all_nuclides(Particle* p, int i_tally, double flux, int filter_index) { const Tally& tally {*model::tallies[i_tally]}; @@ -1955,7 +1955,7 @@ score_all_nuclides(const Particle* p, int i_tally, double flux, } } -void score_analog_tally_ce(const Particle* p) +void score_analog_tally_ce(Particle* p) { for (auto i_tally : model::active_analog_tallies) { const Tally& tally {*model::tallies[i_tally]}; @@ -2059,7 +2059,7 @@ void score_analog_tally_mg(const Particle* p) } void -score_tracklength_tally(const Particle* p, double distance) +score_tracklength_tally(Particle* p, double distance) { // Determine the tracklength estimate of the flux double flux = p->wgt_ * distance; @@ -2122,14 +2122,14 @@ score_tracklength_tally(const Particle* p, double distance) match.bins_present_ = false; } -void score_collision_tally(const Particle* p) +void score_collision_tally(Particle* p) { // Determine the collision estimate of the flux double flux; if (!settings::survival_biasing) { - flux = p->wgt_last_ / simulation::material_xs.total; + flux = p->wgt_last_ / p->material_xs_.total; } else { - flux = (p->wgt_last_ + p->wgt_absorb_) / simulation::material_xs.total; + flux = (p->wgt_last_ + p->wgt_absorb_) / p->material_xs_.total; } for (auto i_tally : model::active_collision_tallies) { From 52fc93e6e038df2455b80adf268fa5f3af60b173 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 18 Mar 2019 09:18:54 -0500 Subject: [PATCH 103/165] Rename cross section caches --- include/openmc/particle.h | 11 ++- src/material.cpp | 38 ++++---- src/nuclide.cpp | 8 +- src/particle.cpp | 26 +++--- src/photon.cpp | 2 +- src/physics.cpp | 62 ++++++------- src/physics_mg.cpp | 18 ++-- src/tallies/derivative.cpp | 142 ++++++++++++++-------------- src/tallies/tally_scoring.cpp | 170 +++++++++++++++++----------------- 9 files changed, 239 insertions(+), 238 deletions(-) diff --git a/include/openmc/particle.h b/include/openmc/particle.h index e971c30da..2130b6454 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -111,11 +111,11 @@ struct ElementMicroXS { }; //============================================================================== -// MATERIALMACROXS contains cached macroscopic cross sections for the material a +// MACROXS contains cached macroscopic cross sections for the material a // particle is traveling through //============================================================================== -struct MaterialMacroXS { +struct MacroXS { double total; //!< macroscopic total xs double absorption; //!< macroscopic absorption xs double fission; //!< macroscopic fission xs @@ -219,9 +219,10 @@ public: //========================================================================== // Data members - std::vector micro_xs_; - std::vector micro_photon_xs_; - MaterialMacroXS material_xs_; + // Cross section caches + std::vector neutron_xs_; //!< Microscopic neutron cross sections + std::vector photon_xs_; //!< Microscopic photon cross sections + MacroXS macro_xs_; //!< Macroscopic cross sections int64_t id_; //!< Unique ID Type type_ {Type::neutron}; //!< Particle type (n, p, e, etc.) diff --git a/src/material.cpp b/src/material.cpp index 0d2fe4bbc..94a621483 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -732,10 +732,10 @@ void Material::init_nuclide_index() void Material::calculate_xs(Particle& p) const { // Set all material macroscopic cross sections to zero - p.material_xs_.total = 0.0; - p.material_xs_.absorption = 0.0; - p.material_xs_.fission = 0.0; - p.material_xs_.nu_fission = 0.0; + p.macro_xs_.total = 0.0; + p.macro_xs_.absorption = 0.0; + p.macro_xs_.fission = 0.0; + p.macro_xs_.nu_fission = 0.0; if (p.type_ == Particle::Type::neutron) { this->calculate_neutron_xs(p); @@ -792,7 +792,7 @@ void Material::calculate_neutron_xs(Particle& p) const int i_nuclide = nuclide_[i]; // Calculate microscopic cross section for this nuclide - const auto& micro {p.micro_xs_[i_nuclide]}; + const auto& micro {p.neutron_xs_[i_nuclide]}; if (p.E_ != micro.last_E || p.sqrtkT_ != micro.last_sqrtkT || i_sab != micro.index_sab @@ -807,19 +807,19 @@ void Material::calculate_neutron_xs(Particle& p) const double atom_density = atom_density_(i); // Add contributions to cross sections - p.material_xs_.total += atom_density * micro.total; - p.material_xs_.absorption += atom_density * micro.absorption; - p.material_xs_.fission += atom_density * micro.fission; - p.material_xs_.nu_fission += atom_density * micro.nu_fission; + p.macro_xs_.total += atom_density * micro.total; + p.macro_xs_.absorption += atom_density * micro.absorption; + p.macro_xs_.fission += atom_density * micro.fission; + p.macro_xs_.nu_fission += atom_density * micro.nu_fission; } } void Material::calculate_photon_xs(Particle& p) const { - p.material_xs_.coherent = 0.0; - p.material_xs_.incoherent = 0.0; - p.material_xs_.photoelectric = 0.0; - p.material_xs_.pair_production = 0.0; + p.macro_xs_.coherent = 0.0; + p.macro_xs_.incoherent = 0.0; + p.macro_xs_.photoelectric = 0.0; + p.macro_xs_.pair_production = 0.0; // Add contribution from each nuclide in material for (int i = 0; i < nuclide_.size(); ++i) { @@ -830,7 +830,7 @@ void Material::calculate_photon_xs(Particle& p) const int i_element = element_[i]; // Calculate microscopic cross section for this nuclide - const auto& micro {p.micro_photon_xs_[i_element]}; + const auto& micro {p.photon_xs_[i_element]}; if (p.E_ != micro.last_E) { data::elements[i_element].calculate_xs(p); } @@ -842,11 +842,11 @@ void Material::calculate_photon_xs(Particle& p) const double atom_density = atom_density_(i); // Add contributions to material macroscopic cross sections - p.material_xs_.total += atom_density * micro.total; - p.material_xs_.coherent += atom_density * micro.coherent; - p.material_xs_.incoherent += atom_density * micro.incoherent; - p.material_xs_.photoelectric += atom_density * micro.photoelectric; - p.material_xs_.pair_production += atom_density * micro.pair_production; + p.macro_xs_.total += atom_density * micro.total; + p.macro_xs_.coherent += atom_density * micro.coherent; + p.macro_xs_.incoherent += atom_density * micro.incoherent; + p.macro_xs_.photoelectric += atom_density * micro.photoelectric; + p.macro_xs_.pair_production += atom_density * micro.pair_production; } } diff --git a/src/nuclide.cpp b/src/nuclide.cpp index 87965dfc3..cfb5a669f 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -459,7 +459,7 @@ double Nuclide::nu(double E, EmissionMode mode, int group) const void Nuclide::calculate_elastic_xs(Particle& p) const { // Get temperature index, grid index, and interpolation factor - auto& micro {p.micro_xs_[i_nuclide_]}; + auto& micro {p.neutron_xs_[i_nuclide_]}; int i_temp = micro.index_temp; int i_grid = micro.index_grid; double f = micro.interp_factor; @@ -495,7 +495,7 @@ double Nuclide::elastic_xs_0K(double E) const void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle& p) { - auto& micro {p.micro_xs_[i_nuclide_]}; + auto& micro {p.neutron_xs_[i_nuclide_]}; // Initialize cached cross sections to zero micro.elastic = CACHE_INVALID; @@ -702,7 +702,7 @@ void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle void Nuclide::calculate_sab_xs(int i_sab, double sab_frac, Particle& p) { - auto& micro {p.micro_xs_[i_nuclide_]}; + auto& micro {p.neutron_xs_[i_nuclide_]}; // Set flag that S(a,b) treatment should be used for scattering micro.index_sab = i_sab; @@ -731,7 +731,7 @@ void Nuclide::calculate_sab_xs(int i_sab, double sab_frac, Particle& p) void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const { - auto& micro = p.micro_xs_[i_nuclide_]; + auto& micro = p.neutron_xs_[i_nuclide_]; micro.use_ptable = true; // Create a shorthand for the URR data diff --git a/src/particle.cpp b/src/particle.cpp index f5084cd1c..88ff251dd 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -58,8 +58,8 @@ Particle::Particle() } // Create microscopic cross section caches - micro_xs_.resize(data::nuclides.size()); - micro_photon_xs_.resize(data::elements.size()); + neutron_xs_.resize(data::nuclides.size()); + photon_xs_.resize(data::elements.size()); } void @@ -135,7 +135,7 @@ Particle::transport() // Force calculation of cross-sections by setting last energy to zero if (settings::run_CE) { - for (auto& micro : micro_xs_) micro.last_E = 0.0; + for (auto& micro : neutron_xs_) micro.last_E = 0.0; } // Prepare to write out particle track. @@ -189,17 +189,17 @@ Particle::transport() } else { // Get the MG data calculate_xs_c(material_, g_, sqrtkT_, this->u_local(), - material_xs_.total, material_xs_.absorption, material_xs_.nu_fission); + macro_xs_.total, macro_xs_.absorption, macro_xs_.nu_fission); // Finally, update the particle group while we have already checked // for if multi-group g_last_ = g_; } } else { - material_xs_.total = 0.0; - material_xs_.absorption = 0.0; - material_xs_.fission = 0.0; - material_xs_.nu_fission = 0.0; + macro_xs_.total = 0.0; + macro_xs_.absorption = 0.0; + macro_xs_.fission = 0.0; + macro_xs_.nu_fission = 0.0; } // Find the distance to the nearest boundary @@ -215,10 +215,10 @@ Particle::transport() if (type_ == Particle::Type::electron || type_ == Particle::Type::positron) { d_collision = 0.0; - } else if (material_xs_.total == 0.0) { + } else if (macro_xs_.total == 0.0) { d_collision = INFINITY; } else { - d_collision = -std::log(prn()) / material_xs_.total; + d_collision = -std::log(prn()) / macro_xs_.total; } // Select smaller of the two distances @@ -237,7 +237,7 @@ Particle::transport() // Score track-length estimate of k-eff if (settings::run_mode == RUN_MODE_EIGENVALUE && type_ == Particle::Type::neutron) { - global_tally_tracklength += wgt_ * distance * material_xs_.nu_fission; + global_tally_tracklength += wgt_ * distance * macro_xs_.nu_fission; } // Score flux derivative accumulators for differential tallies. @@ -280,8 +280,8 @@ Particle::transport() // Score collision estimate of keff if (settings::run_mode == RUN_MODE_EIGENVALUE && type_ == Particle::Type::neutron) { - global_tally_collision += wgt_ * material_xs_.nu_fission - / material_xs_.total; + global_tally_collision += wgt_ * macro_xs_.nu_fission + / macro_xs_.total; } // Score surface current tallies -- this has to be done before the collision diff --git a/src/photon.cpp b/src/photon.cpp index 9841e9e3b..79345b90e 100644 --- a/src/photon.cpp +++ b/src/photon.cpp @@ -452,7 +452,7 @@ void PhotonInteraction::calculate_xs(Particle& p) const // calculate interpolation factor double f = (log_E - energy_(i_grid)) / (energy_(i_grid+1) - energy_(i_grid)); - auto& xs {p.micro_photon_xs_[i_element_]}; + auto& xs {p.photon_xs_[i_element_]}; xs.index_grid = i_grid; xs.interp_factor = f; diff --git a/src/physics.cpp b/src/physics.cpp index 029ab18c8..4cc9b12a0 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -110,7 +110,7 @@ void sample_neutron_reaction(Particle* p) // If survival biasing is being used, the following subroutine adjusts the // weight of the particle. Otherwise, it checks to see if absorption occurs - if (p->micro_xs_[i_nuclide].absorption > 0.0) { + if (p->neutron_xs_[i_nuclide].absorption > 0.0) { absorption(p, i_nuclide); } else { p->wgt_absorb_ = 0.0; @@ -146,8 +146,8 @@ create_fission_sites(Particle* p, int i_nuclide, const Reaction* rx, double weight = settings::ufs_on ? ufs_get_weight(p) : 1.0; // Determine the expected number of neutrons produced - double nu_t = p->wgt_ / simulation::keff * weight * p->micro_xs_[ - i_nuclide].nu_fission / p->micro_xs_[i_nuclide].total; + double nu_t = p->wgt_ / simulation::keff * weight * p->neutron_xs_[ + i_nuclide].nu_fission / p->neutron_xs_[i_nuclide].total; // Sample the number of neutrons produced int nu = static_cast(nu_t); @@ -227,7 +227,7 @@ void sample_photon_reaction(Particle* p) // Sample element within material int i_element = sample_element(p); p->event_nuclide_ = i_element; - const auto& micro {p->micro_photon_xs_[i_element]}; + const auto& micro {p->photon_xs_[i_element]}; const auto& element {data::elements[i_element]}; // Calculate photon energy over electron rest mass equivalent @@ -408,7 +408,7 @@ void sample_positron_reaction(Particle* p) int sample_nuclide(const Particle* p) { // Sample cumulative distribution function - double cutoff = prn() * p->material_xs_.total; + double cutoff = prn() * p->macro_xs_.total; // Get pointers to nuclide/density arrays const auto& mat {model::materials[p->material_]}; @@ -421,7 +421,7 @@ int sample_nuclide(const Particle* p) double atom_density = mat->atom_density_[i]; // Increment probability to compare to cutoff - prob += atom_density * p->micro_xs_[i_nuclide].total; + prob += atom_density * p->neutron_xs_[i_nuclide].total; if (prob >= cutoff) return i_nuclide; } @@ -433,7 +433,7 @@ int sample_nuclide(const Particle* p) int sample_element(Particle* p) { // Sample cumulative distribution function - double cutoff = prn() * p->material_xs_.total; + double cutoff = prn() * p->macro_xs_.total; // Get pointers to elements, densities const auto& mat {model::materials[p->material_]}; @@ -454,7 +454,7 @@ int sample_element(Particle* p) double atom_density = mat->atom_density_[i]; // Determine microscopic cross section - double sigma = atom_density * p->micro_photon_xs_[i_element].total; + double sigma = atom_density * p->photon_xs_[i_element].total; // Increment probability to compare to cutoff prob += sigma; @@ -472,7 +472,7 @@ Reaction* sample_fission(int i_nuclide, const Particle* p) // If we're in the URR, by default use the first fission reaction. We also // default to the first reaction if we know that there are no partial fission // reactions - if (p->micro_xs_[i_nuclide].use_ptable || !nuc->has_partial_fission_) { + if (p->neutron_xs_[i_nuclide].use_ptable || !nuc->has_partial_fission_) { return nuc->fission_rx_[0]; } @@ -485,10 +485,10 @@ Reaction* sample_fission(int i_nuclide, const Particle* p) } // Get grid index and interpolatoin factor and sample fission cdf - int i_temp = p->micro_xs_[i_nuclide].index_temp; - int i_grid = p->micro_xs_[i_nuclide].index_grid; - double f = p->micro_xs_[i_nuclide].interp_factor; - double cutoff = prn() * p->micro_xs_[i_nuclide].fission; + int i_temp = p->neutron_xs_[i_nuclide].index_temp; + int i_grid = p->neutron_xs_[i_nuclide].index_grid; + double f = p->neutron_xs_[i_nuclide].interp_factor; + double cutoff = prn() * p->neutron_xs_[i_nuclide].fission; double prob = 0.0; // Loop through each partial fission reaction type @@ -512,10 +512,10 @@ Reaction* sample_fission(int i_nuclide, const Particle* p) void sample_photon_product(int i_nuclide, const Particle* p, int* i_rx, int* i_product) { // Get grid index and interpolation factor and sample photon production cdf - int i_temp = p->micro_xs_[i_nuclide].index_temp; - int i_grid = p->micro_xs_[i_nuclide].index_grid; - double f = p->micro_xs_[i_nuclide].interp_factor; - double cutoff = prn() * p->micro_xs_[i_nuclide].photon_prod; + int i_temp = p->neutron_xs_[i_nuclide].index_temp; + int i_grid = p->neutron_xs_[i_nuclide].index_grid; + double f = p->neutron_xs_[i_nuclide].interp_factor; + double cutoff = prn() * p->neutron_xs_[i_nuclide].photon_prod; double prob = 0.0; // Loop through each reaction type @@ -548,8 +548,8 @@ void absorption(Particle* p, int i_nuclide) { if (settings::survival_biasing) { // Determine weight absorbed in survival biasing - p->wgt_absorb_ = p->wgt_ * p->micro_xs_[i_nuclide].absorption / - p->micro_xs_[i_nuclide].total; + p->wgt_absorb_ = p->wgt_ * p->neutron_xs_[i_nuclide].absorption / + p->neutron_xs_[i_nuclide].total; // Adjust weight of particle by probability of absorption p->wgt_ -= p->wgt_absorb_; @@ -557,17 +557,17 @@ void absorption(Particle* p, int i_nuclide) // Score implicit absorption estimate of keff if (settings::run_mode == RUN_MODE_EIGENVALUE) { - global_tally_absorption += p->wgt_absorb_ * p->micro_xs_[ - i_nuclide].nu_fission / p->micro_xs_[i_nuclide].absorption; + global_tally_absorption += p->wgt_absorb_ * p->neutron_xs_[ + i_nuclide].nu_fission / p->neutron_xs_[i_nuclide].absorption; } } else { // See if disappearance reaction happens - if (p->micro_xs_[i_nuclide].absorption > - prn() * p->micro_xs_[i_nuclide].total) { + if (p->neutron_xs_[i_nuclide].absorption > + prn() * p->neutron_xs_[i_nuclide].total) { // Score absorption estimate of keff if (settings::run_mode == RUN_MODE_EIGENVALUE) { - global_tally_absorption += p->wgt_ * p->micro_xs_[ - i_nuclide].nu_fission / p->micro_xs_[i_nuclide].absorption; + global_tally_absorption += p->wgt_ * p->neutron_xs_[ + i_nuclide].nu_fission / p->neutron_xs_[i_nuclide].absorption; } p->alive_ = false; @@ -584,7 +584,7 @@ void scatter(Particle* p, int i_nuclide) // Get pointer to nuclide and grid index/interpolation factor const auto& nuc {data::nuclides[i_nuclide]}; - const auto& micro {p->micro_xs_[i_nuclide]}; + const auto& micro {p->neutron_xs_[i_nuclide]}; int i_temp = micro.index_temp; int i_grid = micro.index_grid; double f = micro.interp_factor; @@ -691,9 +691,9 @@ void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, // Sample velocity of target nucleus Direction v_t {}; - if (!p->micro_xs_[i_nuclide].use_ptable) { + if (!p->neutron_xs_[i_nuclide].use_ptable) { v_t = sample_target_velocity(nuc.get(), p->E_, p->u(), v_n, - p->micro_xs_[i_nuclide].elastic, kT); + p->neutron_xs_[i_nuclide].elastic, kT); } // Velocity of center-of-mass @@ -746,7 +746,7 @@ void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, void sab_scatter(int i_nuclide, int i_sab, Particle* p) { // Determine temperature index - const auto& micro {p->micro_xs_[i_nuclide]}; + const auto& micro {p->neutron_xs_[i_nuclide]}; int i_temp = micro.index_temp_sab; // Sample energy and angle @@ -1104,8 +1104,8 @@ void inelastic_scatter(const Nuclide* nuc, const Reaction* rx, Particle* p) void sample_secondary_photons(Particle* p, int i_nuclide) { // Sample the number of photons produced - double y_t = p->wgt_ * p->micro_xs_[i_nuclide].photon_prod / - p->micro_xs_[i_nuclide].total; + double y_t = p->wgt_ * p->neutron_xs_[i_nuclide].photon_prod / + p->neutron_xs_[i_nuclide].total; int y = static_cast(y_t); if (prn() <= y_t - y) ++y; diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index 9565a627c..affe0ec19 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -60,7 +60,7 @@ sample_reaction(Particle* p) // If survival biasing is being used, the following subroutine adjusts the // weight of the particle. Otherwise, it checks to see if absorption occurs. - if (p->material_xs_.absorption > 0.) { + if (p->macro_xs_.absorption > 0.) { absorption(p); } else { p->wgt_absorb_ = 0.; @@ -113,7 +113,7 @@ create_fission_sites(Particle* p, Particle::Bank* bank_array, int64_t* size_bank // Determine the expected number of neutrons produced double nu_t = p->wgt_ / simulation::keff * weight * - p->material_xs_.nu_fission / p->material_xs_.total; + p->macro_xs_.nu_fission / p->macro_xs_.total; // Sample the number of neutrons produced int nu = static_cast(nu_t); @@ -204,7 +204,7 @@ absorption(Particle* p) if (settings::survival_biasing) { // Determine weight absorbed in survival biasing p->wgt_absorb_ = p->wgt_ * - p->material_xs_.absorption / p->material_xs_.total; + p->macro_xs_.absorption / p->macro_xs_.total; // Adjust weight of particle by the probability of absorption p->wgt_ -= p->wgt_absorb_; @@ -213,14 +213,14 @@ absorption(Particle* p) // Score implicit absorpion estimate of keff #pragma omp atomic global_tally_absorption += p->wgt_absorb_ * - p->material_xs_.nu_fission / - p->material_xs_.absorption; + p->macro_xs_.nu_fission / + p->macro_xs_.absorption; } else { - if (p->material_xs_.absorption > - prn() * p->material_xs_.total) { + if (p->macro_xs_.absorption > + prn() * p->macro_xs_.total) { #pragma omp atomic - global_tally_absorption += p->wgt_ * p->material_xs_.nu_fission / - p->material_xs_.absorption; + global_tally_absorption += p->wgt_ * p->macro_xs_.nu_fission / + p->macro_xs_.absorption; p->alive_ = false; p->event_ = EVENT_ABSORB; } diff --git a/src/tallies/derivative.cpp b/src/tallies/derivative.cpp index 411995fd7..290d09384 100644 --- a/src/tallies/derivative.cpp +++ b/src/tallies/derivative.cpp @@ -221,12 +221,12 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, switch (score_bin) { case SCORE_TOTAL: - if (i_nuclide == -1 && p->material_xs_.total > 0.0) { + if (i_nuclide == -1 && p->macro_xs_.total > 0.0) { score *= flux_deriv - + p->micro_xs_[deriv.diff_nuclide].total - / p->material_xs_.total; + + p->neutron_xs_[deriv.diff_nuclide].total + / p->macro_xs_.total; } else if (i_nuclide == deriv.diff_nuclide - && p->micro_xs_[i_nuclide].total) { + && p->neutron_xs_[i_nuclide].total) { score *= flux_deriv + 1. / atom_density; } else { score *= flux_deriv; @@ -234,13 +234,13 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, break; case SCORE_SCATTER: - if (i_nuclide == -1 && (p->material_xs_.total - - p->material_xs_.absorption) > 0.0) { + if (i_nuclide == -1 && (p->macro_xs_.total + - p->macro_xs_.absorption) > 0.0) { score *= flux_deriv - + (p->micro_xs_[deriv.diff_nuclide].total - - p->micro_xs_[deriv.diff_nuclide].absorption) - / (p->material_xs_.total - - p->material_xs_.absorption); + + (p->neutron_xs_[deriv.diff_nuclide].total + - p->neutron_xs_[deriv.diff_nuclide].absorption) + / (p->macro_xs_.total + - p->macro_xs_.absorption); } else if (i_nuclide == deriv.diff_nuclide) { score *= flux_deriv + 1. / atom_density; } else { @@ -249,12 +249,12 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, break; case SCORE_ABSORPTION: - if (i_nuclide == -1 && p->material_xs_.absorption > 0.0) { + if (i_nuclide == -1 && p->macro_xs_.absorption > 0.0) { score *= flux_deriv - + p->micro_xs_[deriv.diff_nuclide].absorption - / p->material_xs_.absorption; + + p->neutron_xs_[deriv.diff_nuclide].absorption + / p->macro_xs_.absorption; } else if (i_nuclide == deriv.diff_nuclide - && p->micro_xs_[i_nuclide].absorption) { + && p->neutron_xs_[i_nuclide].absorption) { score *= flux_deriv + 1. / atom_density; } else { score *= flux_deriv; @@ -262,12 +262,12 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, break; case SCORE_FISSION: - if (i_nuclide == -1 && p->material_xs_.fission > 0.0) { + if (i_nuclide == -1 && p->macro_xs_.fission > 0.0) { score *= flux_deriv - + p->micro_xs_[deriv.diff_nuclide].fission - / p->material_xs_.fission; + + p->neutron_xs_[deriv.diff_nuclide].fission + / p->macro_xs_.fission; } else if (i_nuclide == deriv.diff_nuclide - && p->micro_xs_[i_nuclide].fission) { + && p->neutron_xs_[i_nuclide].fission) { score *= flux_deriv + 1. / atom_density; } else { score *= flux_deriv; @@ -275,12 +275,12 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, break; case SCORE_NU_FISSION: - if (i_nuclide == -1 && p->material_xs_.nu_fission > 0.0) { + if (i_nuclide == -1 && p->macro_xs_.nu_fission > 0.0) { score *= flux_deriv - + p->micro_xs_[deriv.diff_nuclide].nu_fission - / p->material_xs_.nu_fission; + + p->neutron_xs_[deriv.diff_nuclide].nu_fission + / p->macro_xs_.nu_fission; } else if (i_nuclide == deriv.diff_nuclide - && p->micro_xs_[i_nuclide].nu_fission) { + && p->neutron_xs_[i_nuclide].nu_fission) { score *= flux_deriv + 1. / atom_density; } else { score *= flux_deriv; @@ -331,64 +331,64 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, switch (score_bin) { case SCORE_TOTAL: - if (p->micro_xs_[p->event_nuclide_].total) { + if (p->neutron_xs_[p->event_nuclide_].total) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + (dsig_s + dsig_a) * material.atom_density_(i) - / p->material_xs_.total; + / p->macro_xs_.total; } else { score *= flux_deriv; } break; case SCORE_SCATTER: - if (p->micro_xs_[p->event_nuclide_].total - - p->micro_xs_[p->event_nuclide_].absorption) { + if (p->neutron_xs_[p->event_nuclide_].total + - p->neutron_xs_[p->event_nuclide_].absorption) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + dsig_s * material.atom_density_(i) - / (p->material_xs_.total - - p->material_xs_.absorption); + / (p->macro_xs_.total + - p->macro_xs_.absorption); } else { score *= flux_deriv; } break; case SCORE_ABSORPTION: - if (p->micro_xs_[p->event_nuclide_].absorption) { + if (p->neutron_xs_[p->event_nuclide_].absorption) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + dsig_a * material.atom_density_(i) - / p->material_xs_.absorption; + / p->macro_xs_.absorption; } else { score *= flux_deriv; } break; case SCORE_FISSION: - if (p->micro_xs_[p->event_nuclide_].fission) { + if (p->neutron_xs_[p->event_nuclide_].fission) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + dsig_f * material.atom_density_(i) - / p->material_xs_.fission; + / p->macro_xs_.fission; } else { score *= flux_deriv; } break; case SCORE_NU_FISSION: - if (p->micro_xs_[p->event_nuclide_].fission) { - double nu = p->micro_xs_[p->event_nuclide_].nu_fission - / p->micro_xs_[p->event_nuclide_].fission; + if (p->neutron_xs_[p->event_nuclide_].fission) { + double nu = p->neutron_xs_[p->event_nuclide_].nu_fission + / p->neutron_xs_[p->event_nuclide_].fission; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv + nu * dsig_f * material.atom_density_(i) - / p->material_xs_.nu_fission; + / p->macro_xs_.nu_fission; } else { score *= flux_deriv; } @@ -413,141 +413,141 @@ apply_derivative_to_score(const Particle* p, int i_tally, int i_nuclide, switch (score_bin) { case SCORE_TOTAL: - if (i_nuclide == -1 && p->material_xs_.total > 0.0) { + if (i_nuclide == -1 && p->macro_xs_.total > 0.0) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && p->micro_xs_[i_nuc].total) { + && p->neutron_xs_[i_nuc].total) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += (dsig_s + dsig_a) * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / p->material_xs_.total; - } else if (p->micro_xs_[i_nuclide].total) { + score *= flux_deriv + cum_dsig / p->macro_xs_.total; + } else if (p->neutron_xs_[i_nuclide].total) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv - + (dsig_s + dsig_a) / p->micro_xs_[i_nuclide].total; + + (dsig_s + dsig_a) / p->neutron_xs_[i_nuclide].total; } else { score *= flux_deriv; } break; case SCORE_SCATTER: - if (i_nuclide == -1 && (p->material_xs_.total - - p->material_xs_.absorption)) { + if (i_nuclide == -1 && (p->macro_xs_.total + - p->macro_xs_.absorption)) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && (p->micro_xs_[i_nuc].total - - p->micro_xs_[i_nuc].absorption)) { + && (p->neutron_xs_[i_nuc].total + - p->neutron_xs_[i_nuc].absorption)) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += dsig_s * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / (p->material_xs_.total - - p->material_xs_.absorption); - } else if (p->micro_xs_[i_nuclide].total - - p->micro_xs_[i_nuclide].absorption) { + score *= flux_deriv + cum_dsig / (p->macro_xs_.total + - p->macro_xs_.absorption); + } else if (p->neutron_xs_[i_nuclide].total + - p->neutron_xs_[i_nuclide].absorption) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); - score *= flux_deriv + dsig_s / (p->micro_xs_[i_nuclide].total - - p->micro_xs_[i_nuclide].absorption); + score *= flux_deriv + dsig_s / (p->neutron_xs_[i_nuclide].total + - p->neutron_xs_[i_nuclide].absorption); } else { score *= flux_deriv; } break; case SCORE_ABSORPTION: - if (i_nuclide == -1 && p->material_xs_.absorption > 0.0) { + if (i_nuclide == -1 && p->macro_xs_.absorption > 0.0) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && p->micro_xs_[i_nuc].absorption) { + && p->neutron_xs_[i_nuc].absorption) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += dsig_a * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / p->material_xs_.absorption; - } else if (p->micro_xs_[i_nuclide].absorption) { + score *= flux_deriv + cum_dsig / p->macro_xs_.absorption; + } else if (p->neutron_xs_[i_nuclide].absorption) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv - + dsig_a / p->micro_xs_[i_nuclide].absorption; + + dsig_a / p->neutron_xs_[i_nuclide].absorption; } else { score *= flux_deriv; } break; case SCORE_FISSION: - if (i_nuclide == -1 && p->material_xs_.fission > 0.0) { + if (i_nuclide == -1 && p->macro_xs_.fission > 0.0) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && p->micro_xs_[i_nuc].fission) { + && p->neutron_xs_[i_nuc].fission) { double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += dsig_f * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / p->material_xs_.fission; - } else if (p->micro_xs_[i_nuclide].fission) { + score *= flux_deriv + cum_dsig / p->macro_xs_.fission; + } else if (p->neutron_xs_[i_nuclide].fission) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv - + dsig_f / p->micro_xs_[i_nuclide].fission; + + dsig_f / p->neutron_xs_[i_nuclide].fission; } else { score *= flux_deriv; } break; case SCORE_NU_FISSION: - if (i_nuclide == -1 && p->material_xs_.nu_fission > 0.0) { + if (i_nuclide == -1 && p->macro_xs_.nu_fission > 0.0) { double cum_dsig = 0; for (auto i = 0; i < material.nuclide_.size(); ++i) { auto i_nuc = material.nuclide_[i]; const auto& nuc {*data::nuclides[i_nuc]}; if (multipole_in_range(&nuc, p->E_last_) - && p->micro_xs_[i_nuc].fission) { - double nu = p->micro_xs_[i_nuc].nu_fission - / p->micro_xs_[i_nuc].fission; + && p->neutron_xs_[i_nuc].fission) { + double nu = p->neutron_xs_[i_nuc].nu_fission + / p->neutron_xs_[i_nuc].fission; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); cum_dsig += nu * dsig_f * material.atom_density_(i); } } - score *= flux_deriv + cum_dsig / p->material_xs_.nu_fission; - } else if (p->micro_xs_[i_nuclide].fission) { + score *= flux_deriv + cum_dsig / p->macro_xs_.nu_fission; + } else if (p->neutron_xs_[i_nuclide].fission) { const auto& nuc {*data::nuclides[i_nuclide]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); score *= flux_deriv - + dsig_f / p->micro_xs_[i_nuclide].fission; + + dsig_f / p->neutron_xs_[i_nuclide].fission; } else { score *= flux_deriv; } @@ -582,7 +582,7 @@ score_track_derivative(const Particle* p, double distance) // phi is proportional to e^(-Sigma_tot * dist) // (1 / phi) * (d_phi / d_rho) = - (d_Sigma_tot / d_rho) * dist // (1 / phi) * (d_phi / d_rho) = - Sigma_tot / rho * dist - deriv.flux_deriv -= distance * p->material_xs_.total + deriv.flux_deriv -= distance * p->macro_xs_.total / material.density_gpcc_; break; @@ -591,7 +591,7 @@ score_track_derivative(const Particle* p, double distance) // (1 / phi) * (d_phi / d_N) = - (d_Sigma_tot / d_N) * dist // (1 / phi) * (d_phi / d_N) = - sigma_tot * dist deriv.flux_deriv -= distance - * p->micro_xs_[deriv.diff_nuclide].total; + * p->neutron_xs_[deriv.diff_nuclide].total; break; case DIFF_TEMPERATURE: @@ -660,7 +660,7 @@ void score_collision_derivative(const Particle* p) // phi is proportional to Sigma_s // (1 / phi) * (d_phi / d_T) = (d_Sigma_s / d_T) / Sigma_s // (1 / phi) * (d_phi / d_T) = (d_sigma_s / d_T) / sigma_s - const auto& micro_xs {p->micro_xs_[i_nuc]}; + const auto& micro_xs {p->neutron_xs_[i_nuc]}; double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p->E_last_, p->sqrtkT_); diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index 57e810dfd..de851ea3c 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -349,7 +349,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, if (p->type_ == Particle::Type::neutron || p->type_ == Particle::Type::photon) { - score *= flux / p->material_xs_.total; + score *= flux / p->macro_xs_.total; } else { score = 0.; } @@ -373,9 +373,9 @@ score_general_ce(Particle* p, int i_tally, int start_index, } else { if (i_nuclide >= 0) { - score = p->micro_xs_[i_nuclide].total * atom_density * flux; + score = p->neutron_xs_[i_nuclide].total * atom_density * flux; } else { - score = p->material_xs_.total * flux; + score = p->macro_xs_.total * flux; } } break; @@ -393,7 +393,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, } else { score = p->wgt_last_; } - score *= flux / p->material_xs_.total; + score *= flux / p->macro_xs_.total; } else { score = flux; } @@ -411,11 +411,11 @@ score_general_ce(Particle* p, int i_tally, int start_index, score = p->wgt_last_ * flux; } else { if (i_nuclide >= 0) { - score = (p->micro_xs_[i_nuclide].total - - p->micro_xs_[i_nuclide].absorption) * atom_density * flux; + score = (p->neutron_xs_[i_nuclide].total + - p->neutron_xs_[i_nuclide].absorption) * atom_density * flux; } else { - score = (p->material_xs_.total - - p->material_xs_.absorption) * flux; + score = (p->macro_xs_.total + - p->macro_xs_.absorption) * flux; } } break; @@ -458,26 +458,26 @@ score_general_ce(Particle* p, int i_tally, int start_index, } } else { if (i_nuclide >= 0) { - score = p->micro_xs_[i_nuclide].absorption * atom_density + score = p->neutron_xs_[i_nuclide].absorption * atom_density * flux; } else { - score = p->material_xs_.absorption * flux; + score = p->macro_xs_.absorption * flux; } } break; case SCORE_FISSION: - if (p->material_xs_.absorption == 0) continue; + if (p->macro_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing) { // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // fission - if (p->micro_xs_[p->event_nuclide_].absorption > 0) { + if (p->neutron_xs_[p->event_nuclide_].absorption > 0) { score = p->wgt_absorb_ - * p->micro_xs_[p->event_nuclide_].fission - / p->micro_xs_[p->event_nuclide_].absorption * flux; + * p->neutron_xs_[p->event_nuclide_].fission + / p->neutron_xs_[p->event_nuclide_].absorption * flux; } else { score = 0.; } @@ -488,21 +488,21 @@ score_general_ce(Particle* p, int i_tally, int start_index, // weight entering the collision as the estimate for the fission // reaction rate score = p->wgt_last_ - * p->micro_xs_[p->event_nuclide_].fission - / p->micro_xs_[p->event_nuclide_].absorption * flux; + * p->neutron_xs_[p->event_nuclide_].fission + / p->neutron_xs_[p->event_nuclide_].absorption * flux; } } else { if (i_nuclide >= 0) { - score = p->micro_xs_[i_nuclide].fission * atom_density * flux; + score = p->neutron_xs_[i_nuclide].fission * atom_density * flux; } else { - score = p->material_xs_.fission * flux; + score = p->macro_xs_.fission * flux; } } break; case SCORE_NU_FISSION: - if (p->material_xs_.absorption == 0) continue; + if (p->macro_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing || p->fission_) { if (tally.energyout_filter_ != C_NONE) { @@ -516,10 +516,10 @@ score_general_ce(Particle* p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // nu-fission - if (p->micro_xs_[p->event_nuclide_].absorption > 0) { + if (p->neutron_xs_[p->event_nuclide_].absorption > 0) { score = p->wgt_absorb_ - * p->micro_xs_[p->event_nuclide_].nu_fission - / p->micro_xs_[p->event_nuclide_].absorption * flux; + * p->neutron_xs_[p->event_nuclide_].nu_fission + / p->neutron_xs_[p->event_nuclide_].absorption * flux; } else { score = 0.; } @@ -535,17 +535,17 @@ score_general_ce(Particle* p, int i_tally, int start_index, } } else { if (i_nuclide >= 0) { - score = p->micro_xs_[i_nuclide].nu_fission * atom_density + score = p->neutron_xs_[i_nuclide].nu_fission * atom_density * flux; } else { - score = p->material_xs_.nu_fission * flux; + score = p->macro_xs_.nu_fission * flux; } } break; case SCORE_PROMPT_NU_FISSION: - if (p->material_xs_.absorption == 0) continue; + if (p->macro_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing || p->fission_) { if (tally.energyout_filter_ != C_NONE) { @@ -559,12 +559,12 @@ score_general_ce(Particle* p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // prompt-nu-fission - if (p->micro_xs_[p->event_nuclide_].absorption > 0) { + if (p->neutron_xs_[p->event_nuclide_].absorption > 0) { score = p->wgt_absorb_ - * p->micro_xs_[p->event_nuclide_].fission + * p->neutron_xs_[p->event_nuclide_].fission * data::nuclides[p->event_nuclide_] ->nu(E, ReactionProduct::EmissionMode::prompt) - / p->micro_xs_[p->event_nuclide_].absorption * flux; + / p->neutron_xs_[p->event_nuclide_].absorption * flux; } else { score = 0.; } @@ -583,7 +583,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, } } else { if (i_nuclide >= 0) { - score = p->micro_xs_[i_nuclide].fission + score = p->neutron_xs_[i_nuclide].fission * data::nuclides[i_nuclide] ->nu(E, ReactionProduct::EmissionMode::prompt) * atom_density * flux; @@ -595,7 +595,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; auto atom_density = material.atom_density_(i); - score += p->micro_xs_[j_nuclide].fission + score += p->neutron_xs_[j_nuclide].fission * data::nuclides[j_nuclide] ->nu(E, ReactionProduct::EmissionMode::prompt) * atom_density * flux; @@ -607,7 +607,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, case SCORE_DELAYED_NU_FISSION: - if (p->material_xs_.absorption == 0) continue; + if (p->macro_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing || p->fission_) { if (tally.energyout_filter_ != C_NONE) { @@ -621,7 +621,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission - if (p->micro_xs_[p->event_nuclide_].absorption > 0 + if (p->neutron_xs_[p->event_nuclide_].absorption > 0 && data::nuclides[p->event_nuclide_]->fissionable_) { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; @@ -634,8 +634,8 @@ score_general_ce(Particle* p, int i_tally, int start_index, auto yield = data::nuclides[p->event_nuclide_] ->nu(E, ReactionProduct::EmissionMode::delayed, d); score = p->wgt_absorb_ * yield - * p->micro_xs_[p->event_nuclide_].fission - / p->micro_xs_[p->event_nuclide_].absorption * flux; + * p->neutron_xs_[p->event_nuclide_].fission + / p->neutron_xs_[p->event_nuclide_].absorption * flux; score_fission_delayed_dg(i_tally, d_bin, score, score_index); } @@ -645,10 +645,10 @@ score_general_ce(Particle* p, int i_tally, int start_index, // by multiplying the absorbed weight by the fraction of the // delayed-nu-fission xs to the absorption xs score = p->wgt_absorb_ - * p->micro_xs_[p->event_nuclide_].fission + * p->neutron_xs_[p->event_nuclide_].fission * data::nuclides[p->event_nuclide_] ->nu(E, ReactionProduct::EmissionMode::delayed) - / p->micro_xs_[p->event_nuclide_].absorption *flux; + / p->neutron_xs_[p->event_nuclide_].absorption *flux; } } } else { @@ -694,7 +694,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, auto d = filt.groups_[d_bin]; auto yield = data::nuclides[i_nuclide] ->nu(E, ReactionProduct::EmissionMode::delayed, d); - score = p->micro_xs_[i_nuclide].fission * yield + score = p->neutron_xs_[i_nuclide].fission * yield * atom_density * flux; score_fission_delayed_dg(i_tally, d_bin, score, score_index); } @@ -702,7 +702,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, } else { // If the delayed group filter is not present, compute the score // by multiplying the delayed-nu-fission macro xs by the flux - score = p->micro_xs_[i_nuclide].fission + score = p->neutron_xs_[i_nuclide].fission * data::nuclides[i_nuclide] ->nu(E, ReactionProduct::EmissionMode::delayed) * atom_density * flux; @@ -723,7 +723,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, auto d = filt.groups_[d_bin]; auto yield = data::nuclides[j_nuclide] ->nu(E, ReactionProduct::EmissionMode::delayed, d); - score = p->micro_xs_[j_nuclide].fission * yield + score = p->neutron_xs_[j_nuclide].fission * yield * atom_density * flux; score_fission_delayed_dg(i_tally, d_bin, score, score_index); @@ -738,7 +738,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; auto atom_density = material.atom_density_(i); - score += p->micro_xs_[j_nuclide].fission + score += p->neutron_xs_[j_nuclide].fission * data::nuclides[j_nuclide] ->nu(E, ReactionProduct::EmissionMode::delayed) * atom_density * flux; @@ -751,14 +751,14 @@ score_general_ce(Particle* p, int i_tally, int start_index, case SCORE_DECAY_RATE: - if (p->material_xs_.absorption == 0) continue; + if (p->macro_xs_.absorption == 0) continue; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing) { // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (p->micro_xs_[p->event_nuclide_].absorption > 0 + if (p->neutron_xs_[p->event_nuclide_].absorption > 0 && nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; if (tally.delayedgroup_filter_ != C_NONE) { @@ -773,8 +773,8 @@ score_general_ce(Particle* p, int i_tally, int start_index, = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); auto rate = rxn.products_[d].decay_rate_; score = p->wgt_absorb_ * yield - * p->micro_xs_[p->event_nuclide_].fission - / p->micro_xs_[p->event_nuclide_].absorption + * p->neutron_xs_[p->event_nuclide_].fission + / p->neutron_xs_[p->event_nuclide_].absorption * rate * flux; score_fission_delayed_dg(i_tally, d_bin, score, score_index); @@ -796,8 +796,8 @@ score_general_ce(Particle* p, int i_tally, int start_index, = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d+1); auto rate = rxn.products_[d+1].decay_rate_; score += rate * p->wgt_absorb_ - * p->micro_xs_[p->event_nuclide_].fission * yield - / p->micro_xs_[p->event_nuclide_].absorption * flux; + * p->neutron_xs_[p->event_nuclide_].fission * yield + / p->neutron_xs_[p->event_nuclide_].absorption * flux; } } } @@ -854,7 +854,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); auto rate = rxn.products_[d].decay_rate_; - score = p->micro_xs_[i_nuclide].fission * yield * flux + score = p->neutron_xs_[i_nuclide].fission * yield * flux * atom_density * rate; score_fission_delayed_dg(i_tally, d_bin, score, score_index); } @@ -870,7 +870,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d+1); auto rate = rxn.products_[d+1].decay_rate_; - score += p->micro_xs_[i_nuclide].fission * flux + score += p->neutron_xs_[i_nuclide].fission * flux * yield * atom_density * rate; } } @@ -894,7 +894,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); auto rate = rxn.products_[d].decay_rate_; - score = p->micro_xs_[j_nuclide].fission * yield + score = p->neutron_xs_[j_nuclide].fission * yield * flux * atom_density * rate; score_fission_delayed_dg(i_tally, d_bin, score, score_index); @@ -922,7 +922,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d+1); auto rate = rxn.products_[d+1].decay_rate_; - score += p->micro_xs_[j_nuclide].fission + score += p->neutron_xs_[j_nuclide].fission * yield * atom_density * flux * rate; } } @@ -935,7 +935,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, case SCORE_KAPPA_FISSION: - if (p->material_xs_.absorption == 0.) continue; + if (p->macro_xs_.absorption == 0.) continue; score = 0.; // Kappa-fission values are determined from the Q-value listed for the // fission cross section. @@ -945,12 +945,12 @@ score_general_ce(Particle* p, int i_tally, int start_index, // calculate fraction of absorptions that would have resulted in // fission scaled by the Q-value const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (p->micro_xs_[p->event_nuclide_].absorption > 0 + if (p->neutron_xs_[p->event_nuclide_].absorption > 0 && nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; score = p->wgt_absorb_ * rxn.q_value_ - * p->micro_xs_[p->event_nuclide_].fission - / p->micro_xs_[p->event_nuclide_].absorption * flux; + * p->neutron_xs_[p->event_nuclide_].fission + / p->neutron_xs_[p->event_nuclide_].absorption * flux; } } else { // Skip any non-absorption events @@ -959,12 +959,12 @@ score_general_ce(Particle* p, int i_tally, int start_index, // weight entering the collision as the estimate for the fission // reaction rate const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (p->micro_xs_[p->event_nuclide_].absorption > 0 + if (p->neutron_xs_[p->event_nuclide_].absorption > 0 && nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; score = p->wgt_last_ * rxn.q_value_ - * p->micro_xs_[p->event_nuclide_].fission - / p->micro_xs_[p->event_nuclide_].absorption * flux; + * p->neutron_xs_[p->event_nuclide_].fission + / p->neutron_xs_[p->event_nuclide_].absorption * flux; } } } else { @@ -972,7 +972,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, const auto& nuc {*data::nuclides[i_nuclide]}; if (nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; - score = rxn.q_value_ * p->micro_xs_[i_nuclide].fission + score = rxn.q_value_ * p->neutron_xs_[i_nuclide].fission * atom_density * flux; } } else { @@ -984,7 +984,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, const auto& nuc {*data::nuclides[j_nuclide]}; if (nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; - score += rxn.q_value_ * p->micro_xs_[j_nuclide].fission + score += rxn.q_value_ * p->neutron_xs_[j_nuclide].fission * atom_density * flux; } } @@ -1007,9 +1007,9 @@ score_general_ce(Particle* p, int i_tally, int start_index, score = p->wgt_last_ * flux; } else { if (i_nuclide >= 0) { - if (p->micro_xs_[i_nuclide].elastic == CACHE_INVALID) + if (p->neutron_xs_[i_nuclide].elastic == CACHE_INVALID) data::nuclides[i_nuclide]->calculate_elastic_xs(*p); - score = p->micro_xs_[i_nuclide].elastic * atom_density * flux; + score = p->neutron_xs_[i_nuclide].elastic * atom_density * flux; } else { score = 0.; if (p->material_ != MATERIAL_VOID) { @@ -1017,9 +1017,9 @@ score_general_ce(Particle* p, int i_tally, int start_index, for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; auto atom_density = material.atom_density_(i); - if (p->micro_xs_[j_nuclide].elastic == CACHE_INVALID) + if (p->neutron_xs_[j_nuclide].elastic == CACHE_INVALID) data::nuclides[j_nuclide]->calculate_elastic_xs(*p); - score += p->micro_xs_[j_nuclide].elastic * atom_density + score += p->neutron_xs_[j_nuclide].elastic * atom_density * flux; } } @@ -1030,7 +1030,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, case SCORE_FISS_Q_PROMPT: case SCORE_FISS_Q_RECOV: //continue; - if (p->material_xs_.absorption == 0.) continue; + if (p->macro_xs_.absorption == 0.) continue; score = 0.; if (tally.estimator_ == ESTIMATOR_ANALOG) { if (settings::survival_biasing) { @@ -1038,7 +1038,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, // calculate fraction of absorptions that would have resulted in // fission scaled by the Q-value const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (p->micro_xs_[p->event_nuclide_].absorption > 0) { + if (p->neutron_xs_[p->event_nuclide_].absorption > 0) { double q_value = 0.; if (score_bin == SCORE_FISS_Q_PROMPT) { if (nuc.fission_q_prompt_) @@ -1048,8 +1048,8 @@ score_general_ce(Particle* p, int i_tally, int start_index, q_value = (*nuc.fission_q_recov_)(p->E_last_); } score = p->wgt_absorb_ * q_value - * p->micro_xs_[p->event_nuclide_].fission - / p->micro_xs_[p->event_nuclide_].absorption * flux; + * p->neutron_xs_[p->event_nuclide_].fission + / p->neutron_xs_[p->event_nuclide_].absorption * flux; } } else { // Skip any non-absorption events @@ -1058,7 +1058,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, // weight entering the collision as the estimate for the fission // reaction rate const auto& nuc {*data::nuclides[p->event_nuclide_]}; - if (p->micro_xs_[p->event_nuclide_].absorption > 0) { + if (p->neutron_xs_[p->event_nuclide_].absorption > 0) { double q_value = 0.; if (score_bin == SCORE_FISS_Q_PROMPT) { if (nuc.fission_q_prompt_) @@ -1068,8 +1068,8 @@ score_general_ce(Particle* p, int i_tally, int start_index, q_value = (*nuc.fission_q_recov_)(p->E_last_); } score = p->wgt_last_ * q_value - * p->micro_xs_[p->event_nuclide_].fission - / p->micro_xs_[p->event_nuclide_].absorption * flux; + * p->neutron_xs_[p->event_nuclide_].fission + / p->neutron_xs_[p->event_nuclide_].absorption * flux; } } } else { @@ -1083,7 +1083,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, if (nuc.fission_q_recov_) q_value = (*nuc.fission_q_recov_)(p->E_last_); } - score = q_value * p->micro_xs_[i_nuclide].fission + score = q_value * p->neutron_xs_[i_nuclide].fission * atom_density * flux; } else { if (p->material_ != MATERIAL_VOID) { @@ -1100,7 +1100,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, if (nuc.fission_q_recov_) q_value = (*nuc.fission_q_recov_)(p->E_last_); } - score += q_value * p->micro_xs_[j_nuclide].fission + score += q_value * p->neutron_xs_[j_nuclide].fission * atom_density * flux; } } @@ -1130,7 +1130,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, case N_4N: m = 5; break; } if (i_nuclide >= 0) { - score = p->micro_xs_[i_nuclide].reaction[m] * atom_density + score = p->neutron_xs_[i_nuclide].reaction[m] * atom_density * flux; } else { score = 0.; @@ -1139,7 +1139,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, for (auto i = 0; i < material.nuclide_.size(); ++i) { auto j_nuclide = material.nuclide_[i]; auto atom_density = material.atom_density_(i); - score += p->micro_xs_[j_nuclide].reaction[m] + score += p->neutron_xs_[j_nuclide].reaction[m] * atom_density * flux; } } @@ -1164,10 +1164,10 @@ score_general_ce(Particle* p, int i_tally, int start_index, auto m = nuc.reaction_index_[score_bin]; if (m == C_NONE) continue; const auto& rxn {*nuc.reactions_[m]}; - auto i_temp = p->micro_xs_[i_nuclide].index_temp; + auto i_temp = p->neutron_xs_[i_nuclide].index_temp; if (i_temp >= 0) { // Can be false due to multipole - auto i_grid = p->micro_xs_[i_nuclide].index_grid; - auto f = p->micro_xs_[i_nuclide].interp_factor; + auto i_grid = p->neutron_xs_[i_nuclide].index_grid; + auto f = p->neutron_xs_[i_nuclide].interp_factor; const auto& xs {rxn.xs_[i_temp]}; if (i_grid >= xs.threshold) { score = ((1.0 - f) * xs.value[i_grid-xs.threshold] @@ -1184,10 +1184,10 @@ score_general_ce(Particle* p, int i_tally, int start_index, auto m = nuc.reaction_index_[score_bin]; if (m == C_NONE) continue; const auto& rxn {*nuc.reactions_[m]}; - auto i_temp = p->micro_xs_[j_nuclide].index_temp; + auto i_temp = p->neutron_xs_[j_nuclide].index_temp; if (i_temp >= 0) { // Can be false due to multipole - auto i_grid = p->micro_xs_[j_nuclide].index_grid; - auto f = p->micro_xs_[j_nuclide].interp_factor; + auto i_grid = p->neutron_xs_[j_nuclide].index_grid; + auto f = p->neutron_xs_[j_nuclide].interp_factor; const auto& xs {rxn.xs_[i_temp]}; if (i_grid >= xs.threshold) { score += ((1.0 - f) * xs.value[i_grid-xs.threshold] @@ -1291,7 +1291,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, } else { score = p->wgt_last_; } - score *= flux / p->material_xs_.total; + score *= flux / p->macro_xs_.total; } else { score = flux; } @@ -1320,7 +1320,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, score = get_nuclide_xs(i_nuclide, MG_GET_XS_TOTAL, p_g) * atom_density * flux; } else { - score = p->material_xs_.total * flux; + score = p->macro_xs_.total * flux; } } break; @@ -1438,7 +1438,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, score = atom_density * flux * get_nuclide_xs(i_nuclide, MG_GET_XS_ABSORPTION, p_g); } else { - score = p->material_xs_.absorption * flux; + score = p->macro_xs_.absorption * flux; } } break; @@ -2127,9 +2127,9 @@ void score_collision_tally(Particle* p) // Determine the collision estimate of the flux double flux; if (!settings::survival_biasing) { - flux = p->wgt_last_ / p->material_xs_.total; + flux = p->wgt_last_ / p->macro_xs_.total; } else { - flux = (p->wgt_last_ + p->wgt_absorb_) / p->material_xs_.total; + flux = (p->wgt_last_ + p->wgt_absorb_) / p->macro_xs_.total; } for (auto i_tally : model::active_collision_tallies) { From 429f186223e146ee3eb54be9df2917f7b92961b8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 28 Oct 2018 16:11:33 -0600 Subject: [PATCH 104/165] Fix grammatical error in photon docs --- docs/source/methods/photon_physics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/methods/photon_physics.rst b/docs/source/methods/photon_physics.rst index 23809f674..2d9a62ef3 100644 --- a/docs/source/methods/photon_physics.rst +++ b/docs/source/methods/photon_physics.rst @@ -5,7 +5,7 @@ Photon Physics ============== Photons, being neutral particles, behave much in the same manner as neutrons, -traveling in straight lines and experiencing occasional collisions which change +traveling in straight lines and experiencing occasional collisions that change their energy and direction. Photons undergo four basic interactions as they pass through matter: coherent (Rayleigh) scattering, incoherent (Compton) scattering, photoelectric effect, and pair/triplet production. Photons with energy in the From d70cfda07c29958a58380ca7d4c015bc5172c137 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 18 Mar 2019 11:34:33 -0500 Subject: [PATCH 105/165] A few style guide additions --- docs/source/devguide/styleguide.rst | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/source/devguide/styleguide.rst b/docs/source/devguide/styleguide.rst index 0f7669a24..cbf665cc8 100644 --- a/docs/source/devguide/styleguide.rst +++ b/docs/source/devguide/styleguide.rst @@ -12,6 +12,11 @@ adding new code in OpenMC. C++ --- +Indentation +----------- + +Use two spaces per indentation level. + Miscellaneous ------------- @@ -126,6 +131,15 @@ single declaration to avoid confusion: Curly braces ------------ +For a class declaration, the opening brace should be on the same line that +lists the name of the class. + +.. code-block:: C++ + + class Matrix { + ... + }; + For a function definition, the opening and closing braces should each be on their own lines. This helps distinguish function code from the argument list. If the entire function fits on one or two lines, then the braces can be on the @@ -210,11 +224,18 @@ Use of third-party Python packages should be limited to numpy_, scipy_, matplotlib_, pandas_, and h5py_. Use of other third-party packages must be implemented as optional dependencies rather than required dependencies. +Prefer pathlib_ when working with filesystem paths over functions in the os_ +module or other standard-library modules. Functions that accept arguments that +represent a filesystem path should work with both strings and Path_ objects. + .. _C++ Core Guidelines: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines .. _PEP8: https://www.python.org/dev/peps/pep-0008/ -.. _numpydoc: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt +.. _numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html .. _numpy: http://www.numpy.org/ .. _scipy: https://www.scipy.org/ .. _matplotlib: https://matplotlib.org/ .. _pandas: https://pandas.pydata.org/ -.. _h5py: http://www.h5py.org/ +.. _h5py: https://www.h5py.org/ +.. _pathlib: https://docs.python.org/3/library/pathlib.html +.. _os: https://docs.python.org/3/library/os.html +.. _Path: https://docs.python.org/3/library/pathlib.html#pathlib.Path From 86d187a0a71cfdeee7fd5de4ace49764ec1f1725 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 18 Mar 2019 12:26:53 -0500 Subject: [PATCH 106/165] Turn Particle.coord_ into a std::vector (remove MAX_COORD) --- CMakeLists.txt | 4 ---- docs/source/usersguide/install.rst | 3 --- include/openmc/geometry.h | 3 ++- include/openmc/geometry_aux.h | 9 ++++----- include/openmc/particle.h | 4 ++-- src/geometry.cpp | 3 ++- src/geometry_aux.cpp | 10 ++-------- src/particle.cpp | 4 +++- 8 files changed, 15 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f943d0969..930b1e0bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,9 +20,6 @@ option(optimize "Turn on all compiler optimization flags" OFF) option(coverage "Compile with coverage analysis flags" OFF) option(dagmc "Enable support for DAGMC (CAD) geometry" OFF) -# Maximum number of nested coordinates levels -set(maxcoord 10 CACHE STRING "Maximum number of nested coordinate levels") - #=============================================================================== # MPI for distributed-memory parallelism #=============================================================================== @@ -260,7 +257,6 @@ target_include_directories(libopenmc # Set compile flags target_compile_options(libopenmc PRIVATE ${cxxflags}) -target_compile_definitions(libopenmc PUBLIC -DMAX_COORD=${maxcoord}) if (HDF5_IS_PARALLEL) target_compile_definitions(libopenmc PRIVATE -DPHDF5) endif() diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index d44ee9594..96b4f5024 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -243,9 +243,6 @@ coverage Compile and link code instrumented for coverage analysis. This is typically used in conjunction with gcov_. -maxcoord - Maximum number of nested coordinate levels in geometry. Defaults to 10. - To set any of these options (e.g. turning on debug mode), the following form should be used: diff --git a/include/openmc/geometry.h b/include/openmc/geometry.h index a2da2c5f2..9bb1a9ae7 100644 --- a/include/openmc/geometry.h +++ b/include/openmc/geometry.h @@ -15,7 +15,8 @@ namespace openmc { namespace model { -extern "C" int root_universe; +extern int root_universe; //!< Index of root universe +extern int n_coord_levels; //!< Number of CSG coordinate levels extern std::vector overlap_check_count; diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 5898c61f3..ffcdcf885 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -57,7 +57,7 @@ void finalize_geometry(std::vector>& nuc_temps, //! \return The index of the root universe. //============================================================================== -extern "C" int32_t find_root_universe(); +int32_t find_root_universe(); //============================================================================== //! Populate all data structures needed for distribcells. @@ -74,7 +74,7 @@ void prepare_distribcell(); //! the root universe). //============================================================================== -extern "C" void count_cell_instances(int32_t univ_indx); +void count_cell_instances(int32_t univ_indx); //============================================================================== //! Recursively search through universes and count universe instances. @@ -84,8 +84,7 @@ extern "C" void count_cell_instances(int32_t univ_indx); //! search_univ. //============================================================================== -extern "C" int -count_universe_instances(int32_t search_univ, int32_t target_univ_id); +int count_universe_instances(int32_t search_univ, int32_t target_univ_id); //============================================================================== //! Build a character array representing the path to a distribcell instance. @@ -107,7 +106,7 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset); //! \return The number of coordinate levels. //============================================================================== -extern "C" int maximum_levels(int32_t univ); +int maximum_levels(int32_t univ); //============================================================================== //! Deallocates global vectors and maps for cells, universes, and lattices. diff --git a/include/openmc/particle.h b/include/openmc/particle.h index 2130b6454..ef1e076bb 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -229,11 +229,11 @@ public: int n_coord_ {1}; //!< number of current coordinate levels int cell_instance_; //!< offset for distributed properties - LocalCoord coord_[MAX_COORD]; //!< coordinates for all levels + std::vector coord_; //!< coordinates for all levels // Particle coordinates before crossing a surface int n_coord_last_ {1}; //!< number of current coordinates - int cell_last_[MAX_COORD]; //!< coordinates for all levels + std::vector cell_last_; //!< coordinates for all levels // Energy data double E_; //!< post-collision energy in eV diff --git a/src/geometry.cpp b/src/geometry.cpp index 3c1c11b0e..cde2cdc1b 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -22,6 +22,7 @@ namespace openmc { namespace model { int root_universe {-1}; +int n_coord_levels; std::vector overlap_check_count; @@ -257,7 +258,7 @@ find_cell(Particle* p, bool use_neighbor_lists) } // Reset all the deeper coordinate levels. - for (int i = p->n_coord_; i < MAX_COORD; i++) { + for (int i = p->n_coord_; i < p->coord_.size(); i++) { p->coord_[i].reset(); } diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index c560743f8..e19b5f946 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -217,14 +217,8 @@ void finalize_geometry(std::vector>& nuc_temps, // Determine desired temperatures for each nuclide and S(a,b) table get_temperatures(nuc_temps, thermal_temps); - // Check to make sure there are not too many nested coordinate levels in the - // geometry since the coordinate list is statically allocated for performance - // reasons - if (maximum_levels(model::root_universe) > MAX_COORD) { - fatal_error("Too many nested coordinate levels in the geometry. " - "Try increasing the maximum number of coordinate levels by " - "providing the CMake -Dmaxcoord= option."); - } + // Determine number of nested coordinate levels in the geometry + model::n_coord_levels = maximum_levels(model::root_universe); } //============================================================================== diff --git a/src/particle.cpp b/src/particle.cpp index 88ff251dd..c6f73f4f1 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -50,7 +50,9 @@ LocalCoord::reset() Particle::Particle() { - // Clear coordinate lists + // Create and clear coordinate levels + coord_.resize(model::n_coord_levels); + cell_last_.resize(model::n_coord_levels); clear(); for (int& n : n_delayed_bank_) { From d980b4a5ea3e6050031825f6318b55c52a613c18 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 19 Mar 2019 07:37:33 -0500 Subject: [PATCH 107/165] Make secondary_bank_ a vector and improve interfaces --- include/openmc/bank.h | 4 +-- include/openmc/mesh.h | 7 ++-- include/openmc/particle.h | 3 +- include/openmc/physics.h | 4 ++- include/openmc/physics_mg.h | 9 +++-- src/bank.cpp | 2 -- src/eigenvalue.cpp | 56 ++++++++++++++---------------- src/mesh.cpp | 31 +++++------------ src/particle.cpp | 23 ++++++------- src/physics.cpp | 52 ++++++++-------------------- src/physics_mg.cpp | 65 ++++++++++------------------------- src/simulation.cpp | 12 +++---- src/tallies/tally_scoring.cpp | 6 ++-- 13 files changed, 95 insertions(+), 179 deletions(-) diff --git a/include/openmc/bank.h b/include/openmc/bank.h index b7fab9ac6..4597369c7 100644 --- a/include/openmc/bank.h +++ b/include/openmc/bank.h @@ -20,15 +20,13 @@ namespace openmc { namespace simulation { -extern "C" int64_t n_bank; - extern std::vector source_bank; extern std::vector fission_bank; #ifdef _OPENMP extern std::vector master_fission_bank; #endif -#pragma omp threadprivate(fission_bank, n_bank) +#pragma omp threadprivate(fission_bank) } // namespace simulation diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 3fc7db781..f53bba224 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -96,14 +96,11 @@ public: //! Count number of bank sites in each mesh bin / energy bin // - //! \param[in] n Number of bank sites //! \param[in] bank Array of bank sites - //! \param[in] n_energy Number of energies - //! \param[in] energies Array of energies //! \param[out] Whether any bank sites are outside the mesh //! \return Array indicating number of sites in each mesh/energy bin - xt::xarray count_sites(int64_t n, const Particle::Bank* bank, - int n_energy, const double* energies, bool* outside) const; + xt::xarray count_sites(const std::vector& bank, + bool* outside) const; int id_ {-1}; //!< User-specified ID int n_dimension_; //!< Number of dimensions diff --git a/include/openmc/particle.h b/include/openmc/particle.h index ef1e076bb..d52c67ea5 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -285,8 +285,7 @@ public: bool write_track_ {false}; // Secondary particles created - int64_t n_secondary_ {}; - Bank secondary_bank_[MAX_SECONDARY]; + std::vector secondary_bank_; }; } // namespace openmc diff --git a/include/openmc/physics.h b/include/openmc/physics.h index 5c8d64f5f..107380eb8 100644 --- a/include/openmc/physics.h +++ b/include/openmc/physics.h @@ -7,6 +7,8 @@ #include "openmc/position.h" #include "openmc/reaction.h" +#include + namespace openmc { //============================================================================== @@ -47,7 +49,7 @@ int sample_nuclide(const Particle* p); //! Determine the average total, prompt, and delayed neutrons produced from //! fission and creates appropriate bank sites. void create_fission_sites(Particle* p, int i_nuclide, const Reaction* rx, - Particle::Bank* bank_array, int64_t* bank_size, int64_t bank_capacity); + std::vector& bank); int sample_element(Particle* p); diff --git a/include/openmc/physics_mg.h b/include/openmc/physics_mg.h index cdf1f7089..f246cb6ec 100644 --- a/include/openmc/physics_mg.h +++ b/include/openmc/physics_mg.h @@ -8,6 +8,8 @@ #include "openmc/particle.h" #include "openmc/nuclide.h" +#include + namespace openmc { //! \brief samples particle behavior after a collision event. @@ -31,12 +33,9 @@ scatter(Particle* p); //! \brief Determines the average total, prompt and delayed neutrons produced //! from fission and creates the appropriate bank sites. //! \param p Particle to operate on -//! \param bank_array The particle bank to populate -//! \param size_bank Number of particles currently in the bank -//! \param bank_array_size Allocated size of the bank +//! \param bank The particle bank to populate void -create_fission_sites(Particle* p, Particle::Bank* bank_array, int64_t* size_bank, - int64_t bank_array_size); +create_fission_sites(Particle* p, std::vector& bank); //! \brief Handles an absorption event //! \param p Particle to operate on diff --git a/src/bank.cpp b/src/bank.cpp index 8b7b43688..fc48a7761 100644 --- a/src/bank.cpp +++ b/src/bank.cpp @@ -16,8 +16,6 @@ namespace openmc { namespace simulation { -int64_t n_bank; - std::vector source_bank; std::vector fission_bank; #ifdef _OPENMP diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index c995a02d7..170195529 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -23,6 +23,7 @@ #include // for min #include #include // for sqrt, abs, pow +#include // for back_inserter #include namespace openmc { @@ -81,21 +82,22 @@ void synchronize_bank() #ifdef OPENMC_MPI int64_t start = 0; - MPI_Exscan(&simulation::n_bank, &start, 1, MPI_INT64_T, MPI_SUM, mpi::intracomm); + int64_t n_bank = simulation::fission_bank.size(); + MPI_Exscan(&n_bank, &start, 1, MPI_INT64_T, MPI_SUM, mpi::intracomm); // While we would expect the value of start on rank 0 to be 0, the MPI // standard says that the receive buffer on rank 0 is undefined and not // significant if (mpi::rank == 0) start = 0; - int64_t finish = start + simulation::n_bank; + int64_t finish = start + simulation::fission_bank.size(); int64_t total = finish; MPI_Bcast(&total, 1, MPI_INT64_T, mpi::n_procs - 1, mpi::intracomm); #else int64_t start = 0; - int64_t finish = simulation::n_bank; - int64_t total = simulation::n_bank; + int64_t finish = simulation::fission_bank.size(); + int64_t total = simulation::fission_bank.size(); #endif // If there are not that many particles per generation, it's possible that no @@ -103,7 +105,7 @@ void synchronize_bank() // extra logic to treat this circumstance, we really want to ensure the user // runs enough particles to avoid this in the first place. - if (simulation::n_bank == 0) { + if (simulation::fission_bank.empty()) { fatal_error("No fission sites banked on MPI rank " + std::to_string(mpi::rank)); } @@ -134,21 +136,21 @@ void synchronize_bank() int64_t index_temp = 0; std::vector temp_sites(3*simulation::work); - for (int64_t i = 0; i < simulation::n_bank; ++i) { + for (const auto& site : simulation::fission_bank) { // If there are less than n_particles particles banked, automatically add // int(n_particles/total) sites to temp_sites. For example, if you need // 1000 and 300 were banked, this would add 3 source sites per banked site // and the remaining 100 would be randomly sampled. if (total < settings::n_particles) { for (int64_t j = 1; j <= settings::n_particles / total; ++j) { - temp_sites[index_temp] = simulation::fission_bank[i]; + temp_sites[index_temp] = site; ++index_temp; } } // Randomly sample sites needed if (prn() < p_sample) { - temp_sites[index_temp] = simulation::fission_bank[i]; + temp_sites[index_temp] = site; ++index_temp; } } @@ -189,7 +191,7 @@ void synchronize_bank() // fission bank sites_needed = settings::n_particles - finish; for (int i = 0; i < sites_needed; ++i) { - int i_bank = simulation::n_bank - sites_needed + i; + int i_bank = simulation::fission_bank.size() - sites_needed + i; temp_sites[index_temp] = simulation::fission_bank[i_bank]; ++index_temp; } @@ -346,38 +348,30 @@ void calculate_average_keff() #ifdef _OPENMP void join_bank_from_threads() { - // Initialize the total number of fission bank sites - int64_t total = 0; - -#pragma omp parallel + #pragma omp parallel { // Copy thread fission bank sites to one shared copy -#pragma omp for ordered schedule(static) + #pragma omp for ordered schedule(static) for (int i = 0; i < simulation::n_threads; ++i) { -#pragma omp ordered + #pragma omp ordered { std::copy( - &simulation::fission_bank[0], - &simulation::fission_bank[0] + simulation::n_bank, - &simulation::master_fission_bank[total] + simulation::fission_bank.cbegin(), + simulation::fission_bank.cend(), + std::back_inserter(simulation::master_fission_bank) ); - total += simulation::n_bank; } } // Make sure all threads have made it to this point -#pragma omp barrier + #pragma omp barrier // Now copy the shared fission bank sites back to the master thread's copy. if (simulation::thread_id == 0) { - simulation::n_bank = total; - std::copy( - &simulation::master_fission_bank[0], - &simulation::master_fission_bank[0] + simulation::n_bank, - &simulation::fission_bank[0] - ); + simulation::fission_bank = simulation::master_fission_bank; + simulation::master_fission_bank.clear(); } else { - simulation::n_bank = 0; + simulation::fission_bank.clear(); } } } @@ -537,8 +531,8 @@ void shannon_entropy() // Get source weight in each mesh bin bool sites_outside; - xt::xtensor p = m->count_sites(simulation::n_bank, - simulation::fission_bank.data(), 0, nullptr, &sites_outside); + xt::xtensor p = m->count_sites(simulation::fission_bank, + &sites_outside); // display warning message if there were sites outside entropy box if (sites_outside) { @@ -577,8 +571,8 @@ void ufs_count_sites() } else { // count number of source sites in each ufs mesh cell bool sites_outside; - simulation::source_frac = m->count_sites(simulation::work, - simulation::source_bank.data(), 0, nullptr, &sites_outside); + simulation::source_frac = m->count_sites(simulation::source_bank, + &sites_outside); // Check for sites outside of the mesh if (mpi::master && sites_outside) { diff --git a/src/mesh.cpp b/src/mesh.cpp index b75a0aad1..ddfa272a6 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -732,25 +732,21 @@ void RegularMesh::to_hdf5(hid_t group) const close_group(mesh_group); } -xt::xarray RegularMesh::count_sites(int64_t n, const Particle::Bank* bank, - int n_energy, const double* energies, bool* outside) const +xt::xarray +RegularMesh::count_sites(const std::vector& bank, + bool* outside) const { // Determine shape of array for counts std::size_t m = xt::prod(shape_)(); - std::vector shape; - if (n_energy > 0) { - shape = {m, static_cast(n_energy - 1)}; - } else { - shape = {m}; - } + std::vector shape = {m}; // Create array of zeros xt::xarray cnt {shape, 0.0}; bool outside_ = false; - for (int64_t i = 0; i < n; ++i) { + for (const auto& site : bank) { // determine scoring bin for entropy mesh - int mesh_bin = get_bin(bank[i].r); + int mesh_bin = get_bin(site.r); // if outside mesh, skip particle if (mesh_bin < 0) { @@ -758,19 +754,8 @@ xt::xarray RegularMesh::count_sites(int64_t n, const Particle::Bank* ban continue; } - if (n_energy > 0) { - double E = bank[i].E; - if (E >= energies[0] && E <= energies[n_energy - 1]) { - // determine energy bin - int e_bin = lower_bound_index(energies, energies + n_energy, E); - - // Add to appropriate bin - cnt(mesh_bin, e_bin) += bank[i].wgt; - } - } else { - // Add to appropriate bin - cnt(mesh_bin) += bank[i].wgt; - } + // Add to appropriate bin + cnt(mesh_bin) += site.wgt; } // Create copy of count data diff --git a/src/particle.cpp b/src/particle.cpp index c6f73f4f1..92045e2cd 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -75,17 +75,14 @@ Particle::clear() void Particle::create_secondary(Direction u, double E, Type type) { - if (n_secondary_ == MAX_SECONDARY) { - fatal_error("Too many secondary particles created."); - } + secondary_bank_.emplace_back(); - int64_t n = n_secondary_; - secondary_bank_[n].particle = type; - secondary_bank_[n].wgt = wgt_; - secondary_bank_[n].r = this->r(); - secondary_bank_[n].u = u; - secondary_bank_[n].E = settings::run_CE ? E : g_; - ++n_secondary_; + auto& bank {secondary_bank_.back()}; + bank.particle = type; + bank.wgt = wgt_; + bank.r = this->r(); + bank.u = u; + bank.E = settings::run_CE ? E : g_; } void @@ -360,10 +357,10 @@ Particle::transport() // Check for secondary particles if this particle is dead if (!alive_) { // If no secondary particles, break out of event loop - if (n_secondary_ == 0) break; + if (secondary_bank_.empty()) break; - this->from_source(&secondary_bank_[n_secondary_ - 1]); - --n_secondary_; + this->from_source(&secondary_bank_.back()); + secondary_bank_.pop_back(); n_event = 0; // Enter new particle in particle track file diff --git a/src/physics.cpp b/src/physics.cpp index 4cc9b12a0..7d44aa17c 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -91,12 +91,10 @@ void sample_neutron_reaction(Particle* p) if (nuc->fissionable_) { Reaction* rx = sample_fission(i_nuclide, p); if (settings::run_mode == RUN_MODE_EIGENVALUE) { - create_fission_sites(p, i_nuclide, rx, simulation::fission_bank.data(), - &simulation::n_bank, simulation::fission_bank.size()); + create_fission_sites(p, i_nuclide, rx, simulation::fission_bank); } else if (settings::run_mode == RUN_MODE_FIXEDSOURCE && settings::create_fission_neutrons) { - create_fission_sites(p, i_nuclide, rx, p->secondary_bank_, - &p->n_secondary_, MAX_SECONDARY); + create_fission_sites(p, i_nuclide, rx, p->secondary_bank_); } } @@ -137,10 +135,8 @@ void sample_neutron_reaction(Particle* p) void create_fission_sites(Particle* p, int i_nuclide, const Reaction* rx, - Particle::Bank* bank_array, int64_t* size_bank, int64_t bank_capacity) + std::vector& bank) { - // TODO: Heat generation from fission - // If uniform fission source weighting is turned on, we increase or decrease // the expected number of fission sites produced double weight = settings::ufs_on ? ufs_get_weight(p) : 1.0; @@ -153,47 +149,30 @@ create_fission_sites(Particle* p, int i_nuclide, const Reaction* rx, int nu = static_cast(nu_t); if (prn() <= (nu_t - nu)) ++nu; - // Check for the bank size getting hit. For fixed source calculations, this - // is a fatal error; for eigenvalue calculations, it just means that k-eff - // was too high for a single batch. - if (*size_bank + nu > bank_capacity) { - if (settings::run_mode == RUN_MODE_FIXEDSOURCE) { - throw std::runtime_error{"Secondary particle bank size limit reached." - " If you are running a subcritical multiplication problem," - " k-effective may be too close to one."}; - } else { - if (mpi::master) { - warning("Maximum number of sites in fission bank reached. This can" - " result in irreproducible results using different numbers of" - " processes/threads."); - } - } - } - // Begin banking the source neutrons // First, if our bank is full then don't continue - if (nu == 0 || *size_bank == bank_capacity) return; + if (nu == 0) return; // Initialize the counter of delayed neutrons encountered for each delayed // group. double nu_d[MAX_DELAYED_GROUPS] = {0.}; p->fission_ = true; - for (size_t i = *size_bank; i < std::min(*size_bank + nu, bank_capacity); ++i) { + for (int i = 0; i < nu; ++i) { + // Create new bank site and get reference to last element + bank.emplace_back(); + auto& site {bank.back()}; + // Bank source neutrons by copying the particle data - bank_array[i].r = p->r(); - - // Set that the bank particle is a neutron - bank_array[i].particle = Particle::Type::neutron; - - // Set the weight of the fission bank site - bank_array[i].wgt = 1. / weight; + site.r = p->r(); + site.particle = Particle::Type::neutron; + site.wgt = 1. / weight; // Sample delayed group and angle/energy for fission reaction - sample_fission_neutron(i_nuclide, rx, p->E_, &bank_array[i]); + sample_fission_neutron(i_nuclide, rx, p->E_, &site); // Set the delayed group on the particle as well - p->delayed_group_ = bank_array[i].delayed_group; + p->delayed_group_ = site.delayed_group; // Increment the number of neutrons born delayed if (p->delayed_group_ > 0) { @@ -201,9 +180,6 @@ create_fission_sites(Particle* p, int i_nuclide, const Reaction* rx, } } - // Increment number of bank sites - *size_bank = std::min(*size_bank + nu, bank_capacity); - // Store the total weight banked for analog fission tallies p->n_bank_ = nu; p->wgt_bank_ = nu / weight; diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index affe0ec19..2a6b700f0 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -48,13 +48,10 @@ sample_reaction(Particle* p) if (model::materials[p->material_]->fissionable_) { if (settings::run_mode == RUN_MODE_EIGENVALUE) { - create_fission_sites( - p, simulation::fission_bank.data(), &simulation::n_bank, - simulation::fission_bank.size()); + create_fission_sites(p, simulation::fission_bank); } else if ((settings::run_mode == RUN_MODE_FIXEDSOURCE) && (settings::create_fission_neutrons)) { - create_fission_sites(p, p->secondary_bank_, &(p->n_secondary_), - MAX_SECONDARY); + create_fission_sites(p, p->secondary_bank_); } } @@ -102,11 +99,8 @@ scatter(Particle* p) } void -create_fission_sites(Particle* p, Particle::Bank* bank_array, int64_t* size_bank, - int64_t bank_array_size) +create_fission_sites(Particle* p, std::vector& bank) { - // TODO: Heat generation from fission - // If uniform fission source weighting is turned on, we increase or decrease // the expected number of fission sites produced double weight = settings::ufs_on ? ufs_get_weight(p) : 1.0; @@ -121,62 +115,42 @@ create_fission_sites(Particle* p, Particle::Bank* bank_array, int64_t* size_bank nu++; } - // Check for the bank size getting hit. For fixed source calculations, this - // is a fatal error; for eigenvalue calculations, it just means that k-eff - // was too high for a single batch. - if (*size_bank + nu > bank_array_size) { - if (settings::run_mode == RUN_MODE_FIXEDSOURCE) { - throw std::runtime_error{"Secondary particle bank size limit reached." - " If you are running a subcritical multiplication problem," - " k-effective may be too close to one."}; - } else { - if (mpi::master) { - std::stringstream msg; - msg << "Maximum number of sites in fission bank reached. This can" - " result in irreproducible results using different numbers of" - " processes/threads."; - warning(msg); - } - } - } - // Begin banking the source neutrons // First, if our bank is full then don't continue - if ((nu == 0) || (*size_bank == bank_array_size)) return; + if (nu == 0) return; // Initialize the counter of delayed neutrons encountered for each delayed // group. double nu_d[MAX_DELAYED_GROUPS] = {0.}; p->fission_ = true; - for (size_t i = static_cast(*size_bank); - i < static_cast(std::min(*size_bank + nu, bank_array_size)); i++) { + for (int i = 0; i < nu; ++i) { + // Create new bank site and get reference to last element + bank.emplace_back(); + auto& site {bank.back()}; + // Bank source neutrons by copying the particle data - bank_array[i].r = p->r(); - - // Set that the bank particle is a neutron - bank_array[i].particle = Particle::Type::neutron; - - // Set the weight of the fission bank site - bank_array[i].wgt = 1. / weight; + site.r = p->r(); + site.particle = Particle::Type::neutron; + site.wgt = 1. / weight; // Sample the cosine of the angle, assuming fission neutrons are emitted // isotropically - double mu = 2. * prn() - 1.; + double mu = 2.*prn() - 1.; // Sample the azimuthal angle uniformly in [0, 2.pi) double phi = 2. * PI * prn(); - bank_array[i].u.x = mu; - bank_array[i].u.y = std::sqrt(1. - mu * mu) * std::cos(phi); - bank_array[i].u.z = std::sqrt(1. - mu * mu) * std::sin(phi); + site.u.x = mu; + site.u.y = std::sqrt(1. - mu * mu) * std::cos(phi); + site.u.z = std::sqrt(1. - mu * mu) * std::sin(phi); // Sample secondary energy distribution for the fission reaction and set // the energy in the fission bank int dg; int gout; data::macro_xs[p->material_].sample_fission_energy(p->g_ - 1, dg, gout); - bank_array[i].E = gout + 1; - bank_array[i].delayed_group = dg + 1; + site.E = gout + 1; + site.delayed_group = dg + 1; // Set the delayed group on the particle as well p->delayed_group_ = dg + 1; @@ -187,9 +161,6 @@ create_fission_sites(Particle* p, Particle::Bank* bank_array, int64_t* size_bank } } - // Increment number of bank sites - *size_bank = std::min(*size_bank + nu, bank_array_size); - // Store the total weight banked for analog fission tallies p->n_bank_ = nu; p->wgt_bank_ = nu / weight; diff --git a/src/simulation.cpp b/src/simulation.cpp index b4db5e0e6..fca0c8528 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -279,14 +279,14 @@ void allocate_banks() { simulation::thread_id = omp_get_thread_num(); if (simulation::thread_id == 0) { - simulation::fission_bank.resize(3*simulation::work); + simulation::fission_bank.reserve(3*simulation::work); } else { - simulation::fission_bank.resize(3*simulation::work / simulation::n_threads); + simulation::fission_bank.reserve(3*simulation::work / simulation::n_threads); } } - simulation::master_fission_bank.resize(3*simulation::work); + simulation::master_fission_bank.reserve(3*simulation::work); #else - simulation::fission_bank.resize(3*simulation::work); + simulation::fission_bank.reserve(3*simulation::work); #endif } } @@ -386,8 +386,8 @@ void finalize_batch() void initialize_generation() { if (settings::run_mode == RUN_MODE_EIGENVALUE) { - // Reset number of fission bank sites - simulation::n_bank = 0; + // Clear out the fission bank + simulation::fission_bank.clear(); // Count source sites if using uniform fission source weighting if (settings::ufs_on) ufs_count_sites(); diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index de851ea3c..7e235fa45 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -192,7 +192,7 @@ score_fission_eout(const Particle* p, int i_tally, int i_score, int score_bin) // loop over number of particles banked for (auto i = 0; i < p->n_bank_; ++i) { - auto i_bank = simulation::n_bank - p->n_bank_ + i; + auto i_bank = simulation::fission_bank.size() - p->n_bank_ + i; const auto& bank = simulation::fission_bank[i_bank]; // get the delayed group @@ -813,7 +813,7 @@ score_general_ce(Particle* p, int i_tally, int start_index, // contribution to the fission bank to the score. score = 0.; for (auto i = 0; i < p->n_bank_; ++i) { - auto i_bank = simulation::n_bank - p->n_bank_ + i; + auto i_bank = simulation::fission_bank.size() - p->n_bank_ + i; const auto& bank = simulation::fission_bank[i_bank]; auto g = bank.delayed_group; if (g != 0) { @@ -1785,7 +1785,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // contribution to the fission bank to the score. score = 0.; for (auto i = 0; i < p->n_bank_; ++i) { - auto i_bank = simulation::n_bank - p->n_bank_ + i; + auto i_bank = simulation::fission_bank.size() - p->n_bank_ + i; const auto& bank = simulation::fission_bank[i_bank]; auto g = bank.delayed_group; if (g != 0) { From 49bf4523c37e7a449eb133cc00e020c4cc784a0a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 19 Mar 2019 10:11:39 -0500 Subject: [PATCH 108/165] Remove thread_id and n_threads global variables --- docs/source/io_formats/settings.rst | 9 --------- include/openmc/simulation.h | 6 +----- openmc/settings.py | 19 ------------------- src/bank.cpp | 2 +- src/eigenvalue.cpp | 10 ++++++++-- src/initialize.cpp | 6 +++--- src/output.cpp | 2 ++ src/particle.cpp | 4 ++-- src/physics_mg.cpp | 15 ++++++--------- src/random_lcg.cpp | 2 +- src/settings.cpp | 16 ++-------------- src/simulation.cpp | 26 +++++++++++--------------- tests/unit_tests/test_settings.py | 1 - 13 files changed, 37 insertions(+), 81 deletions(-) diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index e5c0ca160..9c68a9730 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -730,15 +730,6 @@ sections. *Default*: 10 K ---------------------- -```` Element ---------------------- - -The ```` element indicates the number of OpenMP threads to be used for -a simulation. It has no attributes and accepts a positive integer value. - - *Default*: None (Determined by environment variable :envvar:`OMP_NUM_THREADS`) - .. _trace: ------------------- diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index 3eb5b1f05..8d43108f1 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -44,12 +44,8 @@ extern std::vector work_index; // Threadprivate variables extern "C" bool trace; //!< flag to show debug information -#ifdef _OPENMP -extern "C" int n_threads; //!< number of OpenMP threads -extern "C" int thread_id; //!< ID of a given thread -#endif -#pragma omp threadprivate(current_work, thread_id, trace) +#pragma omp threadprivate(current_work, trace) } // namespace simulation diff --git a/openmc/settings.py b/openmc/settings.py index 4be2eaaa3..f348bc6cb 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -130,8 +130,6 @@ class Settings(object): range. 'multipole' is a boolean indicating whether or not the windowed multipole method should be used to evaluate resolved resonance cross sections. - threads : int - Number of OpenMP threads trace : tuple or list Show detailed information about a single particle, indicated by three integers: the batch number, generation number, and particle number @@ -197,7 +195,6 @@ class Settings(object): self._statepoint = {} self._sourcepoint = {} - self._threads = None self._no_reduce = None self._verbosity = None @@ -312,10 +309,6 @@ class Settings(object): def statepoint(self): return self._statepoint - @property - def threads(self): - return self._threads - @property def no_reduce(self): return self._no_reduce @@ -623,12 +616,6 @@ class Settings(object): self._temperature = temperature - @threads.setter - def threads(self, threads): - cv.check_type('number of threads', threads, Integral) - cv.check_greater_than('number of threads', threads, 0) - self._threads = threads - @trace.setter def trace(self, trace): cv.check_type('trace', trace, Iterable, Integral) @@ -885,11 +872,6 @@ class Settings(object): else: element.text = str(value) - def _create_threads_subelement(self, root): - if self._threads is not None: - element = ET.SubElement(root, "threads") - element.text = str(self._threads) - def _create_trace_subelement(self, root): if self._trace is not None: element = ET.SubElement(root, "trace") @@ -980,7 +962,6 @@ class Settings(object): self._create_entropy_mesh_subelement(root_element) self._create_trigger_subelement(root_element) self._create_no_reduce_subelement(root_element) - self._create_threads_subelement(root_element) self._create_verbosity_subelement(root_element) self._create_tabular_legendre_subelements(root_element) self._create_temperature_subelements(root_element) diff --git a/src/bank.cpp b/src/bank.cpp index fc48a7761..a80cfbf37 100644 --- a/src/bank.cpp +++ b/src/bank.cpp @@ -31,7 +31,7 @@ std::vector master_fission_bank; void free_memory_bank() { simulation::source_bank.clear(); -#pragma omp parallel + #pragma omp parallel { simulation::fission_bank.clear(); } diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index 170195529..f5ed493fb 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -20,6 +20,10 @@ #include "openmc/timer.h" #include "openmc/tallies/tally.h" +#ifdef _OPENMP +#include +#endif + #include // for min #include #include // for sqrt, abs, pow @@ -348,11 +352,13 @@ void calculate_average_keff() #ifdef _OPENMP void join_bank_from_threads() { + int n_threads = omp_get_max_threads(); + #pragma omp parallel { // Copy thread fission bank sites to one shared copy #pragma omp for ordered schedule(static) - for (int i = 0; i < simulation::n_threads; ++i) { + for (int i = 0; i < n_threads; ++i) { #pragma omp ordered { std::copy( @@ -367,7 +373,7 @@ void join_bank_from_threads() #pragma omp barrier // Now copy the shared fission bank sites back to the master thread's copy. - if (simulation::thread_id == 0) { + if (omp_get_thread_num() == 0) { simulation::fission_bank = simulation::master_fission_bank; simulation::master_fission_bank.clear(); } else { diff --git a/src/initialize.cpp b/src/initialize.cpp index 3aa31184f..61390651f 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -196,13 +196,13 @@ parse_command_line(int argc, char* argv[]) #ifdef _OPENMP // Read and set number of OpenMP threads - simulation::n_threads = std::stoi(argv[i]); - if (simulation::n_threads < 1) { + int n_threads = std::stoi(argv[i]); + if (n_threads < 1) { std::string msg {"Number of threads must be positive."}; strcpy(openmc_err_msg, msg.c_str()); return OPENMC_E_INVALID_ARGUMENT; } - omp_set_num_threads(simulation::n_threads); + omp_set_num_threads(n_threads); #else if (mpi::master) warning("Ignoring number of threads specified on command line."); diff --git a/src/output.cpp b/src/output.cpp index 92ad14e9d..82aaca989 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -11,7 +11,9 @@ #include #include // for pair +#ifdef _OPENMP #include +#endif #include "xtensor/xview.hpp" #include "openmc/capi.h" diff --git a/src/particle.cpp b/src/particle.cpp index 92045e2cd..ab0f6effb 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -590,7 +590,7 @@ Particle::mark_as_lost(const char* message) // Increment number of lost particles alive_ = false; -#pragma omp atomic + #pragma omp atomic simulation::n_lost_particles += 1; // Count the total number of simulated particles (on this processor) @@ -615,7 +615,7 @@ Particle::write_restart() const filename << settings::path_output << "particle_" << simulation::current_batch << '_' << id_ << ".h5"; -#pragma omp critical (WriteParticleRestart) + #pragma omp critical (WriteParticleRestart) { // Create file hid_t file_id = file_open(filename.str(), 'w'); diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index 2a6b700f0..84dfa9cde 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -174,22 +174,19 @@ absorption(Particle* p) { if (settings::survival_biasing) { // Determine weight absorbed in survival biasing - p->wgt_absorb_ = p->wgt_ * - p->macro_xs_.absorption / p->macro_xs_.total; + p->wgt_absorb_ = p->wgt_ * p->macro_xs_.absorption / p->macro_xs_.total; // Adjust weight of particle by the probability of absorption p->wgt_ -= p->wgt_absorb_; p->wgt_last_ = p->wgt_; // Score implicit absorpion estimate of keff -#pragma omp atomic - global_tally_absorption += p->wgt_absorb_ * - p->macro_xs_.nu_fission / - p->macro_xs_.absorption; + #pragma omp atomic + global_tally_absorption += p->wgt_absorb_ * p->macro_xs_.nu_fission / + p->macro_xs_.absorption; } else { - if (p->macro_xs_.absorption > - prn() * p->macro_xs_.total) { -#pragma omp atomic + if (p->macro_xs_.absorption > prn() * p->macro_xs_.total) { + #pragma omp atomic global_tally_absorption += p->wgt_ * p->macro_xs_.nu_fission / p->macro_xs_.absorption; p->alive_ = false; diff --git a/src/random_lcg.cpp b/src/random_lcg.cpp index cf5d7e34b..5002b4279 100644 --- a/src/random_lcg.cpp +++ b/src/random_lcg.cpp @@ -141,7 +141,7 @@ extern "C" void openmc_set_seed(int64_t new_seed) { seed = new_seed; -#pragma omp parallel + #pragma omp parallel { for (int i = 0; i < N_STREAMS; i++) { prn_seed[i] = seed + i; diff --git a/src/settings.cpp b/src/settings.cpp index dfa5ebb7e..4c041a080 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -383,20 +383,8 @@ void read_settings_xml() // Number of OpenMP threads if (check_for_node(root, "threads")) { -#ifdef _OPENMP - if (simulation::n_threads == 0) { - simulation::n_threads = std::stoi(get_node_value(root, "threads")); - if (simulation::n_threads < 1) { - std::stringstream msg; - msg << "Invalid number of threads: " << simulation::n_threads; - fatal_error(msg); - } - omp_set_num_threads(simulation::n_threads); - } -#else - if (mpi::master) warning("OpenMC was not compiled with OpenMP support; " - "ignoring number of threads."); -#endif + if (mpi::master) warning("The element has been deprecated. Use " + "the OMP_NUM_THREADS environment variable to set the number of threads."); } // ========================================================================== diff --git a/src/simulation.cpp b/src/simulation.cpp index fca0c8528..ea313e94c 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -20,7 +20,9 @@ #include "openmc/tallies/tally.h" #include "openmc/tallies/trigger.h" +#ifdef _OPENMP #include +#endif #include "xtensor/xview.hpp" #include @@ -59,7 +61,7 @@ int openmc_simulation_init() calculate_work(); // Allocate array for matching filter bins -#pragma omp parallel + #pragma omp parallel { simulation::filter_matches.resize(model::tally_filters.size()); } @@ -136,7 +138,7 @@ int openmc_simulation_finalize() // Write tally results to tallies.out if (settings::output_tallies && mpi::master) write_tallies(); -#pragma omp parallel + #pragma omp parallel { simulation::filter_matches.clear(); } @@ -186,7 +188,7 @@ int openmc_next_batch(int* status) // ==================================================================== // LOOP OVER PARTICLES -#pragma omp parallel for schedule(runtime) + #pragma omp parallel for schedule(runtime) for (int64_t i_work = 1; i_work <= simulation::work; ++i_work) { simulation::current_work = i_work; @@ -250,10 +252,6 @@ std::vector work_index; // Threadprivate variables bool trace; //!< flag to show debug information -#ifdef _OPENMP -int n_threads {-1}; //!< number of OpenMP threads -int thread_id; //!< ID of a given thread -#endif } // namespace simulation @@ -273,15 +271,13 @@ void allocate_banks() // a generation, there is also a 'master_fission_bank' that is used to // collect the sites from each thread. - simulation::n_threads = omp_get_max_threads(); - -#pragma omp parallel + #pragma omp parallel { - simulation::thread_id = omp_get_thread_num(); - if (simulation::thread_id == 0) { + if (omp_get_thread_num() == 0) { simulation::fission_bank.reserve(3*simulation::work); } else { - simulation::fission_bank.reserve(3*simulation::work / simulation::n_threads); + int n_threads = omp_get_num_threads(); + simulation::fission_bank.reserve(3*simulation::work / n_threads); } } simulation::master_fission_bank.reserve(3*simulation::work); @@ -403,9 +399,9 @@ void finalize_generation() auto& gt = simulation::global_tallies; // Update global tallies with the omp private accumulation variables -#pragma omp parallel + #pragma omp parallel { -#pragma omp critical(increment_global_tallies) + #pragma omp critical(increment_global_tallies) { if (settings::run_mode == RUN_MODE_EIGENVALUE) { gt(K_COLLISION, RESULT_VALUE) += global_tally_collision; diff --git a/tests/unit_tests/test_settings.py b/tests/unit_tests/test_settings.py index 697eb095f..e42f6240f 100644 --- a/tests/unit_tests/test_settings.py +++ b/tests/unit_tests/test_settings.py @@ -36,7 +36,6 @@ def test_export_to_xml(run_in_tmpdir): s.tabular_legendre = {'enable': True, 'num_points': 50} s.temperature = {'default': 293.6, 'method': 'interpolation', 'multipole': True, 'range': (200., 1000.)} - s.threads = 8 s.trace = (10, 1, 20) s.track = [1, 1, 1, 2, 1, 1] s.ufs_mesh = mesh From 279104cfed48518373efb59186758e96b4acb84e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 19 Mar 2019 10:55:05 -0500 Subject: [PATCH 109/165] Move secondary bank outside of Particle class --- include/openmc/bank.h | 3 ++- include/openmc/particle.h | 5 +---- src/bank.cpp | 1 + src/particle.cpp | 12 ++++++------ src/physics.cpp | 2 +- src/physics_mg.cpp | 2 +- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/openmc/bank.h b/include/openmc/bank.h index 4597369c7..93e2be669 100644 --- a/include/openmc/bank.h +++ b/include/openmc/bank.h @@ -22,11 +22,12 @@ namespace simulation { extern std::vector source_bank; extern std::vector fission_bank; +extern std::vector secondary_bank; #ifdef _OPENMP extern std::vector master_fission_bank; #endif -#pragma omp threadprivate(fission_bank) +#pragma omp threadprivate(fission_bank, secondary_bank) } // namespace simulation diff --git a/include/openmc/particle.h b/include/openmc/particle.h index d52c67ea5..c6156e481 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -187,7 +187,7 @@ public: //! \param u Direction of the secondary particle //! \param E Energy of the secondary particle in [eV] //! \param type Particle type - void create_secondary(Direction u, double E, Type type); + void create_secondary(Direction u, double E, Type type) const; //! initialize from a source site // @@ -283,9 +283,6 @@ public: // Track output bool write_track_ {false}; - - // Secondary particles created - std::vector secondary_bank_; }; } // namespace openmc diff --git a/src/bank.cpp b/src/bank.cpp index a80cfbf37..172ecf84f 100644 --- a/src/bank.cpp +++ b/src/bank.cpp @@ -18,6 +18,7 @@ namespace simulation { std::vector source_bank; std::vector fission_bank; +std::vector secondary_bank; #ifdef _OPENMP std::vector master_fission_bank; #endif diff --git a/src/particle.cpp b/src/particle.cpp index ab0f6effb..8ca07ca82 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -73,11 +73,11 @@ Particle::clear() } void -Particle::create_secondary(Direction u, double E, Type type) +Particle::create_secondary(Direction u, double E, Type type) const { - secondary_bank_.emplace_back(); + simulation::secondary_bank.emplace_back(); - auto& bank {secondary_bank_.back()}; + auto& bank {simulation::secondary_bank.back()}; bank.particle = type; bank.wgt = wgt_; bank.r = this->r(); @@ -357,10 +357,10 @@ Particle::transport() // Check for secondary particles if this particle is dead if (!alive_) { // If no secondary particles, break out of event loop - if (secondary_bank_.empty()) break; + if (simulation::secondary_bank.empty()) break; - this->from_source(&secondary_bank_.back()); - secondary_bank_.pop_back(); + this->from_source(&simulation::secondary_bank.back()); + simulation::secondary_bank.pop_back(); n_event = 0; // Enter new particle in particle track file diff --git a/src/physics.cpp b/src/physics.cpp index 7d44aa17c..2d48855c7 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -94,7 +94,7 @@ void sample_neutron_reaction(Particle* p) create_fission_sites(p, i_nuclide, rx, simulation::fission_bank); } else if (settings::run_mode == RUN_MODE_FIXEDSOURCE && settings::create_fission_neutrons) { - create_fission_sites(p, i_nuclide, rx, p->secondary_bank_); + create_fission_sites(p, i_nuclide, rx, simulation::secondary_bank); } } diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index 84dfa9cde..f99d15aac 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -51,7 +51,7 @@ sample_reaction(Particle* p) create_fission_sites(p, simulation::fission_bank); } else if ((settings::run_mode == RUN_MODE_FIXEDSOURCE) && (settings::create_fission_neutrons)) { - create_fission_sites(p, p->secondary_bank_); + create_fission_sites(p, simulation::secondary_bank); } } From c049557c8575bf76dbf0346633e7707fad76e94b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 19 Mar 2019 14:38:24 -0500 Subject: [PATCH 110/165] Get rid of MAX_SECONDARY constant --- include/openmc/particle.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/openmc/particle.h b/include/openmc/particle.h index c6156e481..8ec53de44 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -26,9 +26,6 @@ namespace openmc { // use to store the bins for delayed group tallies. constexpr int MAX_DELAYED_GROUPS {8}; -// Maximum number of secondary particles created -constexpr int MAX_SECONDARY {1000}; - // Maximum number of lost particles constexpr int MAX_LOST_PARTICLES {10}; From 492d984525a665f97baf02326a8b407d884883fc Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Mar 2019 13:26:04 -0500 Subject: [PATCH 111/165] Change name of work -> work_per_rank --- include/openmc/simulation.h | 2 +- src/eigenvalue.cpp | 4 ++-- src/particle.cpp | 3 ++- src/simulation.cpp | 16 ++++++++-------- src/source.cpp | 4 ++-- src/state_point.cpp | 8 ++++---- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index 8d43108f1..fef6ebbcd 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -37,7 +37,7 @@ extern "C" int restart_batch; //!< batch at which a restart job resumed extern "C" bool satisfy_triggers; //!< have tally triggers been satisfied? extern "C" int total_gen; //!< total number of generations simulated extern double total_weight; //!< Total source weight in a batch -extern "C" int64_t work; //!< number of particles per process +extern int64_t work_per_rank; //!< number of particles per MPI rank extern std::vector k_generation; extern std::vector work_index; diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index f5ed493fb..08a4d3f91 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -138,7 +138,7 @@ void synchronize_bank() // Allocate temporary source bank int64_t index_temp = 0; - std::vector temp_sites(3*simulation::work); + std::vector temp_sites(3*simulation::work_per_rank); for (const auto& site : simulation::fission_bank) { // If there are less than n_particles particles banked, automatically add @@ -597,7 +597,7 @@ void ufs_count_sites() // Since the total starting weight is not equal to n_particles, we need to // renormalize the weight of the source sites - for (int i = 0; i < simulation::work; ++i) { + for (int i = 0; i < simulation::work_per_rank; ++i) { simulation::source_bank[i].wgt *= settings::n_particles / total; } } diff --git a/src/particle.cpp b/src/particle.cpp index 8ca07ca82..d2b845bf4 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -594,7 +594,8 @@ Particle::mark_as_lost(const char* message) simulation::n_lost_particles += 1; // Count the total number of simulated particles (on this processor) - auto n = simulation::current_batch * settings::gen_per_batch * simulation::work; + auto n = simulation::current_batch * settings::gen_per_batch * + simulation::work_per_rank; // Abort the simulation if the maximum number of lost particles has been // reached diff --git a/src/simulation.cpp b/src/simulation.cpp index ea313e94c..fc7a78851 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -189,7 +189,7 @@ int openmc_next_batch(int* status) // LOOP OVER PARTICLES #pragma omp parallel for schedule(runtime) - for (int64_t i_work = 1; i_work <= simulation::work; ++i_work) { + for (int64_t i_work = 1; i_work <= simulation::work_per_rank; ++i_work) { simulation::current_work = i_work; // grab source particle from bank @@ -245,7 +245,7 @@ int restart_batch; bool satisfy_triggers {false}; int total_gen {0}; double total_weight; -int64_t work; +int64_t work_per_rank; std::vector k_generation; std::vector work_index; @@ -262,7 +262,7 @@ bool trace; //!< flag to show debug information void allocate_banks() { // Allocate source bank - simulation::source_bank.resize(simulation::work); + simulation::source_bank.resize(simulation::work_per_rank); if (settings::run_mode == RUN_MODE_EIGENVALUE) { #ifdef _OPENMP @@ -274,15 +274,15 @@ void allocate_banks() #pragma omp parallel { if (omp_get_thread_num() == 0) { - simulation::fission_bank.reserve(3*simulation::work); + simulation::fission_bank.reserve(3*simulation::work_per_rank); } else { int n_threads = omp_get_num_threads(); - simulation::fission_bank.reserve(3*simulation::work / n_threads); + simulation::fission_bank.reserve(3*simulation::work_per_rank / n_threads); } } - simulation::master_fission_bank.reserve(3*simulation::work); + simulation::master_fission_bank.reserve(3*simulation::work_per_rank); #else - simulation::fission_bank.reserve(3*simulation::work); + simulation::fission_bank.reserve(3*simulation::work_per_rank); #endif } } @@ -507,7 +507,7 @@ void calculate_work() int64_t work_i = i < remainder ? min_work + 1 : min_work; // Set number of particles - if (mpi::rank == i) simulation::work = work_i; + if (mpi::rank == i) simulation::work_per_rank = work_i; // Set index into source bank for rank i i_bank += work_i; diff --git a/src/source.cpp b/src/source.cpp index 36d66394c..0baa21b17 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -264,7 +264,7 @@ void initialize_source() } else { // Generation source sites from specified distribution in user input - for (int64_t i = 0; i < simulation::work; ++i) { + for (int64_t i = 0; i < simulation::work_per_rank; ++i) { // initialize random number seed int64_t id = simulation::total_gen*settings::n_particles + simulation::work_index[mpi::rank] + i + 1; @@ -330,7 +330,7 @@ void free_memory_source() void fill_source_bank_fixedsource() { if (settings::path_source.empty()) { - for (int64_t i = 0; i < simulation::work; ++i) { + for (int64_t i = 0; i < simulation::work_per_rank; ++i) { // initialize random number seed int64_t id = (simulation::total_gen + overall_generation()) * settings::n_particles + simulation::work_index[mpi::rank] + i + 1; diff --git a/src/state_point.cpp b/src/state_point.cpp index d657316f9..54f1cb38c 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -537,7 +537,7 @@ write_source_bank(hid_t group_id) H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); // Create another data space but for each proc individually - hsize_t count[] {static_cast(simulation::work)}; + hsize_t count[] {static_cast(simulation::work_per_rank)}; hid_t memspace = H5Screate_simple(1, count, nullptr); // Select hyperslab for this dataspace @@ -569,7 +569,7 @@ write_source_bank(hid_t group_id) // Save source bank sites since the souce_bank array is overwritten below #ifdef OPENMC_MPI std::vector temp_source {simulation::source_bank.begin(), - simulation::source_bank.begin() + simulation::work}; + simulation::source_bank.begin() + simulation::work_per_rank}; #endif for (int i = 0; i < mpi::n_procs; ++i) { @@ -607,7 +607,7 @@ write_source_bank(hid_t group_id) #endif } else { #ifdef OPENMC_MPI - MPI_Send(simulation::source_bank.data(), simulation::work, mpi::bank, + MPI_Send(simulation::source_bank.data(), simulation::work_per_rank, mpi::bank, 0, mpi::rank, mpi::intracomm); #endif } @@ -625,7 +625,7 @@ void read_source_bank(hid_t group_id) hid_t dset = H5Dopen(group_id, "source_bank", H5P_DEFAULT); // Create another data space but for each proc individually - hsize_t dims[] {static_cast(simulation::work)}; + hsize_t dims[] {static_cast(simulation::work_per_rank)}; hid_t memspace = H5Screate_simple(1, dims, nullptr); // Make sure source bank is big enough From 0fbe024e11c373e985fd5220353e57bdbca8c2dc Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 14 Mar 2019 14:47:42 -0500 Subject: [PATCH 112/165] Get rid of ERROR_INT and use 0 for "no surface" --- include/openmc/constants.h | 2 -- src/output.cpp | 2 +- src/particle.cpp | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 87388c91a..d9307abe2 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -403,8 +403,6 @@ constexpr int LEAKAGE {3}; // Miscellaneous constexpr int C_NONE {-1}; constexpr int F90_NONE {0}; //TODO: replace usage of this with C_NONE -constexpr int ERROR_INT {-2147483647}; // TODO: use when F90 - // interop is gone // Interpolation rules enum class Interpolation { diff --git a/src/output.cpp b/src/output.cpp index 82aaca989..df0976d94 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -191,7 +191,7 @@ extern "C" void print_particle(Particle* p) } // Display miscellaneous info. - if (p->surface_ != ERROR_INT) { + if (p->surface_ != 0) { const Surface& surf {*model::surfaces[std::abs(p->surface_)-1]}; std::cout << " Surface = " << std::copysign(surf.id_, p->surface_) << "\n"; } diff --git a/src/particle.cpp b/src/particle.cpp index d2b845bf4..b307aec8d 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -259,7 +259,7 @@ Particle::transport() if (lattice_translation[0] != 0 || lattice_translation[1] != 0 || lattice_translation[2] != 0) { // Particle crosses lattice boundary - surface_ = ERROR_INT; + surface_ = 0; cross_lattice(this, lattice_translation); event_ = EVENT_LATTICE; } else { @@ -291,7 +291,7 @@ Particle::transport() score_surface_tally(this, model::active_meshsurf_tallies); // Clear surface component - surface_ = ERROR_INT; + surface_ = 0; if (settings::run_CE) { collision(this); @@ -556,7 +556,7 @@ Particle::cross_surface() // COULDN'T FIND PARTICLE IN NEIGHBORING CELLS, SEARCH ALL CELLS // Remove lower coordinate levels and assignment of surface - surface_ = ERROR_INT; + surface_ = 0; n_coord_ = 1; bool found = find_cell(this, false); From 4971779f39ab84ae5826e0835ce9dea56a53a0ee Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 14 Mar 2019 16:07:00 -0500 Subject: [PATCH 113/165] Use __builtin_reachable to tell gcc about unreachable code --- src/nuclide.cpp | 3 +++ src/physics.cpp | 5 +++-- src/tallies/filter_particle.cpp | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/nuclide.cpp b/src/nuclide.cpp index cfb5a669f..8a6f1aa57 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -454,6 +454,9 @@ double Nuclide::nu(double E, EmissionMode mode, int group) const return (*fission_rx_[0]->products_[0].yield_)(E); } } +#ifdef __GNUC__ + __builtin_unreachable(); +#endif } void Nuclide::calculate_elastic_xs(Particle& p) const diff --git a/src/physics.cpp b/src/physics.cpp index 2d48855c7..3edaf4545 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -882,8 +882,9 @@ Direction sample_target_velocity(const Nuclide* nuc, double E, Direction u, } // case RVS, DBRC } // switch (sampling_method) - throw std::runtime_error{"Unable to sample target velocity for " - "elastic scattering."}; +#ifdef __GNUC__ + __builtin_unreachable(); +#endif } Direction diff --git a/src/tallies/filter_particle.cpp b/src/tallies/filter_particle.cpp index a2902785a..1d4b84937 100644 --- a/src/tallies/filter_particle.cpp +++ b/src/tallies/filter_particle.cpp @@ -50,6 +50,9 @@ ParticleFilter::text_label(int bin) const case Particle::Type::positron: return "Particle: positron"; } +#ifdef __GNUC__ + __builtin_unreachable(); +#endif } } // namespace openmc From 2e94189b1bcfa60c70fd6f06912c0757c72f6cdd Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Mar 2019 22:33:54 -0500 Subject: [PATCH 114/165] Make sure subcrit multiplication problems abort gracefully when k > 1 --- src/physics.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/physics.cpp b/src/physics.cpp index 3edaf4545..1cfd31658 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -95,6 +95,14 @@ void sample_neutron_reaction(Particle* p) } else if (settings::run_mode == RUN_MODE_FIXEDSOURCE && settings::create_fission_neutrons) { create_fission_sites(p, i_nuclide, rx, simulation::secondary_bank); + + // Make sure particle population doesn't grow out of control for + // subcritical multiplication problems. + if (simulation::secondary_bank.size() >= 10000) { + fatal_error("The secondary particle bank appears to be growing without " + "bound. You are likely running a subcritical multiplication problem " + "with k-effective close to or greater than one."); + } } } From c60ecd7e8f688927904e818535c2d30d420b76e0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 21 Mar 2019 07:43:42 -0500 Subject: [PATCH 115/165] Have distance_to_boundary return a struct --- include/openmc/geometry.h | 26 +++++++++++------- src/geometry.cpp | 56 +++++++++++++++++---------------------- src/particle.cpp | 24 +++++++---------- 3 files changed, 52 insertions(+), 54 deletions(-) diff --git a/include/openmc/geometry.h b/include/openmc/geometry.h index 9bb1a9ae7..5feca2992 100644 --- a/include/openmc/geometry.h +++ b/include/openmc/geometry.h @@ -1,6 +1,8 @@ #ifndef OPENMC_GEOMETRY_H #define OPENMC_GEOMETRY_H +#include +#include #include #include @@ -22,12 +24,22 @@ extern std::vector overlap_check_count; } // namespace model +//============================================================================== +// Information about nearest boundary crossing +//============================================================================== + +struct BoundaryInfo { + double distance {INFINITY}; //!< distance to nearest boundary + int surface_index {0}; //!< if boundary is surface, index in surfaces vector + int coord_level; //!< coordinate level after crossing boundary + std::array lattice_translation {}; //!< which way lattice indices will change +}; + //============================================================================== //! Check for overlapping cells at a particle's position. //============================================================================== -extern "C" bool -check_cell_overlap(Particle* p); +bool check_cell_overlap(Particle* p); //============================================================================== //! Locate a particle in the geometry tree and set its geometry data fields. @@ -41,23 +53,19 @@ check_cell_overlap(Particle* p); //! valid geometry coordinate stack. //============================================================================== -extern "C" bool -find_cell(Particle* p, bool use_neighbor_lists); +bool find_cell(Particle* p, bool use_neighbor_lists); //============================================================================== //! Move a particle into a new lattice tile. //============================================================================== -extern "C" void -cross_lattice(Particle* p, int lattice_translation[3]); +void cross_lattice(Particle* p, const BoundaryInfo& boundary); //============================================================================== //! Find the next boundary a particle will intersect. //============================================================================== -extern "C" void -distance_to_boundary(Particle* p, double* dist, int* surface_crossed, - int lattice_translation[3], int* next_level); +BoundaryInfo distance_to_boundary(Particle* p); } // namespace openmc diff --git a/src/geometry.cpp b/src/geometry.cpp index cde2cdc1b..6eaa61fe2 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -32,8 +32,7 @@ std::vector overlap_check_count; // Non-member functions //============================================================================== -extern "C" bool -check_cell_overlap(Particle* p) +bool check_cell_overlap(Particle* p) { int n_coord = p->n_coord_; @@ -246,7 +245,7 @@ find_cell_inner(Particle* p, const NeighborList* neighbor_list) //============================================================================== -extern "C" bool +bool find_cell(Particle* p, bool use_neighbor_lists) { // Determine universe (if not yet set, use root universe). @@ -288,8 +287,8 @@ find_cell(Particle* p, bool use_neighbor_lists) //============================================================================== -extern "C" void -cross_lattice(Particle* p, int lattice_translation[3]) +void +cross_lattice(Particle* p, const BoundaryInfo& boundary) { auto& lat {*model::lattices[p->coord_[p->n_coord_-1].lattice]}; @@ -303,9 +302,9 @@ cross_lattice(Particle* p, int lattice_translation[3]) } // Set the lattice indices. - p->coord_[p->n_coord_-1].lattice_x += lattice_translation[0]; - p->coord_[p->n_coord_-1].lattice_y += lattice_translation[1]; - p->coord_[p->n_coord_-1].lattice_z += lattice_translation[2]; + p->coord_[p->n_coord_-1].lattice_x += boundary.lattice_translation[0]; + p->coord_[p->n_coord_-1].lattice_y += boundary.lattice_translation[1]; + p->coord_[p->n_coord_-1].lattice_z += boundary.lattice_translation[2]; std::array i_xyz {p->coord_[p->n_coord_-1].lattice_x, p->coord_[p->n_coord_-1].lattice_y, p->coord_[p->n_coord_-1].lattice_z}; @@ -346,16 +345,11 @@ cross_lattice(Particle* p, int lattice_translation[3]) //============================================================================== -extern "C" void -distance_to_boundary(Particle* p, double* dist, int* surface_crossed, - int lattice_translation[3], int* next_level) +BoundaryInfo distance_to_boundary(Particle* p) { - *dist = INFINITY; + BoundaryInfo info; double d_lat = INFINITY; double d_surf = INFINITY; - lattice_translation[0] = 0; - lattice_translation[1] = 0; - lattice_translation[2] = 0; int32_t level_surf_cross; std::array level_lat_trans; @@ -402,43 +396,43 @@ distance_to_boundary(Particle* p, double* dist, int* surface_crossed, // If the boundary on this coordinate level is coincident with a boundary on // a higher level then we need to make sure that the higher level boundary // is selected. This logic must consider floating point precision. + double& d = info.distance; if (d_surf < d_lat) { - if (*dist == INFINITY || ((*dist) - d_surf)/(*dist) >= FP_REL_PRECISION) { - *dist = d_surf; + if (d == INFINITY || (d - d_surf)/d >= FP_REL_PRECISION) { + d = d_surf; // If the cell is not simple, it is possible that both the negative and // positive half-space were given in the region specification. Thus, we // have to explicitly check which half-space the particle would be // traveling into if the surface is crossed if (c.simple_) { - *surface_crossed = level_surf_cross; + info.surface_index = level_surf_cross; } else { Position r_hit = r + d_surf * u; Surface& surf {*model::surfaces[std::abs(level_surf_cross)-1]}; Direction norm = surf.normal(r_hit); if (u.dot(norm) > 0) { - *surface_crossed = std::abs(level_surf_cross); + info.surface_index = std::abs(level_surf_cross); } else { - *surface_crossed = -std::abs(level_surf_cross); + info.surface_index = -std::abs(level_surf_cross); } } - lattice_translation[0] = 0; - lattice_translation[1] = 0; - lattice_translation[2] = 0; - *next_level = i + 1; + info.lattice_translation[0] = 0; + info.lattice_translation[1] = 0; + info.lattice_translation[2] = 0; + info.coord_level = i + 1; } } else { - if (*dist == INFINITY || ((*dist) - d_lat)/(*dist) >= FP_REL_PRECISION) { - *dist = d_lat; - *surface_crossed = F90_NONE; - lattice_translation[0] = level_lat_trans[0]; - lattice_translation[1] = level_lat_trans[1]; - lattice_translation[2] = level_lat_trans[2]; - *next_level = i + 1; + if (d == INFINITY || (d - d_lat)/d >= FP_REL_PRECISION) { + d = d_lat; + info.surface_index = 0; + info.lattice_translation = level_lat_trans; + info.coord_level = i + 1; } } } + return info; } //============================================================================== diff --git a/src/particle.cpp b/src/particle.cpp index b307aec8d..4e0066b20 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -202,12 +202,7 @@ Particle::transport() } // Find the distance to the nearest boundary - double d_boundary; - int surface_crossed; - int lattice_translation[3]; - int next_level; - distance_to_boundary(this, &d_boundary, &surface_crossed, - lattice_translation, &next_level); + auto boundary = distance_to_boundary(this); // Sample a distance to collision double d_collision; @@ -221,7 +216,7 @@ Particle::transport() } // Select smaller of the two distances - double distance = std::min(d_boundary, d_collision); + double distance = std::min(boundary.distance, d_collision); // Advance particle for (int j = 0; j < n_coord_; ++j) { @@ -244,11 +239,13 @@ Particle::transport() score_track_derivative(this, distance); } - if (d_collision > d_boundary) { + if (d_collision > boundary.distance) { // ==================================================================== // PARTICLE CROSSES SURFACE - if (next_level > 0) n_coord_ = next_level; + // Set surface that particle is on and adjust coordinate levels + surface_ = boundary.surface_index; + n_coord_ = boundary.coord_level; // Saving previous cell data for (int j = 0; j < n_coord_; ++j) { @@ -256,15 +253,14 @@ Particle::transport() } n_coord_last_ = n_coord_; - if (lattice_translation[0] != 0 || lattice_translation[1] != 0 || - lattice_translation[2] != 0) { + if (boundary.lattice_translation[0] != 0 || + boundary.lattice_translation[1] != 0 || + boundary.lattice_translation[2] != 0) { // Particle crosses lattice boundary - surface_ = 0; - cross_lattice(this, lattice_translation); + cross_lattice(this, boundary); event_ = EVENT_LATTICE; } else { // Particle crosses surface - surface_ = surface_crossed; this->cross_surface(); event_ = EVENT_SURFACE; } From c231e197077ac6d10f695f58628af2c9b2c300f9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 25 Mar 2019 21:55:22 -0500 Subject: [PATCH 116/165] Fix profile option in CMakeLists.txt --- CMakeLists.txt | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 930b1e0bb..15c3cd1b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,9 +35,6 @@ endif() #=============================================================================== if(dagmc) find_package(DAGMC REQUIRED) - if(NOT DAGMC_FOUND) - message(FATAL_ERROR "Could not find DAGMC installation") - endif() link_directories(${DAGMC_LIBRARY_DIRS}) endif() @@ -63,10 +60,7 @@ if(NOT DEFINED HDF5_PREFER_PARALLEL) endif() endif() -find_package(HDF5 COMPONENTS HL) -if(NOT HDF5_FOUND) - message(FATAL_ERROR "Could not find HDF5") -endif() +find_package(HDF5 REQUIRED COMPONENTS HL) if(HDF5_IS_PARALLEL) if(NOT MPI_ENABLED) message(FATAL_ERROR "Parallel HDF5 must be used with MPI.") @@ -95,7 +89,7 @@ if(debug) list(APPEND cxxflags -g -O0) endif() if(profile) - list(APPEND cxxflags -pg) + list(APPEND cxxflags -g -fno-omit-frame-pointer) endif() if(optimize) list(REMOVE_ITEM cxxflags -O2) @@ -103,8 +97,8 @@ if(optimize) endif() # Show flags being used -message(STATUS "C++ flags: ${cxxflags}") -message(STATUS "Linker flags: ${ldflags}") +message(STATUS "OpenMC C++ flags: ${cxxflags}") +message(STATUS "OpenMC Linker flags: ${ldflags}") #=============================================================================== # pugixml library @@ -146,7 +140,7 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # the RPATH to be used when installing, but only if it's not a system directory list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) if("${isSystemDir}" STREQUAL "-1") - set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") endif() #=============================================================================== From 2982ce884dabe47fc284616b73d269d80bb0cd85 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 30 Jan 2019 11:06:06 -0600 Subject: [PATCH 117/165] Rely on FindHDF5.cmake that is distributed with CMake --- CMakeLists.txt | 8 +- cmake/Modules/FindHDF5.cmake | 399 ----------------------------------- 2 files changed, 4 insertions(+), 403 deletions(-) delete mode 100644 cmake/Modules/FindHDF5.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 15c3cd1b7..2bad48f58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.3 FATAL_ERROR) -project(openmc CXX) +project(openmc C CXX) # Setup output directories set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) @@ -60,7 +60,7 @@ if(NOT DEFINED HDF5_PREFER_PARALLEL) endif() endif() -find_package(HDF5 REQUIRED COMPONENTS HL) +find_package(HDF5 REQUIRED COMPONENTS C HL) if(HDF5_IS_PARALLEL) if(NOT MPI_ENABLED) message(FATAL_ERROR "Parallel HDF5 must be used with MPI.") @@ -270,8 +270,8 @@ endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. -target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml - faddeeva xtensor) +target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES} + pugixml faddeeva xtensor) if(dagmc) target_compile_definitions(libopenmc PRIVATE DAGMC) diff --git a/cmake/Modules/FindHDF5.cmake b/cmake/Modules/FindHDF5.cmake deleted file mode 100644 index 7492ea750..000000000 --- a/cmake/Modules/FindHDF5.cmake +++ /dev/null @@ -1,399 +0,0 @@ -#.rst: -# FindHDF5 -# -------- -# -# Find HDF5, a library for reading and writing self describing array data. -# -# -# -# This module invokes the HDF5 wrapper compiler that should be installed -# alongside HDF5. Depending upon the HDF5 Configuration, the wrapper -# compiler is called either h5cc or h5pcc. If this succeeds, the module -# will then call the compiler with the -show argument to see what flags -# are used when compiling an HDF5 client application. -# -# The module will optionally accept the COMPONENTS argument. If no -# COMPONENTS are specified, then the find module will default to finding -# only the HDF5 C library. If one or more COMPONENTS are specified, the -# module will attempt to find the language bindings for the specified -# components. The only valid components are C, CXX, Fortran, HL, and -# Fortran_HL. If the COMPONENTS argument is not given, the module will -# attempt to find only the C bindings. -# -# On UNIX systems, this module will read the variable -# HDF5_USE_STATIC_LIBRARIES to determine whether or not to prefer a -# static link to a dynamic link for HDF5 and all of it's dependencies. -# To use this feature, make sure that the HDF5_USE_STATIC_LIBRARIES -# variable is set before the call to find_package. -# -# To provide the module with a hint about where to find your HDF5 -# installation, you can set the environment variable HDF5_ROOT. The -# Find module will then look in this path when searching for HDF5 -# executables, paths, and libraries. -# -# In addition to finding the includes and libraries required to compile -# an HDF5 client application, this module also makes an effort to find -# tools that come with the HDF5 distribution that may be useful for -# regression testing. -# -# This module will define the following variables: -# -# :: -# -# HDF5_INCLUDE_DIRS - Location of the hdf5 includes -# HDF5_INCLUDE_DIR - Location of the hdf5 includes (deprecated) -# HDF5_DEFINITIONS - Required compiler definitions for HDF5 -# HDF5_C_LIBRARIES - Required libraries for the HDF5 C bindings. -# HDF5_CXX_LIBRARIES - Required libraries for the HDF5 C++ bindings -# HDF5_Fortran_LIBRARIES - Required libraries for the HDF5 Fortran bindings -# HDF5_HL_LIBRARIES - Required libraries for the HDF5 high level API -# HDF5_Fortran_HL_LIBRARIES - Required libraries for the high level Fortran -# bindings. -# HDF5_LIBRARIES - Required libraries for all requested bindings -# HDF5_FOUND - true if HDF5 was found on the system -# HDF5_VERSION - HDF5 version in format Major.Minor.Release -# HDF5_LIBRARY_DIRS - the full set of library directories -# HDF5_IS_PARALLEL - Whether or not HDF5 was found with parallel IO support -# HDF5_C_COMPILER_EXECUTABLE - the path to the HDF5 C wrapper compiler -# HDF5_CXX_COMPILER_EXECUTABLE - the path to the HDF5 C++ wrapper compiler -# HDF5_Fortran_COMPILER_EXECUTABLE - the path to the HDF5 Fortran wrapper compiler -# HDF5_DIFF_EXECUTABLE - the path to the HDF5 dataset comparison tool - -#============================================================================= -# Copyright 2015 Axel Huebl, Helmholtz-Zentrum Dresden - Rossendorf -# Copyright 2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# This module is maintained by Will Dicharry . - -include(SelectLibraryConfigurations) -include(FindPackageHandleStandardArgs) - -# List of the valid HDF5 components -set( HDF5_VALID_COMPONENTS - C - CXX - Fortran - HL - Fortran_HL -) - -# Validate the list of find components. -if( NOT HDF5_FIND_COMPONENTS ) - set( HDF5_LANGUAGE_BINDINGS "C" ) -else() - # add the extra specified components, ensuring that they are valid. - foreach( component ${HDF5_FIND_COMPONENTS} ) - list( FIND HDF5_VALID_COMPONENTS ${component} component_location ) - if( ${component_location} EQUAL -1 ) - message( FATAL_ERROR - "\"${component}\" is not a valid HDF5 component." ) - else() - list( APPEND HDF5_LANGUAGE_BINDINGS ${component} ) - endif() - endforeach() -endif() - -# Determine whether to search for serial or parallel executable first -if(HDF5_PREFER_PARALLEL) - set(HDF5_C_COMPILER_NAMES h5pcc h5cc) - set(HDF5_CXX_COMPILER_NAMES h5pc++ h5c++) - set(HDF5_Fortran_COMPILER_NAMES h5pfc h5fc) -else() - set(HDF5_C_COMPILER_NAMES h5cc h5pcc) - set(HDF5_CXX_COMPILER_NAMES h5c++ h5pc++) - set(HDF5_Fortran_COMPILER_NAMES h5fc h5pfc) -endif() - -# try to find the HDF5 wrapper compilers -find_program( HDF5_C_COMPILER_EXECUTABLE - NAMES ${HDF5_C_COMPILER_NAMES} - HINTS ENV HDF5_ROOT - PATH_SUFFIXES bin Bin - DOC "HDF5 Wrapper compiler. Used only to detect HDF5 compile flags." ) -mark_as_advanced( HDF5_C_COMPILER_EXECUTABLE ) - -find_program( HDF5_CXX_COMPILER_EXECUTABLE - NAMES ${HDF5_CXX_COMPILER_NAMES} - HINTS ENV HDF5_ROOT - PATH_SUFFIXES bin Bin - DOC "HDF5 C++ Wrapper compiler. Used only to detect HDF5 compile flags." ) -mark_as_advanced( HDF5_CXX_COMPILER_EXECUTABLE ) - -find_program( HDF5_Fortran_COMPILER_EXECUTABLE - NAMES ${HDF5_Fortran_COMPILER_NAMES} - HINTS ENV HDF5_ROOT - PATH_SUFFIXES bin Bin - DOC "HDF5 Fortran Wrapper compiler. Used only to detect HDF5 compile flags." ) -mark_as_advanced( HDF5_Fortran_COMPILER_EXECUTABLE ) - -unset(HDF5_C_COMPILER_NAMES) -unset(HDF5_CXX_COMPILER_NAMES) -unset(HDF5_Fortran_COMPILER_NAMES) - -find_program( HDF5_DIFF_EXECUTABLE - NAMES h5diff - HINTS ENV HDF5_ROOT - PATH_SUFFIXES bin Bin - DOC "HDF5 file differencing tool." ) -mark_as_advanced( HDF5_DIFF_EXECUTABLE ) - -# Invoke the HDF5 wrapper compiler. The compiler return value is stored to the -# return_value argument, the text output is stored to the output variable. -macro( _HDF5_invoke_compiler language output return_value ) - if( HDF5_${language}_COMPILER_EXECUTABLE ) - exec_program( ${HDF5_${language}_COMPILER_EXECUTABLE} - ARGS -show - OUTPUT_VARIABLE ${output} - RETURN_VALUE ${return_value} - ) - if( ${${return_value}} EQUAL 0 ) - # do nothing - else() - message( STATUS - "Unable to determine HDF5 ${language} flags from HDF5 wrapper." ) - endif() - endif() -endmacro() - -# Parse a compile line for definitions, includes, library paths, and libraries. -macro( _HDF5_parse_compile_line - compile_line_var - include_paths - definitions - library_paths - libraries ) - - # Match the include paths - string( REGEX MATCHALL "-I([^\" ]+)" include_path_flags - "${${compile_line_var}}" - ) - foreach( IPATH ${include_path_flags} ) - string( REGEX REPLACE "^-I" "" IPATH ${IPATH} ) - string( REPLACE "//" "/" IPATH ${IPATH} ) - list( APPEND ${include_paths} ${IPATH} ) - endforeach() - - # Match the definitions - string( REGEX MATCHALL "-D[^ ]*" definition_flags "${${compile_line_var}}" ) - foreach( DEF ${definition_flags} ) - list( APPEND ${definitions} ${DEF} ) - endforeach() - - # Match the library paths - string( REGEX MATCHALL "-L([^\" ]+|\"[^\"]+\")" library_path_flags - "${${compile_line_var}}" - ) - - foreach( LPATH ${library_path_flags} ) - string( REGEX REPLACE "^-L" "" LPATH ${LPATH} ) - string( REPLACE "//" "/" LPATH ${LPATH} ) - list( APPEND ${library_paths} ${LPATH} ) - endforeach() - - # now search for the library names specified in the compile line (match -l...) - # match only -l's preceded by a space or comma - # this is to exclude directory names like xxx-linux/ - string( REGEX MATCHALL "[, ]-l([^\", ]+)" library_name_flags - "${${compile_line_var}}" ) - # strip the -l from all of the library flags and add to the search list - foreach( LIB ${library_name_flags} ) - string( REGEX REPLACE "^[, ]-l" "" LIB ${LIB} ) - list( APPEND ${libraries} ${LIB} ) - endforeach() -endmacro() - -# Try to find HDF5 using an installed hdf5-config.cmake -if( NOT HDF5_FOUND ) - find_package( HDF5 QUIET NO_MODULE ) - if( HDF5_FOUND ) - set( HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR} ) - set( HDF5_LIBRARIES ) - set( HDF5_C_TARGET hdf5 ) - set( HDF5_CXX_TARGET hdf5_cpp ) - set( HDF5_HL_TARGET hdf5_hl ) - set( HDF5_Fortran_TARGET hdf5_fortran ) - set( HDF5_Fortran_HL_TARGET hdf5_hl_fortran ) - foreach( _component ${HDF5_LANGUAGE_BINDINGS} ) - list( FIND HDF5_VALID_COMPONENTS ${_component} _component_location ) - get_target_property( _comp_location ${HDF5_${_component}_TARGET} LOCATION ) - if( _comp_location ) - set( HDF5_${_component}_LIBRARY ${_comp_location} CACHE PATH - "HDF5 ${_component} library" ) - mark_as_advanced( HDF5_${_component}_LIBRARY ) - list( APPEND HDF5_LIBRARIES ${HDF5_${_component}_LIBRARY} ) - endif() - endforeach() - endif() -endif() - -if( NOT HDF5_FOUND ) - _HDF5_invoke_compiler( C HDF5_C_COMPILE_LINE HDF5_C_RETURN_VALUE ) - _HDF5_invoke_compiler( CXX HDF5_CXX_COMPILE_LINE HDF5_CXX_RETURN_VALUE ) - _HDF5_invoke_compiler( Fortran HDF5_Fortran_COMPILE_LINE HDF5_Fortran_RETURN_VALUE ) - set(HDF5_HL_COMPILE_LINE ${HDF5_C_COMPILE_LINE}) - set(HDF5_Fortran_HL_COMPILE_LINE ${HDF5_Fortran_COMPILE_LINE}) - - # seed the initial lists of libraries to find with items we know we need - set( HDF5_C_LIBRARY_NAMES_INIT hdf5 ) - set( HDF5_HL_LIBRARY_NAMES_INIT hdf5_hl ${HDF5_C_LIBRARY_NAMES_INIT} ) - set( HDF5_CXX_LIBRARY_NAMES_INIT hdf5_cpp ${HDF5_C_LIBRARY_NAMES_INIT} ) - set( HDF5_Fortran_LIBRARY_NAMES_INIT hdf5_fortran - ${HDF5_C_LIBRARY_NAMES_INIT} ) - set( HDF5_Fortran_HL_LIBRARY_NAMES_INIT hdf5hl_fortran hdf5_hl - ${HDF5_Fortran_LIBRARY_NAMES_INIT} ) - - foreach( LANGUAGE ${HDF5_LANGUAGE_BINDINGS} ) - if( HDF5_${LANGUAGE}_COMPILE_LINE ) - _HDF5_parse_compile_line( HDF5_${LANGUAGE}_COMPILE_LINE - HDF5_${LANGUAGE}_INCLUDE_FLAGS - HDF5_${LANGUAGE}_DEFINITIONS - HDF5_${LANGUAGE}_LIBRARY_DIRS - HDF5_${LANGUAGE}_LIBRARY_NAMES - ) - - # take a guess that the includes may be in the 'include' sibling - # directory of a library directory. - foreach( dir ${HDF5_${LANGUAGE}_LIBRARY_DIRS} ) - list( APPEND HDF5_${LANGUAGE}_INCLUDE_FLAGS ${dir}/../include ) - endforeach() - endif() - - # set the definitions for the language bindings. - list( APPEND HDF5_DEFINITIONS ${HDF5_${LANGUAGE}_DEFINITIONS} ) - - # find the HDF5 include directories - if(${LANGUAGE} MATCHES "Fortran") - set(HDF5_INCLUDE_FILENAME hdf5.mod) - else() - set(HDF5_INCLUDE_FILENAME hdf5.h) - endif() - - find_path( HDF5_${LANGUAGE}_INCLUDE_DIR ${HDF5_INCLUDE_FILENAME} - HINTS - ${HDF5_${LANGUAGE}_INCLUDE_FLAGS} - ENV - HDF5_ROOT - PATHS - $ENV{HOME}/.local/include - PATH_SUFFIXES - include - Include - ) - mark_as_advanced( HDF5_${LANGUAGE}_INCLUDE_DIR ) - list( APPEND HDF5_INCLUDE_DIRS ${HDF5_${LANGUAGE}_INCLUDE_DIR} ) - - # find the HDF5 libraries - foreach( LIB ${HDF5_${LANGUAGE}_LIBRARY_NAMES_INIT} ) - if( UNIX AND HDF5_USE_STATIC_LIBRARIES ) - # According to bug 1643 on the CMake bug tracker, this is the - # preferred method for searching for a static library. - # See http://www.cmake.org/Bug/view.php?id=1643. We search - # first for the full static library name, but fall back to a - # generic search on the name if the static search fails. - set( THIS_LIBRARY_SEARCH_DEBUG lib${LIB}d.a ${LIB}d ) - set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a ${LIB} ) - else() - set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d ) - set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} ) - endif() - find_library( HDF5_${LIB}_LIBRARY_DEBUG - NAMES ${THIS_LIBRARY_SEARCH_DEBUG} - HINTS ${HDF5_${LANGUAGE}_LIBRARY_DIRS} - ENV HDF5_ROOT - PATH_SUFFIXES lib Lib ) - find_library( HDF5_${LIB}_LIBRARY_RELEASE - NAMES ${THIS_LIBRARY_SEARCH_RELEASE} - HINTS ${HDF5_${LANGUAGE}_LIBRARY_DIRS} - ENV HDF5_ROOT - PATH_SUFFIXES lib Lib ) - select_library_configurations( HDF5_${LIB} ) - list(APPEND HDF5_${LANGUAGE}_LIBRARIES ${HDF5_${LIB}_LIBRARY}) - endforeach() - list( APPEND HDF5_LIBRARY_DIRS ${HDF5_${LANGUAGE}_LIBRARY_DIRS} ) - - # When the wrapper lists a library with -l, e.g. -lz, simply use it as - # is. If find_library is called for these libraries, you end up with - # local libraries that will not be suitable when cross-compiling for the - # Intel Xeon Phi. - foreach(LIBNAME ${HDF5_${LANGUAGE}_LIBRARY_NAMES}) - list(APPEND HDF5_${LANGUAGE}_LIBRARIES "-l${LIBNAME}") - endforeach() - - # Append the libraries for this language binding to the list of all - # required libraries. - list(APPEND HDF5_LIBRARIES ${HDF5_${LANGUAGE}_LIBRARIES}) - endforeach() - - # We may have picked up some duplicates in various lists during the above - # process for the language bindings (both the C and C++ bindings depend on - # libz for example). Remove the duplicates. It appears that the default - # CMake behavior is to remove duplicates from the end of a list. However, - # for link lines, this is incorrect since unresolved symbols are searched - # for down the link line. Therefore, we reverse the list, remove the - # duplicates, and then reverse it again to get the duplicates removed from - # the beginning. - macro( _remove_duplicates_from_beginning _list_name ) - list( REVERSE ${_list_name} ) - list( REMOVE_DUPLICATES ${_list_name} ) - list( REVERSE ${_list_name} ) - endmacro() - - if( HDF5_INCLUDE_DIRS ) - _remove_duplicates_from_beginning( HDF5_INCLUDE_DIRS ) - endif() - if( HDF5_LIBRARY_DIRS ) - _remove_duplicates_from_beginning( HDF5_LIBRARY_DIRS ) - endif() - - # If the HDF5 include directory was found, open H5pubconf.h to determine if - # HDF5 was compiled with parallel IO support - set( HDF5_IS_PARALLEL FALSE ) - set( HDF5_VERSION "" ) - foreach( _dir IN LISTS HDF5_INCLUDE_DIRS ) - foreach(_hdr "${_dir}/H5pubconf.h" "${_dir}/H5pubconf-64.h" "${_dir}/H5pubconf-32.h") - if( EXISTS "${_hdr}" ) - file( STRINGS "${_hdr}" - HDF5_HAVE_PARALLEL_DEFINE - REGEX "HAVE_PARALLEL 1" ) - if( HDF5_HAVE_PARALLEL_DEFINE ) - set( HDF5_IS_PARALLEL TRUE ) - endif() - unset(HDF5_HAVE_PARALLEL_DEFINE) - - file( STRINGS "${_hdr}" - HDF5_VERSION_DEFINE - REGEX "^[ \t]*#[ \t]*define[ \t]+H5_VERSION[ \t]+" ) - if( "${HDF5_VERSION_DEFINE}" MATCHES - "H5_VERSION[ \t]+\"([0-9]+\\.[0-9]+\\.[0-9]+).*\"" ) - set( HDF5_VERSION "${CMAKE_MATCH_1}" ) - endif() - unset(HDF5_VERSION_DEFINE) - endif() - endforeach() - endforeach() - set( HDF5_IS_PARALLEL ${HDF5_IS_PARALLEL} CACHE BOOL - "HDF5 library compiled with parallel IO support" ) - mark_as_advanced( HDF5_IS_PARALLEL ) - - # For backwards compatibility we set HDF5_INCLUDE_DIR to the value of - # HDF5_INCLUDE_DIRS - if( HDF5_INCLUDE_DIRS ) - set( HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIRS}" ) - endif() - -endif() - -find_package_handle_standard_args( HDF5 - REQUIRED_VARS HDF5_LIBRARIES HDF5_INCLUDE_DIRS - VERSION_VAR HDF5_VERSION -) From 1b48802da1951571ef5c6bd87db8ec5e6e0348af Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 25 Mar 2019 21:58:52 -0500 Subject: [PATCH 118/165] Use message(STATUS ...) in two places in CMakeLists.txt --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bad48f58..4033d2466 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ option(dagmc "Enable support for DAGMC (CAD) geometry" OFF) set(MPI_ENABLED FALSE) if($ENV{CXX} MATCHES "(mpi[^/]*|CC)$") - message("-- Detected MPI wrapper: $ENV{CXX}") + message(STATUS "Detected MPI wrapper: $ENV{CXX}") set(MPI_ENABLED TRUE) endif() @@ -65,7 +65,7 @@ if(HDF5_IS_PARALLEL) if(NOT MPI_ENABLED) message(FATAL_ERROR "Parallel HDF5 must be used with MPI.") endif() - message("-- Using parallel HDF5") + message(STATUS "Using parallel HDF5") endif() #=============================================================================== From 34a3fe2519f59a33c819e340edf5c607cc3af824 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 25 Mar 2019 22:11:03 -0500 Subject: [PATCH 119/165] Fix Cell.from_xml_element when multiple temperatures are specified --- openmc/cell.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openmc/cell.py b/openmc/cell.py index 8503deffa..8381fa8d8 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -571,7 +571,10 @@ class Cell(IDManagerMixin): # Check for other attributes t = get_text(elem, 'temperature') if t is not None: - c.temperature = float(t) + if ' ' in t: + c.temperature = [float(t_i) for t_i in t.split()] + else: + c.temperature = float(t) for key in ('temperature', 'rotation', 'translation'): value = get_text(elem, key) if value is not None: From fefb68a866c2f9ba60e8a67d23f594fcd2dd2f33 Mon Sep 17 00:00:00 2001 From: liangjg Date: Tue, 26 Mar 2019 13:32:50 -0400 Subject: [PATCH 120/165] Add from_hdf5() in IncidentPhoton --- openmc/data/photon.py | 428 ++++++++++++++++++++++++++++++------------ 1 file changed, 308 insertions(+), 120 deletions(-) diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 47bdbf1d9..d8f46f9a4 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -19,13 +19,13 @@ from .endf import Evaluation, get_head_record, get_tab1_record, get_list_record from .function import Tabulated1D +# Electron subshell labels _SUBSHELLS = ['K', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5', 'N1', 'N2', 'N3', 'N4', 'N5', 'N6', 'N7', 'O1', 'O2', 'O3', 'O4', 'O5', 'O6', 'O7', 'O8', 'O9', 'P1', 'P2', 'P3', 'P4', 'P5', 'P6', 'P7', 'P8', 'P9', 'P10', 'P11', 'Q1', 'Q2', 'Q3'] - # Helper function to map designator to subshell string or None def _subshell(i): if i == 0: @@ -33,57 +33,56 @@ def _subshell(i): else: return _SUBSHELLS[i - 1] - _REACTION_NAME = { - 501: 'Total photon interaction', - 502: 'Photon coherent scattering', - 504: 'Photon incoherent scattering', - 515: 'Pair production, electron field', - 516: 'Total pair production', - 517: 'Pair production, nuclear field', - 522: 'Photoelectric absorption', - 526: 'Electro-atomic scattering', - 527: 'Electro-atomic bremsstrahlung', - 528: 'Electro-atomic excitation', - 534: 'K (1s1/2) subshell photoelectric', - 535: 'L1 (2s1/2) subshell photoelectric', - 536: 'L2 (2p1/2) subshell photoelectric', - 537: 'L3 (2p3/2) subshell photoelectric', - 538: 'M1 (3s1/2) subshell photoelectric', - 539: 'M2 (3p1/2) subshell photoelectric', - 540: 'M3 (3p3/2) subshell photoelectric', - 541: 'M4 (3d3/2) subshell photoelectric', - 542: 'M5 (3d5/2) subshell photoelectric', - 543: 'N1 (4s1/2) subshell photoelectric', - 544: 'N2 (4p1/2) subshell photoelectric', - 545: 'N3 (4p3/2) subshell photoelectric', - 546: 'N4 (4d3/2) subshell photoelectric', - 547: 'N5 (4d5/2) subshell photoelectric', - 548: 'N6 (4f5/2) subshell photoelectric', - 549: 'N7 (4f7/2) subshell photoelectric', - 550: 'O1 (5s1/2) subshell photoelectric', - 551: 'O2 (5p1/2) subshell photoelectric', - 552: 'O3 (5p3/2) subshell photoelectric', - 553: 'O4 (5d3/2) subshell photoelectric', - 554: 'O5 (5d5/2) subshell photoelectric', - 555: 'O6 (5f5/2) subshell photoelectric', - 556: 'O7 (5f7/2) subshell photoelectric', - 557: 'O8 (5g7/2) subshell photoelectric', - 558: 'O9 (5g9/2) subshell photoelectric', - 559: 'P1 (6s1/2) subshell photoelectric', - 560: 'P2 (6p1/2) subshell photoelectric', - 561: 'P3 (6p3/2) subshell photoelectric', - 562: 'P4 (6d3/2) subshell photoelectric', - 563: 'P5 (6d5/2) subshell photoelectric', - 564: 'P6 (6f5/2) subshell photoelectric', - 565: 'P7 (6f7/2) subshell photoelectric', - 566: 'P8 (6g7/2) subshell photoelectric', - 567: 'P9 (6g9/2) subshell photoelectric', - 568: 'P10 (6h9/2) subshell photoelectric', - 569: 'P11 (6h11/2) subshell photoelectric', - 570: 'Q1 (7s1/2) subshell photoelectric', - 571: 'Q2 (7p1/2) subshell photoelectric', - 572: 'Q3 (7p3/2) subshell photoelectric' + 501: ('Total photon interaction', 'total'), + 502: ('Photon coherent scattering', 'coherent'), + 504: ('Photon incoherent scattering', 'incoherent'), + 515: ('Pair production, electron field', 'pair_production_electron'), + 516: ('Total pair production', 'pair_production_total'), + 517: ('Pair production, nuclear field', 'pair_production_nuclear'), + 522: ('Photoelectric absorption', 'photoelectric'), + 526: ('Electro-atomic scattering', 'electro_atomic_scat'), + 527: ('Electro-atomic bremsstrahlung', 'electro_atomic_brem'), + 528: ('Electro-atomic excitation', 'electro_atomic_excit'), + 534: ('K (1s1/2) subshell photoelectric', 'K'), + 535: ('L1 (2s1/2) subshell photoelectric', 'L1'), + 536: ('L2 (2p1/2) subshell photoelectric', 'L2'), + 537: ('L3 (2p3/2) subshell photoelectric', 'L3'), + 538: ('M1 (3s1/2) subshell photoelectric', 'M1'), + 539: ('M2 (3p1/2) subshell photoelectric', 'M2'), + 540: ('M3 (3p3/2) subshell photoelectric', 'M3'), + 541: ('M4 (3d3/2) subshell photoelectric', 'M4'), + 542: ('M5 (3d5/2) subshell photoelectric', 'M5'), + 543: ('N1 (4s1/2) subshell photoelectric', 'N1'), + 544: ('N2 (4p1/2) subshell photoelectric', 'N2'), + 545: ('N3 (4p3/2) subshell photoelectric', 'N3'), + 546: ('N4 (4d3/2) subshell photoelectric', 'N4'), + 547: ('N5 (4d5/2) subshell photoelectric', 'N5'), + 548: ('N6 (4f5/2) subshell photoelectric', 'N6'), + 549: ('N7 (4f7/2) subshell photoelectric', 'N7'), + 550: ('O1 (5s1/2) subshell photoelectric', 'O1'), + 551: ('O2 (5p1/2) subshell photoelectric', 'O2'), + 552: ('O3 (5p3/2) subshell photoelectric', 'O3'), + 553: ('O4 (5d3/2) subshell photoelectric', 'O4'), + 554: ('O5 (5d5/2) subshell photoelectric', 'O5'), + 555: ('O6 (5f5/2) subshell photoelectric', 'O6'), + 556: ('O7 (5f7/2) subshell photoelectric', 'O7'), + 557: ('O8 (5g7/2) subshell photoelectric', 'O8'), + 558: ('O9 (5g9/2) subshell photoelectric', 'O9'), + 559: ('P1 (6s1/2) subshell photoelectric', 'P1'), + 560: ('P2 (6p1/2) subshell photoelectric', 'P2'), + 561: ('P3 (6p3/2) subshell photoelectric', 'P3'), + 562: ('P4 (6d3/2) subshell photoelectric', 'P4'), + 563: ('P5 (6d5/2) subshell photoelectric', 'P5'), + 564: ('P6 (6f5/2) subshell photoelectric', 'P6'), + 565: ('P7 (6f7/2) subshell photoelectric', 'P7'), + 566: ('P8 (6g7/2) subshell photoelectric', 'P8'), + 567: ('P9 (6g9/2) subshell photoelectric', 'P9'), + 568: ('P10 (6h9/2) subshell photoelectric', 'P10'), + 569: ('P11 (6h11/2) subshell photoelectric', 'P11'), + 570: ('Q1 (7s1/2) subshell photoelectric', 'Q1'), + 571: ('Q2 (7p1/2) subshell photoelectric', 'Q2'), + 572: ('Q3 (7p3/2) subshell photoelectric', 'Q3') } # Compton profiles are read from a pre-generated HDF5 file when they are first @@ -323,8 +322,72 @@ class AtomicRelaxation(EqualityMixin): # Return instance of class return cls(binding_energy, num_electrons, transitions) - def to_hdf5(self, group): - raise NotImplementedError + @classmethod + def from_hdf5(cls, group): + """Generate atomic relaxation data from an HDF5 group + + Parameters + ---------- + group : h5py.Group + HDF5 group to read from + + Returns + ------- + openmc.data.AtomicRelaxation + Atomic relaxation data + + """ + # Create data dictionaries + binding_energy = {} + num_electrons = {} + transitions = {} + + designators = [s.decode() for s in group.attrs['designators']] + shell_values = [None] + _SUBSHELLS + columns = ['secondary', 'tertiary', 'energy (eV)', 'probability'] + for shell in designators: + # Shell group + sub_group = group[shell] + + # Read subshell binding energy and number of electrons + if 'binding_energy' in sub_group.attrs: + binding_energy[shell] = sub_group.attrs['binding_energy'] + if 'num_electrons' in sub_group.attrs: + num_electrons[shell] = sub_group.attrs['num_electrons'] + + # Read transition data + if 'transitions' in sub_group: + df = pd.DataFrame(sub_group['transitions'].value, + columns=columns) + # Replace float indexes back to subshell strings + df[columns[:2]] = df[columns[:2]].replace( + np.arange(float(len(shell_values))), shell_values) + transitions[shell] = df + + return cls(binding_energy, num_electrons, transitions) + + def to_hdf5(self, group, shell): + """Write atomic relaxation data to an HDF5 group + + Parameters + ---------- + group : h5py.Group + HDF5 group to write to + shell : str + The subshell to write data for + + """ + + # Write subshell binding energy and number of electrons + group.attrs['binding_energy'] = self.binding_energy[shell] + group.attrs['num_electrons'] = self.num_electrons[shell] + + # Write transition data with replacements + if shell in self.transitions: + shell_values = [None] + _SUBSHELLS + df = self.transitions[shell].replace( + shell_values, range(len(shell_values))) + group.create_dataset('transitions', data=df.values.astype(float)) class IncidentPhoton(EqualityMixin): @@ -580,6 +643,89 @@ class IncidentPhoton(EqualityMixin): return data + @classmethod + def from_hdf5(cls, group_or_filename): + """Generate photon reaction from an HDF5 group + + Parameters + ---------- + group_or_filename : h5py.Group or str + HDF5 group containing interaction data. If given as a string, it is + assumed to be the filename for the HDF5 file, and the first group is + used to read from. + + Returns + ------- + openmc.data.IncidentPhoton + Photon interaction data + + """ + if isinstance(group_or_filename, h5py.Group): + group = group_or_filename + else: + h5file = h5py.File(str(group_or_filename), 'r') + + # Make sure version matches + if 'version' in h5file.attrs: + major, minor = h5file.attrs['version'] + # For now all versions of HDF5 data can be read + else: + raise IOError( + 'HDF5 data does not indicate a version. Your installation ' + 'of the OpenMC Python API expects version {}.x data.' + .format(HDF5_VERSION_MAJOR)) + + group = list(h5file.values())[0] + + Z = group.attrs['Z'] + data = cls(Z) + + # Read energy grid + energy= group['energy'].value + + # Read cross section data + for mt, (name, key) in _REACTION_NAME.items(): + if key in group: + rgroup = group[key] + elif key in group['subshells']: + rgroup = group['subshells'][key] + else: + continue + + data.reactions[mt] = PhotonReaction.from_hdf5(rgroup, mt, energy) + + # Check for necessary reactions + for mt in [502, 504, 522]: + assert mt in data, "Reaction {} not found".format(mt) + + # Read atomic relaxation + data.atomic_relaxation = AtomicRelaxation.from_hdf5(group['subshells']) + + # Read Compton profiles + if 'compton_profiles' in group: + rgroup = group['compton_profiles'] + profile = data.compton_profiles + profile['num_electrons'] = rgroup['num_electrons'].value + profile['binding_energy'] = rgroup['binding_energy'].value + + # Get electron momentum values + pz = rgroup['pz'].value + J = rgroup['J'].value + if pz.size != J.shape[1]: + raise ValueError("'J' array shape is not consistent with the " + "'pz' array shape") + profile['J'] = [Tabulated1D(pz, Jk) for Jk in J] + + # Read bremsstrahlung + if 'bremsstrahlung' in group: + rgroup = group['bremsstrahlung'] + data.bremsstrahlung['I'] = rgroup.attrs['I'] + for key in ('dcs', 'electron_energy', 'ionization_energy', + 'num_electrons', 'photon_energy'): + data.bremsstrahlung[key] = rgroup[key].value + + return data + def export_to_hdf5(self, path, mode='a', libver='earliest'): """Export incident photon data to an HDF5 file. @@ -590,6 +736,9 @@ class IncidentPhoton(EqualityMixin): mode : {'r', r+', 'w', 'x', 'a'} Mode that is used to open the HDF5 file. This is the second argument to the :class:`h5py.File` constructor. + libver : {'earliest', 'latest'} + Compatibility mode for the HDF5 file. 'latest' will produce files + that are less backwards compatible but have performance benefits. """ # Open file and write version @@ -607,77 +756,25 @@ class IncidentPhoton(EqualityMixin): union_grid = np.union1d(union_grid, rx.xs.x) group.create_dataset('energy', data=union_grid) - # Write coherent scattering cross section - rx = self.reactions[502] - coh_group = group.create_group('coherent') - coh_group.create_dataset('xs', data=rx.xs(union_grid)) - if rx.scattering_factor is not None: - # Create integrated form factor - ff = deepcopy(rx.scattering_factor) - ff.x *= ff.x - ff.y *= ff.y/Z**2 - int_ff = Tabulated1D(ff.x, ff.integral()) - int_ff.to_hdf5(coh_group, 'integrated_scattering_factor') - if rx.anomalous_real is not None: - rx.anomalous_real.to_hdf5(coh_group, 'anomalous_real') - if rx.anomalous_imag is not None: - rx.anomalous_imag.to_hdf5(coh_group, 'anomalous_imag') - - # Write incoherent scattering cross section - rx = self[504] - incoh_group = group.create_group('incoherent') - incoh_group.create_dataset('xs', data=rx.xs(union_grid)) - if rx.scattering_factor is not None: - rx.scattering_factor.to_hdf5(incoh_group, 'scattering_factor') - - # Write electron-field pair production cross section - if 515 in self: - pair_group = group.create_group('pair_production_electron') - pair_group.create_dataset('xs', data=self[515].xs(union_grid)) - - # Write nuclear-field pair production cross section - if 517 in self: - pair_group = group.create_group('pair_production_nuclear') - pair_group.create_dataset('xs', data=self[517].xs(union_grid)) - - # Write photoelectric cross section - photoelec_group = group.create_group('photoelectric') - photoelec_group.create_dataset('xs', data=self[522].xs(union_grid)) - - # Write photoionization cross sections + # Write cross sections shell_group = group.create_group('subshells') designators = [] for mt, rx in self.reactions.items(): - if mt >= 534 and mt <= 572: - # Get name of subshell - shell = _SUBSHELLS[mt - 534] - designators.append(shell) - sub_group = shell_group.create_group(shell) + name, key = _REACTION_NAME[mt] + if mt in [502, 504, 515, 517, 522]: + sub_group = group.create_group(key) + elif mt >= 534 and mt <= 572: + # Subshell + designators.append(key) + sub_group = shell_group.create_group(key) - if self.atomic_relaxation is not None: - relax = self.atomic_relaxation - # Write subshell binding energy and number of electrons - sub_group.attrs['binding_energy'] = relax.binding_energy[shell] - sub_group.attrs['num_electrons'] = relax.num_electrons[shell] + # Write atomic relaxation + if key in self.atomic_relaxation.subshells: + self.atomic_relaxation.to_hdf5(sub_group, key) + else: + continue - # Write transition data with replacements - if shell in relax.transitions: - shell_values = _SUBSHELLS.copy() - shell_values.insert(0, None) - df = relax.transitions[shell].replace( - shell_values, range(len(shell_values))) - sub_group.create_dataset( - 'transitions', data=df.values.astype(float)) - - # Determine threshold - threshold = rx.xs.x[0] - idx = np.searchsorted(union_grid, threshold, side='right') - 1 - - # Interpolate cross section onto union grid and write - photoionization = rx.xs(union_grid[idx:]) - sub_group.create_dataset('xs', data=photoionization) - assert len(union_grid) == len(photoionization) + idx - sub_group['xs'].attrs['threshold_idx'] = idx + rx.to_hdf5(sub_group, union_grid, Z) shell_group.attrs['designators'] = np.array(designators, dtype='S') @@ -707,6 +804,7 @@ class IncidentPhoton(EqualityMixin): else: brem_group.create_dataset(key, data=value) + def _add_bremsstrahlung(self): """Add the data used in the thick-target bremsstrahlung approximation @@ -805,7 +903,7 @@ class PhotonReaction(EqualityMixin): def __repr__(self): if self.mt in _REACTION_NAME: return "".format( - self.mt, _REACTION_NAME[self.mt]) + self.mt, _REACTION_NAME[self.mt][0]) else: return "".format(self.mt) @@ -982,3 +1080,93 @@ class PhotonReaction(EqualityMixin): params, rx.anomalous_imag = get_tab1_record(file_obj) return rx + + @classmethod + def from_hdf5(cls, group, mt, energy): + """Generate photon reaction from an HDF5 group + + Parameters + ---------- + group : h5py.Group + HDF5 group to read from + mt : int + The MT value of the reaction to get data for + energy : Iterable of float + arrays of energies at which cross sections are tabulated at + + Returns + ------- + openmc.data.PhotonReaction + Photon reaction data + + """ + # Create instance + rx = cls(mt) + + # Cross sections + xs = group['xs'].value + # Replace zero elements to small non-zero to enable log-log + xs[xs == 0.0] = np.exp(-500.0) + + # Threshold + threshold_idx = 0 + if 'threshold_idx' in group['xs'].attrs: + threshold_idx = group['xs'].attrs['threshold_idx'] + + # Store + rx.xs = Tabulated1D(energy[threshold_idx:], xs, [len(xs)], [5]) + + # Check for anomalous scattering factor + if 'anomalous_real' in group: + rx.anomalous_real = Tabulated1D.from_hdf5(group['anomalous_real']) + if 'anomalous_imag' in group: + rx.anomalous_imag = Tabulated1D.from_hdf5(group['anomalous_imag']) + + # Check for factors / scattering functions + if 'scattering_factor' in group: + rx.scattering_factor = Tabulated1D.from_hdf5(group['scattering_factor']) + + return rx + + def to_hdf5(self, group, energy, Z): + """Write photon reaction to an HDF5 group + + Parameters + ---------- + group : h5py.Group + HDF5 group to write to + energy : Iterable of float + arrays of energies at which cross sections are tabulated at + Z : int + atomic number + + """ + + # Write cross sections + if self.mt >= 534 and self.mt <= 572: + # Determine threshold + threshold = self.xs.x[0] + idx = np.searchsorted(energy, threshold, side='right') - 1 + + # Interpolate cross section onto union grid and write + photoionization = self.xs(energy[idx:]) + group.create_dataset('xs', data=photoionization) + assert len(energy) == len(photoionization) + idx + group['xs'].attrs['threshold_idx'] = idx + else: + group.create_dataset('xs', data=self.xs(energy)) + + # Write scattering factor + if self.scattering_factor is not None: + if self.mt == 502: + # Create integrated form factor + ff = deepcopy(self.scattering_factor) + ff.x *= ff.x + ff.y *= ff.y/Z**2 + int_ff = Tabulated1D(ff.x, ff.integral()) + int_ff.to_hdf5(group, 'integrated_scattering_factor') + self.scattering_factor.to_hdf5(group, 'scattering_factor') + if self.anomalous_real is not None: + self.anomalous_real.to_hdf5(group, 'anomalous_real') + if self.anomalous_imag is not None: + self.anomalous_imag.to_hdf5(group, 'anomalous_imag') From fc8b2a5001e4c8a830e14d5be9654509179e0ccc Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 26 Mar 2019 07:57:55 -0500 Subject: [PATCH 121/165] Add two papers to publication list --- docs/source/publications.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/source/publications.rst b/docs/source/publications.rst index 762f9329e..e1c0f6de0 100644 --- a/docs/source/publications.rst +++ b/docs/source/publications.rst @@ -59,7 +59,7 @@ Coupling and Multi-physics - Ze-Long Zhao, Yongwei Yang, and Shuang Hong, "`Application of FLUKA and OpenMC in coupled physics calculation of target and subcritical reactor for ADS - `_," *Nucl. Sci. Tech.*, **30** + `_," *Nucl. Sci. Tech.*, **30**: 10 (2019). - April Novak, Paul Romano, Brycen Wendt, Ron Rahaman, Elia Merzari, Leslie @@ -134,6 +134,11 @@ Geometry and Visualization Miscellaneous ------------- +- Faisal Qayyum, Muhammad R. Ali, Awais Zahur, and R. Khan, "`Improvements in + methodology to determine feedback reactivity coefficients + `_," *Nucl. Sci. Tech.*, **30**: 63 + (2019). + - Amanda L. Lund and Paul K. Romano, "`Implementation and Validation of Photon Transport in OpenMC `_", Argonne National Laboratory, Technical Report ANL/MCS-TM-381 (2018). @@ -464,6 +469,11 @@ Parallelism Depletion --------- +- Zhao-Qing Liu, Ze-Long Zhao, Yong-Wei Yang, Yu-Cui Gao, Hai-Yan Meng, and + Qing-Yu Gao, "`Development and validation of depletion code system IMPC-Burnup + for ADS `_," *Nucl. Sci. Tech.*, + **30**: 44 (2019). + - Colin Josey, Benoit Forget, and Kord Smith, "`High order methods for the integration of the Bateman equations and other problems of the form of y' = F(y,t)y `_," *J. Comput. Phys.*, From db66dfbd174e9dfb3174a91ece2eb8dc72943a27 Mon Sep 17 00:00:00 2001 From: liangjg Date: Tue, 26 Mar 2019 14:03:10 -0400 Subject: [PATCH 122/165] add tests for IncidentPhoton.from_hdf5 --- tests/unit_tests/test_data_photon.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unit_tests/test_data_photon.py b/tests/unit_tests/test_data_photon.py index e2e737286..f0a107a05 100644 --- a/tests/unit_tests/test_data_photon.py +++ b/tests/unit_tests/test_data_photon.py @@ -129,3 +129,6 @@ def test_export_to_hdf5(tmpdir, element): filename = str(tmpdir.join('tmp.h5')) element.export_to_hdf5(filename) assert os.path.exists(filename) + # Read in data from hdf5 and export again + element2 = openmc.data.IncidentPhoton.from_hdf5(filename) + element2.export_to_hdf5(filename, 'w') From 1d5242ede19f379e99a43ad2c6f5c07497b54281 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 15 Mar 2019 15:36:45 -0500 Subject: [PATCH 123/165] Fix a whole bunch of -Wall warnings --- include/openmc/error.h | 4 ++-- include/openmc/plot.h | 5 ++++- src/bremsstrahlung.cpp | 2 +- src/cross_sections.cpp | 1 - src/dagmc.cpp | 6 +++--- src/distribution_energy.cpp | 3 +++ src/endf.cpp | 3 +-- src/geometry.cpp | 3 +-- src/hdf5_interface.cpp | 5 +++++ src/initialize.cpp | 1 - src/lattice.cpp | 1 - src/material.cpp | 3 +-- src/mgxs.cpp | 2 -- src/nuclide.cpp | 2 +- src/output.cpp | 9 ++++----- src/particle_restart.cpp | 4 ++++ src/photon.cpp | 5 ----- src/physics.cpp | 21 +++++++-------------- src/plot.cpp | 7 ++++--- src/secondary_kalbach.cpp | 2 +- src/secondary_nbody.cpp | 2 ++ src/tallies/tally.cpp | 1 - src/tallies/trigger.cpp | 2 +- 23 files changed, 45 insertions(+), 49 deletions(-) diff --git a/include/openmc/error.h b/include/openmc/error.h index 206c9b5b2..062368f17 100644 --- a/include/openmc/error.h +++ b/include/openmc/error.h @@ -29,13 +29,13 @@ set_errmsg(const std::stringstream& message) [[noreturn]] void fatal_error(const std::string& message, int err=-1); -inline +[[noreturn]] inline void fatal_error(const std::stringstream& message) { fatal_error(message.str()); } -inline +[[noreturn]] inline void fatal_error(const char* message) { fatal_error({message, std::strlen(message)}); diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 2752add9c..8e5aa02a6 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -138,6 +138,10 @@ T PlotBase::get_map() const { in_i = 1; out_i = 2; break; +#ifdef __GNUC__ + default: + __builtin_unreachable(); +#endif } // set initial position @@ -168,7 +172,6 @@ T PlotBase::get_map() const { if (level >=0) {j = level + 1;} if (found_cell) { data.set_value(y, x, p, j); - Cell* c = model::cells[p.coord_[j].cell].get(); } } // inner for } // outer for diff --git a/src/bremsstrahlung.cpp b/src/bremsstrahlung.cpp index 3b9d8b591..e6b76d19d 100644 --- a/src/bremsstrahlung.cpp +++ b/src/bremsstrahlung.cpp @@ -45,7 +45,7 @@ void thick_target_bremsstrahlung(Particle& p, double* E_lost) auto n_e = data::ttb_e_grid.size(); // Find the lower bounding index of the incident electron energy - int j = lower_bound_index(data::ttb_e_grid.cbegin(), + size_t j = lower_bound_index(data::ttb_e_grid.cbegin(), data::ttb_e_grid.cend(), e); if (j == n_e - 1) --j; diff --git a/src/cross_sections.cpp b/src/cross_sections.cpp index e91cfc875..2216b37da 100644 --- a/src/cross_sections.cpp +++ b/src/cross_sections.cpp @@ -247,7 +247,6 @@ read_ce_cross_sections(const std::vector>& nuc_temps, LibraryKey key {Library::Type::photon, element}; int idx = data::library_map[key]; std::string& filename = data::libraries[idx].path_; - int i_element = data::element_map[element]; write_message("Reading " + element + " from " + filename, 6); // Open file and make sure version is sufficient diff --git a/src/dagmc.cpp b/src/dagmc.cpp index b50d65d88..8add1f4f3 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -142,7 +142,7 @@ void load_dagmc_geometry() model::DAG = new moab::DagMC(); } - /// Materials \\\ + // --- Materials --- // create uwuw instance UWUW uwuw(DAGMC_FILENAME.c_str()); @@ -176,7 +176,7 @@ void load_dagmc_geometry() rval = model::DAG->parse_properties(keywords, dum, delimiters.c_str()); MB_CHK_ERR_CONT(rval); - /// Cells (Volumes) \\\ + // --- Cells (Volumes) --- // initialize cell objects int n_cells = model::DAG->num_entities(3); @@ -298,7 +298,7 @@ void load_dagmc_geometry() "This may result in lost particles and rapid simulation failure."); } - /// Surfaces \\\ + // --- Surfaces --- // initialize surface objects int n_surfaces = model::DAG->num_entities(2); diff --git a/src/distribution_energy.cpp b/src/distribution_energy.cpp index e311e322d..1b9be7346 100644 --- a/src/distribution_energy.cpp +++ b/src/distribution_energy.cpp @@ -245,6 +245,9 @@ double ContinuousTabular::sample(double E) const E_out = E_l_k + (std::sqrt(std::max(0.0, p_l_k*p_l_k + 2.0*frac*(r1 - c_k))) - p_l_k)/frac; } + } else { + throw std::runtime_error{"Unexpected interpolation for continuous energy " + "distribution."}; } // Now interpolate between incident energy bins i and i + 1 diff --git a/src/endf.cpp b/src/endf.cpp index 86f08b8a8..464bc974c 100644 --- a/src/endf.cpp +++ b/src/endf.cpp @@ -164,9 +164,8 @@ double Tabulated1D::operator()(double x) const Interpolation interp; if (n_regions_ == 0) { interp = Interpolation::lin_lin; - } else if (n_regions_ == 1) { + } else { interp = int_[0]; - } else if (n_regions_ > 1) { for (int j = 0; j < n_regions_; ++j) { if (i < nbt_[j]) { interp = int_[j]; diff --git a/src/geometry.cpp b/src/geometry.cpp index 6eaa61fe2..8791dd957 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -39,7 +39,6 @@ bool check_cell_overlap(Particle* p) // Loop through each coordinate level for (int j = 0; j < n_coord; j++) { Universe& univ = *model::universes[p->coord_[j].universe]; - int n = univ.cells_.size(); // Loop through each cell on this level for (auto index_cell : univ.cells_) { @@ -351,7 +350,7 @@ BoundaryInfo distance_to_boundary(Particle* p) double d_lat = INFINITY; double d_surf = INFINITY; int32_t level_surf_cross; - std::array level_lat_trans; + std::array level_lat_trans {}; // Loop over each coordinate level. for (int i = 0; i < p->n_coord_; i++) { diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index d85a4cc9e..1fb10b706 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "xtensor/xtensor.hpp" @@ -47,6 +48,8 @@ get_shape(hid_t obj_id, hsize_t* dims) dspace = H5Dget_space(obj_id); } else if (type == H5I_ATTR) { dspace = H5Aget_space(obj_id); + } else { + throw std::runtime_error{"Expected dataset or attribute in call to get_shape."}; } H5Sget_simple_extent_dims(dspace, dims, nullptr); H5Sclose(dspace); @@ -70,6 +73,8 @@ std::vector object_shape(hid_t obj_id) dspace = H5Dget_space(obj_id); } else if (type == H5I_ATTR) { dspace = H5Aget_space(obj_id); + } else { + throw std::runtime_error{"Expected dataset or attribute in call to object_shape."}; } int n = H5Sget_simple_extent_ndims(dspace); diff --git a/src/initialize.cpp b/src/initialize.cpp index 61390651f..f8a4f4a39 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -121,7 +121,6 @@ void initialize_mpi(MPI_Comm intracomm) int parse_command_line(int argc, char* argv[]) { - char buffer[256]; // buffer for reading attribute int last_flag = 0; for (int i=1; i < argc; ++i) { std::string arg {argv[i]}; diff --git a/src/lattice.cpp b/src/lattice.cpp index 6e0f2331f..eb6282bac 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -800,7 +800,6 @@ HexLattice::is_valid_index(int indx) const { int nx {2*n_rings_ - 1}; int ny {2*n_rings_ - 1}; - int nz {n_axial_}; int iz = indx / (nx * ny); int iy = (indx - nx*ny*iz) / nx; int ix = indx - nx*ny*iz - nx*iy; diff --git a/src/material.cpp b/src/material.cpp index 94a621483..de0d7e5de 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -1283,12 +1283,11 @@ openmc_material_set_densities(int32_t index, int n, const char** name, const dou } // Set total density to the sum of the vector - int err = mat->set_density(sum_density, "atom/b-cm"); // Assign S(a,b) tables mat->init_thermal(); - return 0; + return err; } else { set_errmsg("Index in materials array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; diff --git a/src/mgxs.cpp b/src/mgxs.cpp index d345cdb22..efe562fa2 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -329,8 +329,6 @@ Mgxs::Mgxs(const std::string& in_name, const std::vector& mat_kTs, // Force all of the following data to be the same; these will be verified // to be true later int in_scatter_format = micros[0]->scatter_format; - int in_num_groups = micros[0]->num_groups; - int in_num_delayed_groups = micros[0]->num_delayed_groups; bool in_is_isotropic = micros[0]->is_isotropic; std::vector in_polar = micros[0]->polar; std::vector in_azimuthal = micros[0]->azimuthal; diff --git a/src/nuclide.cpp b/src/nuclide.cpp index 8a6f1aa57..7f034fd41 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -97,7 +97,7 @@ Nuclide::Nuclide(hid_t group, const std::vector& temperature, int i_nucl // Determine closest temperature double min_delta_T = INFTY; - double T_actual; + double T_actual = 0.0; for (auto T : temps_available) { double delta_T = std::abs(T - T_desired); if (delta_T < min_delta_T) { diff --git a/src/output.cpp b/src/output.cpp index df0976d94..ee74a27e1 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -283,9 +283,9 @@ print_overlap_check() { #ifdef OPENMC_MPI std::vector temp(model::overlap_check_count); - int err = MPI_Reduce(temp.data(), model::overlap_check_count.data(), - model::overlap_check_count.size(), MPI_INT64_T, - MPI_SUM, 0, mpi::intracomm); + MPI_Reduce(temp.data(), model::overlap_check_count.data(), + model::overlap_check_count.size(), MPI_INT64_T, + MPI_SUM, 0, mpi::intracomm); #endif if (mpi::master) { @@ -482,7 +482,7 @@ void print_runtime() // Calculate particle rate in active/inactive batches int n_active = simulation::current_batch - settings::n_inactive; - double speed_inactive; + double speed_inactive = 0.0; double speed_active; if (settings::restart_run) { if (simulation::restart_batch < settings::n_inactive) { @@ -492,7 +492,6 @@ void print_runtime() speed_active = (settings::n_particles * n_active * settings::gen_per_batch) / time_active.elapsed(); } else { - speed_inactive = 0.0; speed_active = (settings::n_particles * (settings::n_batches - simulation::restart_batch) * settings::gen_per_batch) / time_active.elapsed(); diff --git a/src/particle_restart.cpp b/src/particle_restart.cpp index 0bc677cfd..b2017bbeb 100644 --- a/src/particle_restart.cpp +++ b/src/particle_restart.cpp @@ -14,6 +14,7 @@ #include // for copy #include +#include #include namespace openmc { @@ -90,6 +91,9 @@ void run_particle_restart() case RUN_MODE_FIXEDSOURCE: particle_seed = p.id_; break; + default: + throw std::runtime_error{"Unexpected run mode: " + + std::to_string(previous_run_mode)}; } set_particle_seed(particle_seed); diff --git a/src/photon.cpp b/src/photon.cpp index 79345b90e..8a0ddf9aa 100644 --- a/src/photon.cpp +++ b/src/photon.cpp @@ -550,11 +550,6 @@ void PhotonInteraction::pair_production(double alpha, double* E_electron, // "PENELOPE-2011: A Code System for Monte Carlo Simulation of Electron and // Photon Transport," OECD-NEA, Issy-les-Moulineaux, France (2011). - // Compute the minimum and maximum values of the electron reduced energy, - // i.e. the fraction of the photon energy that is given to the electron - double e_min = 1.0/alpha; - double e_max = 1.0 - 1.0/alpha; - // Compute the high-energy Coulomb correction double a = Z_ / FINE_STRUCTURE; double c = a*a*(1.0/(1.0 + a*a) + 0.202059 + a*a*(-0.03693 + a*a*(0.00835 + diff --git a/src/physics.cpp b/src/physics.cpp index 1cfd31658..e28c5a00e 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -421,20 +421,11 @@ int sample_element(Particle* p) // Get pointers to elements, densities const auto& mat {model::materials[p->material_]}; - int n = mat->nuclide_.size(); - int i = 0; double prob = 0.0; - int i_element; - while (prob < cutoff) { - // Check to make sure that a nuclide was sampled - if (i >= n) { - p->write_restart(); - fatal_error("Did not sample any element during collision."); - } - + for (int i = 0; i < mat->element_.size(); ++i) { // Find atom density - i_element = mat->element_[i]; + int i_element = mat->element_[i]; double atom_density = mat->atom_density_[i]; // Determine microscopic cross section @@ -442,10 +433,12 @@ int sample_element(Particle* p) // Increment probability to compare to cutoff prob += sigma; - ++i; + if (prob > cutoff) return i_element; } - return i_element; + // If we made it here, no element was sampled + p->write_restart(); + fatal_error("Did not sample any element during collision."); } Reaction* sample_fission(int i_nuclide, const Particle* p) @@ -614,7 +607,7 @@ void scatter(Particle* p, int i_nuclide) // INELASTIC SCATTERING int j = 0; - int i; + int i = 0; while (prob < cutoff) { i = nuc->index_inelastic_scatter_[j]; ++j; diff --git a/src/plot.cpp b/src/plot.cpp index 02fb42d76..74279cad5 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -80,8 +80,6 @@ std::unordered_map plot_map; extern "C" int openmc_plot_geometry() { - int err; - for (auto pl : model::plots) { std::stringstream ss; ss << "Processing plot " << pl.id_ << ": " @@ -695,6 +693,10 @@ void draw_mesh_lines(Plot pl, ImageData& data) outer = 1; inner = 2; break; +#ifdef __GNUC__ + default: + __builtin_unreachable(); +#endif } Position ll_plot {pl.origin_}; @@ -806,7 +808,6 @@ void create_voxel(Plot pl) // Write current date and time write_attribute(file_id, "date_and_time", time_stamp().c_str()); - hsize_t three = 3; std::array pixels; std::copy(pl.pixels_.begin(), pl.pixels_.end(), pixels.begin()); write_attribute(file_id, "num_voxels", pixels); diff --git a/src/secondary_kalbach.cpp b/src/secondary_kalbach.cpp index cec5344de..e3974f357 100644 --- a/src/secondary_kalbach.cpp +++ b/src/secondary_kalbach.cpp @@ -199,7 +199,7 @@ void KalbachMann::sample(double E_in, double& E_out, double& mu) const km_r = distribution_[l].r[k]; km_a = distribution_[l].a[k]; - } else if (distribution_[l].interpolation == Interpolation::lin_lin) { + } else { // Linear-linear interpolation double E_l_k1 = distribution_[l].e_out[k+1]; double p_l_k1 = distribution_[l].p[k+1]; diff --git a/src/secondary_nbody.cpp b/src/secondary_nbody.cpp index dabd9de3a..564fca73d 100644 --- a/src/secondary_nbody.cpp +++ b/src/secondary_nbody.cpp @@ -55,6 +55,8 @@ void NBodyPhaseSpace::sample(double E_in, double& E_out, double& mu) const r6 = prn(); y = -std::log(r1*r2*r3*r4) - std::log(r5) * std::pow(std::cos(PI/2.0*r6), 2); break; + default: + throw std::runtime_error{"N-body phase space with >5 bodies."}; } // Now determine v and E_out diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 682db3540..fe1953b26 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -328,7 +328,6 @@ Tally::set_scores(std::vector scores) // Iterate over the given scores. for (auto score_str : scores) { // Make sure a delayed group filter wasn't used with an incompatible score. - bool has_delayedgroup = delayedgroup_filter_ != C_NONE; if (delayedgroup_filter_ != C_NONE) { if (score_str != "delayed-nu-fission" && score_str != "decay-rate") fatal_error("Cannot tally " + score_str + "with a delayedgroup filter"); diff --git a/src/tallies/trigger.cpp b/src/tallies/trigger.cpp index c1b0a9364..d43be8b9c 100644 --- a/src/tallies/trigger.cpp +++ b/src/tallies/trigger.cpp @@ -114,7 +114,7 @@ check_keff_trigger() if (settings::run_mode != RUN_MODE_EIGENVALUE) return 0.; double k_combined[2]; - int err = openmc_get_keff(k_combined); + openmc_get_keff(k_combined); double uncertainty = 0.; switch (settings::keff_trigger.metric) { From cca544292a99265ed5a9937e88f78114e47465e3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 26 Mar 2019 16:16:06 -0500 Subject: [PATCH 124/165] Isolate __builtin_unreachable to macro --- include/openmc/error.h | 6 ++++++ src/nuclide.cpp | 4 +--- src/physics.cpp | 4 +--- src/plot.cpp | 4 +--- src/tallies/filter_particle.cpp | 4 +--- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/include/openmc/error.h b/include/openmc/error.h index 062368f17..5f30f0252 100644 --- a/include/openmc/error.h +++ b/include/openmc/error.h @@ -7,6 +7,12 @@ #include "openmc/capi.h" +#ifdef __GNUC__ +#define UNREACHABLE() __builtin_unreachable() +#else +#define UNREACHABLE() (void)0 +#endif + namespace openmc { inline void diff --git a/src/nuclide.cpp b/src/nuclide.cpp index 7f034fd41..6094b7983 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -454,9 +454,7 @@ double Nuclide::nu(double E, EmissionMode mode, int group) const return (*fission_rx_[0]->products_[0].yield_)(E); } } -#ifdef __GNUC__ - __builtin_unreachable(); -#endif + UNREACHABLE(); } void Nuclide::calculate_elastic_xs(Particle& p) const diff --git a/src/physics.cpp b/src/physics.cpp index e28c5a00e..0d0c60343 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -883,9 +883,7 @@ Direction sample_target_velocity(const Nuclide* nuc, double E, Direction u, } // case RVS, DBRC } // switch (sampling_method) -#ifdef __GNUC__ - __builtin_unreachable(); -#endif + UNREACHABLE(); } Direction diff --git a/src/plot.cpp b/src/plot.cpp index 74279cad5..57466eca1 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -693,10 +693,8 @@ void draw_mesh_lines(Plot pl, ImageData& data) outer = 1; inner = 2; break; -#ifdef __GNUC__ default: - __builtin_unreachable(); -#endif + UNREACHABLE(); } Position ll_plot {pl.origin_}; diff --git a/src/tallies/filter_particle.cpp b/src/tallies/filter_particle.cpp index 1d4b84937..23a305b8d 100644 --- a/src/tallies/filter_particle.cpp +++ b/src/tallies/filter_particle.cpp @@ -50,9 +50,7 @@ ParticleFilter::text_label(int bin) const case Particle::Type::positron: return "Particle: positron"; } -#ifdef __GNUC__ - __builtin_unreachable(); -#endif + UNREACHABLE(); } } // namespace openmc From 2efd58a694c802d4c814becc42a9ab13a3b76325 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 26 Mar 2019 22:43:33 -0500 Subject: [PATCH 125/165] Use dataset[()] instead of deprecated dataset.value --- openmc/data/angle_distribution.py | 2 +- openmc/data/correlated.py | 6 +-- openmc/data/energy_distribution.py | 2 +- openmc/data/function.py | 6 +-- openmc/data/kalbach_mann.py | 2 +- openmc/data/multipole.py | 16 +++---- openmc/data/neutron.py | 4 +- openmc/data/photon.py | 12 ++--- openmc/data/reaction.py | 2 +- openmc/data/thermal.py | 12 ++--- openmc/data/urr.py | 4 +- openmc/filter.py | 32 ++++++------- openmc/filter_expansion.py | 32 ++++++------- openmc/lattice.py | 26 +++++----- openmc/material.py | 12 ++--- openmc/mesh.py | 10 ++-- openmc/mgxs_library.py | 6 +-- openmc/particle_restart.py | 22 ++++----- openmc/statepoint.py | 76 +++++++++++++++--------------- openmc/summary.py | 24 +++++----- openmc/surface.py | 8 ++-- openmc/tallies.py | 2 +- openmc/universe.py | 2 +- openmc/volume.py | 6 +-- 24 files changed, 163 insertions(+), 163 deletions(-) diff --git a/openmc/data/angle_distribution.py b/openmc/data/angle_distribution.py index a1f498ba6..638590cff 100644 --- a/openmc/data/angle_distribution.py +++ b/openmc/data/angle_distribution.py @@ -115,7 +115,7 @@ class AngleDistribution(EqualityMixin): Angular distribution """ - energy = group['energy'].value + energy = group['energy'][()] data = group['mu'] offsets = data.attrs['offsets'] interpolation = data.attrs['interpolation'] diff --git a/openmc/data/correlated.py b/openmc/data/correlated.py index 8cc4509ce..b760f2e2f 100644 --- a/openmc/data/correlated.py +++ b/openmc/data/correlated.py @@ -210,15 +210,15 @@ class CorrelatedAngleEnergy(AngleEnergy): interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] - energy = group['energy'].value + energy = group['energy'][()] offsets = group['energy_out'].attrs['offsets'] interpolation = group['energy_out'].attrs['interpolation'] n_discrete_lines = group['energy_out'].attrs['n_discrete_lines'] - dset_eout = group['energy_out'].value + dset_eout = group['energy_out'][()] energy_out = [] - dset_mu = group['mu'].value + dset_mu = group['mu'][()] mu = [] n_energy = len(energy) diff --git a/openmc/data/energy_distribution.py b/openmc/data/energy_distribution.py index 9e01a4b30..bff97bf81 100644 --- a/openmc/data/energy_distribution.py +++ b/openmc/data/energy_distribution.py @@ -1144,7 +1144,7 @@ class ContinuousTabular(EnergyDistribution): interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] - energy = group['energy'].value + energy = group['energy'][()] data = group['distribution'] offsets = data.attrs['offsets'] diff --git a/openmc/data/function.py b/openmc/data/function.py index 36443e761..f167a3c23 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -349,8 +349,8 @@ class Tabulated1D(Function1D): raise ValueError("Expected an HDF5 attribute 'type' equal to '" + cls.__name__ + "'") - x = dataset.value[0, :] - y = dataset.value[1, :] + x = dataset[0, :] + y = dataset[1, :] breakpoints = dataset.attrs['breakpoints'] interpolation = dataset.attrs['interpolation'] return cls(x, y, breakpoints, interpolation) @@ -434,7 +434,7 @@ class Polynomial(np.polynomial.Polynomial, Function1D): if dataset.attrs['type'].decode() != cls.__name__: raise ValueError("Expected an HDF5 attribute 'type' equal to '" + cls.__name__ + "'") - return cls(dataset.value) + return cls(dataset[()]) class Combination(EqualityMixin): diff --git a/openmc/data/kalbach_mann.py b/openmc/data/kalbach_mann.py index 4be0c15d5..c7df015a7 100644 --- a/openmc/data/kalbach_mann.py +++ b/openmc/data/kalbach_mann.py @@ -202,7 +202,7 @@ class KalbachMann(AngleEnergy): interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] - energy = group['energy'].value + energy = group['energy'][()] data = group['distribution'] offsets = data.attrs['offsets'] diff --git a/openmc/data/multipole.py b/openmc/data/multipole.py index 9022061a0..38c7be123 100644 --- a/openmc/data/multipole.py +++ b/openmc/data/multipole.py @@ -356,24 +356,24 @@ class WindowedMultipole(EqualityMixin): # Read scalars. - out.spacing = group['spacing'].value - out.sqrtAWR = group['sqrtAWR'].value - out.E_min = group['E_min'].value - out.E_max = group['E_max'].value + out.spacing = group['spacing'][()] + out.sqrtAWR = group['sqrtAWR'][()] + out.E_min = group['E_min'][()] + out.E_max = group['E_max'][()] # Read arrays. err = "WMP '{}' array shape is not consistent with the '{}' array shape" - out.data = group['data'].value + out.data = group['data'][()] - out.windows = group['windows'].value + out.windows = group['windows'][()] - out.broaden_poly = group['broaden_poly'].value.astype(np.bool) + out.broaden_poly = group['broaden_poly'][()].astype(np.bool) if out.broaden_poly.shape[0] != out.windows.shape[0]: raise ValueError(err.format('broaden_poly', 'windows')) - out.curvefit = group['curvefit'].value + out.curvefit = group['curvefit'][()] if out.curvefit.shape[0] != out.windows.shape[0]: raise ValueError(err.format('curvefit', 'windows')) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 2ff55700f..cd1e40604 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -521,7 +521,7 @@ class IncidentNeutron(EqualityMixin): kTg = group['kTs'] kTs = [] for temp in kTg: - kTs.append(kTg[temp].value) + kTs.append(kTg[temp][()]) data = cls(name, atomic_number, mass_number, metastable, atomic_weight_ratio, kTs) @@ -529,7 +529,7 @@ class IncidentNeutron(EqualityMixin): # Read energy grid e_group = group['energy'] for temperature, dset in e_group.items(): - data.energy[temperature] = dset.value + data.energy[temperature] = dset[()] # Read reaction data rxs_group = group['reactions'] diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 47bdbf1d9..c21a46e1f 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -558,12 +558,12 @@ class IncidentPhoton(EqualityMixin): if not _COMPTON_PROFILES: filename = os.path.join(os.path.dirname(__file__), 'compton_profiles.h5') with h5py.File(filename, 'r') as f: - _COMPTON_PROFILES['pz'] = f['pz'].value + _COMPTON_PROFILES['pz'] = f['pz'][()] for i in range(1, 101): group = f['{:03}'.format(i)] - num_electrons = group['num_electrons'].value - binding_energy = group['binding_energy'].value*EV_PER_MEV - J = group['J'].value + num_electrons = group['num_electrons'][()] + binding_energy = group['binding_energy'][()]*EV_PER_MEV + J = group['J'][()] _COMPTON_PROFILES[i] = {'num_electrons': num_electrons, 'binding_energy': binding_energy, 'J': J} @@ -720,8 +720,8 @@ class IncidentPhoton(EqualityMixin): group = f['{:03}'.format(i)] _BREMSSTRAHLUNG[i] = { 'I': group.attrs['I'], - 'num_electrons': group['num_electrons'].value, - 'ionization_energy': group['ionization_energy'].value + 'num_electrons': group['num_electrons'][()], + 'ionization_energy': group['ionization_energy'][()] } filename = os.path.join(os.path.dirname(__file__), 'BREMX.DAT') diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index a988f2d6d..c5abc73c3 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -938,7 +938,7 @@ class Reaction(EqualityMixin): 'Could not create reaction cross section for MT={} ' 'at T={} because no corresponding energy grid ' 'exists.'.format(mt, T)) - xs = Tgroup['xs'].value + xs = Tgroup['xs'][()] threshold_idx = Tgroup['xs'].attrs['threshold_idx'] - 1 tabulated_xs = Tabulated1D(energy[T][threshold_idx:], xs) tabulated_xs._threshold_idx = threshold_idx diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index b10cdeba4..27ed7aa29 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -200,8 +200,8 @@ class CoherentElastic(EqualityMixin): Coherent elastic scattering cross section """ - bragg_edges = dataset.value[0, :] - factors = dataset.value[1, :] + bragg_edges = dataset[0, :] + factors = dataset[1, :] return cls(bragg_edges, factors) @@ -414,7 +414,7 @@ class ThermalScattering(EqualityMixin): kTg = group['kTs'] kTs = [] for temp in kTg: - kTs.append(kTg[temp].value) + kTs.append(kTg[temp][()]) temperatures = [str(int(round(kT / K_BOLTZMANN))) + "K" for kT in kTs] table = cls(name, atomic_weight_ratio, kTs) @@ -438,7 +438,7 @@ class ThermalScattering(EqualityMixin): # Angular distribution if 'mu_out' in elastic_group: - table.elastic_mu_out[T] = elastic_group['mu_out'].value + table.elastic_mu_out[T] = elastic_group['mu_out'][()] # Read thermal inelastic scattering if 'inelastic' in Tgroup: @@ -446,8 +446,8 @@ class ThermalScattering(EqualityMixin): table.inelastic_xs[T] = Tabulated1D.from_hdf5( inelastic_group['xs']) if table.secondary_mode in ('equal', 'skewed'): - table.inelastic_e_out[T] = inelastic_group['energy_out'].value - table.inelastic_mu_out[T] = inelastic_group['mu_out'].value + table.inelastic_e_out[T] = inelastic_group['energy_out'][()] + table.inelastic_mu_out[T] = inelastic_group['mu_out'][()] elif table.secondary_mode == 'continuous': table.inelastic_dist[T] = AngleEnergy.from_hdf5( inelastic_group) diff --git a/openmc/data/urr.py b/openmc/data/urr.py index 0edccf6f0..53961a50a 100644 --- a/openmc/data/urr.py +++ b/openmc/data/urr.py @@ -166,8 +166,8 @@ class ProbabilityTables(EqualityMixin): absorption_flag = group.attrs['absorption'] multiply_smooth = bool(group.attrs['multiply_smooth']) - energy = group['energy'].value - table = group['table'].value + energy = group['energy'][()] + table = group['table'][()] return cls(energy, table, interpolation, inelastic_flag, absorption_flag, multiply_smooth) diff --git a/openmc/filter.py b/openmc/filter.py index ef68a4961..49d3ff5de 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -170,19 +170,19 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): # If the HDF5 'type' variable matches this class's short_name, then # there is no overriden from_hdf5 method. Pass the bins to __init__. - if group['type'].value.decode() == cls.short_name.lower(): - out = cls(group['bins'].value, filter_id=filter_id) - out._num_bins = group['n_bins'].value + if group['type'][()].decode() == cls.short_name.lower(): + out = cls(group['bins'][()], filter_id=filter_id) + out._num_bins = group['n_bins'][()] return out # Search through all subclasses and find the one matching the HDF5 # 'type'. Call that class's from_hdf5 method. for subclass in cls._recursive_subclasses(): - if group['type'].value.decode() == subclass.short_name.lower(): + if group['type'][()].decode() == subclass.short_name.lower(): return subclass.from_hdf5(group, **kwargs) raise ValueError("Unrecognized Filter class: '" - + group['type'].value.decode() + "'") + + group['type'][()].decode() + "'") @property def bins(self): @@ -618,16 +618,16 @@ class MeshFilter(Filter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") if 'meshes' not in kwargs: raise ValueError(cls.__name__ + " requires a 'meshes' keyword " "argument.") - mesh_id = group['bins'].value + mesh_id = group['bins'][()] mesh_obj = kwargs['meshes'][mesh_id] filter_id = int(group.name.split('/')[-1].lstrip('filter ')) @@ -1191,15 +1191,15 @@ class DistribcellFilter(Filter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - out = cls(group['bins'].value, filter_id=filter_id) - out._num_bins = group['n_bins'].value + out = cls(group['bins'][()], filter_id=filter_id) + out._num_bins = group['n_bins'][()] return out @@ -1638,13 +1638,13 @@ class EnergyFunctionFilter(Filter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") - energy = group['energy'].value - y = group['y'].value + energy = group['energy'][()] + y = group['y'][()] filter_id = int(group.name.split('/')[-1].lstrip('filter ')) return cls(energy, y, filter_id=filter_id) diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index 59457b685..cc085df8a 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -92,14 +92,14 @@ class LegendreFilter(ExpansionFilter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - out = cls(group['order'].value, filter_id) + out = cls(group['order'][()], filter_id) return out @@ -198,15 +198,15 @@ class SpatialLegendreFilter(ExpansionFilter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - order = group['order'].value - axis = group['axis'].value.decode() - min_, max_ = group['min'].value, group['max'].value + order = group['order'][()] + axis = group['axis'][()].decode() + min_, max_ = group['min'][()], group['max'][()] return cls(order, axis, min_, max_, filter_id) @@ -294,15 +294,15 @@ class SphericalHarmonicsFilter(ExpansionFilter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - out = cls(group['order'].value, filter_id) - out.cosine = group['cosine'].value.decode() + out = cls(group['order'][()], filter_id) + out.cosine = group['cosine'][()].decode() return out @@ -437,14 +437,14 @@ class ZernikeFilter(ExpansionFilter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - order = group['order'].value - x, y, r = group['x'].value, group['y'].value, group['r'].value + order = group['order'][()] + x, y, r = group['x'][()], group['y'][()], group['r'][()] return cls(order, x, y, r, filter_id) diff --git a/openmc/lattice.py b/openmc/lattice.py index 8bf4e4757..ac5799255 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -100,15 +100,15 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): """ lattice_id = int(group.name.split('/')[-1].lstrip('lattice ')) - name = group['name'].value.decode() if 'name' in group else '' - lattice_type = group['type'].value.decode() + name = group['name'][()].decode() if 'name' in group else '' + lattice_type = group['type'][()].decode() if lattice_type == 'rectangular': - dimension = group['dimension'][...] - lower_left = group['lower_left'][...] - pitch = group['pitch'][...] - outer = group['outer'].value - universe_ids = group['universes'][...] + dimension = group['dimension'][()] + lower_left = group['lower_left'][()] + pitch = group['pitch'][()] + outer = group['outer'][()] + universe_ids = group['universes'][()] # Create the Lattice lattice = openmc.RectLattice(lattice_id, name) @@ -136,13 +136,13 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): lattice.universes = uarray elif lattice_type == 'hexagonal': - n_rings = group['n_rings'].value - n_axial = group['n_axial'].value - center = group['center'][...] - pitch = group['pitch'][...] - outer = group['outer'].value + n_rings = group['n_rings'][()] + n_axial = group['n_axial'][()] + center = group['center'][()] + pitch = group['pitch'][()] + outer = group['outer'][()] - universe_ids = group['universes'][...] + universe_ids = group['universes'][()] # Create the Lattice lattice = openmc.HexLattice(lattice_id, name) diff --git a/openmc/material.py b/openmc/material.py index 42c56aced..55aef743c 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -277,10 +277,10 @@ class Material(IDManagerMixin): """ mat_id = int(group.name.split('/')[-1].lstrip('material ')) - name = group['name'].value.decode() if 'name' in group else '' - density = group['atom_density'].value + name = group['name'][()].decode() if 'name' in group else '' + density = group['atom_density'][()] if 'nuclide_densities' in group: - nuc_densities = group['nuclide_densities'][...] + nuc_densities = group['nuclide_densities'][()] # Create the Material material = cls(mat_id, name) @@ -290,7 +290,7 @@ class Material(IDManagerMixin): # Read the names of the S(a,b) tables for this Material and add them if 'sab_names' in group: - sab_tables = group['sab_names'].value + sab_tables = group['sab_names'][()] for sab_table in sab_tables: name = sab_table.decode() material.add_s_alpha_beta(name) @@ -299,13 +299,13 @@ class Material(IDManagerMixin): material.set_density(density=density, units='atom/b-cm') if 'nuclides' in group: - nuclides = group['nuclides'].value + nuclides = group['nuclides'][()] # Add all nuclides to the Material for fullname, density in zip(nuclides, nuc_densities): name = fullname.decode().strip() material.add_nuclide(name, percent=density, percent_type='ao') if 'macroscopics' in group: - macroscopics = group['macroscopics'].value + macroscopics = group['macroscopics'][()] # Add all macroscopics to the Material for fullname in macroscopics: name = fullname.decode().strip() diff --git a/openmc/mesh.py b/openmc/mesh.py index f454a6f88..ba07ec178 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -174,11 +174,11 @@ class Mesh(IDManagerMixin): # Read and assign mesh properties mesh = cls(mesh_id) - mesh.type = group['type'].value.decode() - mesh.dimension = group['dimension'].value - mesh.lower_left = group['lower_left'].value - mesh.upper_right = group['upper_right'].value - mesh.width = group['width'].value + mesh.type = group['type'][()].decode() + mesh.dimension = group['dimension'][()] + mesh.lower_left = group['lower_left'][()] + mesh.upper_right = group['upper_right'][()] + mesh.width = group['width'][()] return mesh diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 51c91ef17..f6864ebe4 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -2219,7 +2219,7 @@ class XSdata(object): for xs_type in xs_types: set_func = 'set_' + xs_type.replace(' ', '_').replace('-', '_') if xs_type in temperature_group: - getattr(data, set_func)(temperature_group[xs_type].value, + getattr(data, set_func)(temperature_group[xs_type][()], float_temp) scatt_group = temperature_group['scatter_data'] @@ -2227,7 +2227,7 @@ class XSdata(object): # Get scatter matrix and 'un-flatten' it g_max = scatt_group['g_max'] g_min = scatt_group['g_min'] - flat_scatter = scatt_group['scatter_matrix'].value + flat_scatter = scatt_group['scatter_matrix'][()] scatter_matrix = np.zeros(data.xs_shapes["[G][G'][Order]"]) G = data.energy_groups.num_groups if data.representation == 'isotropic': @@ -2259,7 +2259,7 @@ class XSdata(object): # Repeat for multiplicity if 'multiplicity_matrix' in scatt_group: - flat_mult = scatt_group['multiplicity_matrix'].value + flat_mult = scatt_group['multiplicity_matrix'][()] mult_matrix = np.zeros(data.xs_shapes["[G][G']"]) flat_index = 0 for p in range(Np): diff --git a/openmc/particle_restart.py b/openmc/particle_restart.py index bc8666969..68a761458 100644 --- a/openmc/particle_restart.py +++ b/openmc/particle_restart.py @@ -49,44 +49,44 @@ class Particle(object): @property def current_batch(self): - return self._f['current_batch'].value + return self._f['current_batch'][()] @property def current_generation(self): - return self._f['current_generation'].value + return self._f['current_generation'][()] @property def energy(self): - return self._f['energy'].value + return self._f['energy'][()] @property def generations_per_batch(self): - return self._f['generations_per_batch'].value + return self._f['generations_per_batch'][()] @property def id(self): - return self._f['id'].value + return self._f['id'][()] @property def type(self): - return self._f['type'].value + return self._f['type'][()] @property def n_particles(self): - return self._f['n_particles'].value + return self._f['n_particles'][()] @property def run_mode(self): - return self._f['run_mode'].value.decode() + return self._f['run_mode'][()].decode() @property def uvw(self): - return self._f['uvw'].value + return self._f['uvw'][()] @property def weight(self): - return self._f['weight'].value + return self._f['weight'][()] @property def xyz(self): - return self._f['xyz'].value + return self._f['xyz'][()] diff --git a/openmc/statepoint.py b/openmc/statepoint.py index df8560379..3dc653584 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -161,35 +161,35 @@ class StatePoint(object): @property def cmfd_balance(self): - return self._f['cmfd/cmfd_balance'].value if self.cmfd_on else None + return self._f['cmfd/cmfd_balance'][()] if self.cmfd_on else None @property def cmfd_dominance(self): - return self._f['cmfd/cmfd_dominance'].value if self.cmfd_on else None + return self._f['cmfd/cmfd_dominance'][()] if self.cmfd_on else None @property def cmfd_entropy(self): - return self._f['cmfd/cmfd_entropy'].value if self.cmfd_on else None + return self._f['cmfd/cmfd_entropy'][()] if self.cmfd_on else None @property def cmfd_indices(self): - return self._f['cmfd/indices'].value if self.cmfd_on else None + return self._f['cmfd/indices'][()] if self.cmfd_on else None @property def cmfd_src(self): if self.cmfd_on: - data = self._f['cmfd/cmfd_src'].value + data = self._f['cmfd/cmfd_src'][()] return np.reshape(data, tuple(self.cmfd_indices), order='F') else: return None @property def cmfd_srccmp(self): - return self._f['cmfd/cmfd_srccmp'].value if self.cmfd_on else None + return self._f['cmfd/cmfd_srccmp'][()] if self.cmfd_on else None @property def current_batch(self): - return self._f['current_batch'].value + return self._f['current_batch'][()] @property def date_and_time(self): @@ -199,7 +199,7 @@ class StatePoint(object): @property def entropy(self): if self.run_mode == 'eigenvalue': - return self._f['entropy'].value + return self._f['entropy'][()] else: return None @@ -220,14 +220,14 @@ class StatePoint(object): @property def generations_per_batch(self): if self.run_mode == 'eigenvalue': - return self._f['generations_per_batch'].value + return self._f['generations_per_batch'][()] else: return None @property def global_tallies(self): if self._global_tallies is None: - data = self._f['global_tallies'].value + data = self._f['global_tallies'][()] gt = np.zeros(data.shape[0], dtype=[ ('name', 'a14'), ('sum', 'f8'), ('sum_sq', 'f8'), ('mean', 'f8'), ('std_dev', 'f8')]) @@ -248,42 +248,42 @@ class StatePoint(object): @property def k_cmfd(self): if self.cmfd_on: - return self._f['cmfd/k_cmfd'].value + return self._f['cmfd/k_cmfd'][()] else: return None @property def k_generation(self): if self.run_mode == 'eigenvalue': - return self._f['k_generation'].value + return self._f['k_generation'][()] else: return None @property def k_combined(self): if self.run_mode == 'eigenvalue': - return ufloat(*self._f['k_combined'].value) + return ufloat(*self._f['k_combined'][()]) else: return None @property def k_col_abs(self): if self.run_mode == 'eigenvalue': - return self._f['k_col_abs'].value + return self._f['k_col_abs'][()] else: return None @property def k_col_tra(self): if self.run_mode == 'eigenvalue': - return self._f['k_col_tra'].value + return self._f['k_col_tra'][()] else: return None @property def k_abs_tra(self): if self.run_mode == 'eigenvalue': - return self._f['k_abs_tra'].value + return self._f['k_abs_tra'][()] else: return None @@ -303,22 +303,22 @@ class StatePoint(object): @property def n_batches(self): - return self._f['n_batches'].value + return self._f['n_batches'][()] @property def n_inactive(self): if self.run_mode == 'eigenvalue': - return self._f['n_inactive'].value + return self._f['n_inactive'][()] else: return None @property def n_particles(self): - return self._f['n_particles'].value + return self._f['n_particles'][()] @property def n_realizations(self): - return self._f['n_realizations'].value + return self._f['n_realizations'][()] @property def path(self): @@ -330,20 +330,20 @@ class StatePoint(object): @property def run_mode(self): - return self._f['run_mode'].value.decode() + return self._f['run_mode'][()].decode() @property def runtime(self): - return {name: dataset.value + return {name: dataset[()] for name, dataset in self._f['runtime'].items()} @property def seed(self): - return self._f['seed'].value + return self._f['seed'][()] @property def source(self): - return self._f['source_bank'].value if self.source_present else None + return self._f['source_bank'][()] if self.source_present else None @property def source_present(self): @@ -376,24 +376,24 @@ class StatePoint(object): group = tallies_group['tally {}'.format(tally_id)] # Read the number of realizations - n_realizations = group['n_realizations'].value + n_realizations = group['n_realizations'][()] # Create Tally object and assign basic properties tally = openmc.Tally(tally_id) tally._sp_filename = self._f.filename - tally.name = group['name'].value.decode() if 'name' in group else '' - tally.estimator = group['estimator'].value.decode() + tally.name = group['name'][()].decode() if 'name' in group else '' + tally.estimator = group['estimator'][()].decode() tally.num_realizations = n_realizations # Read derivative information. if 'derivative' in group: - deriv_id = group['derivative'].value + deriv_id = group['derivative'][()] tally.derivative = self.tally_derivatives[deriv_id] # Read all filters - n_filters = group['n_filters'].value + n_filters = group['n_filters'][()] if n_filters > 0: - filter_ids = group['filters'].value + filter_ids = group['filters'][()] filters_group = self._f['tallies/filters'] for filter_id in filter_ids: filter_group = filters_group['filter {}'.format( @@ -403,15 +403,15 @@ class StatePoint(object): tally.filters.append(new_filter) # Read nuclide bins - nuclide_names = group['nuclides'].value + nuclide_names = group['nuclides'][()] # Add all nuclides to the Tally for name in nuclide_names: nuclide = openmc.Nuclide(name.decode().strip()) tally.nuclides.append(nuclide) - scores = group['score_bins'].value - n_score_bins = group['n_score_bins'].value + scores = group['score_bins'][()] + n_score_bins = group['n_score_bins'][()] # Add the scores to the Tally for j, score in enumerate(scores): @@ -445,14 +445,14 @@ class StatePoint(object): group = self._f['tallies/derivatives/derivative {}' .format(d_id)] deriv = openmc.TallyDerivative(derivative_id=d_id) - deriv.variable = group['independent variable'].value.decode() + deriv.variable = group['independent variable'][()].decode() if deriv.variable == 'density': - deriv.material = group['material'].value + deriv.material = group['material'][()] elif deriv.variable == 'nuclide_density': - deriv.material = group['material'].value - deriv.nuclide = group['nuclide'].value.decode() + deriv.material = group['material'][()] + deriv.nuclide = group['nuclide'][()].decode() elif deriv.variable == 'temperature': - deriv.material = group['material'].value + deriv.material = group['material'][()] self._derivs[d_id] = deriv self._derivs_read = True diff --git a/openmc/summary.py b/openmc/summary.py index 866dd8288..2ab29c00a 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -85,14 +85,14 @@ class Summary(object): def _read_nuclides(self): if 'nuclides/names' in self._f: - names = self._f['nuclides/names'].value - awrs = self._f['nuclides/awrs'].value + names = self._f['nuclides/names'][()] + awrs = self._f['nuclides/awrs'][()] for name, awr in zip(names, awrs): self._nuclides[name.decode()] = awr def _read_macroscopics(self): if 'macroscopics/names' in self._f: - names = self._f['macroscopics/names'].value + names = self._f['macroscopics/names'][()] for name in names: self._macroscopics = name.decode() @@ -130,34 +130,34 @@ class Summary(object): for key, group in self._f['geometry/cells'].items(): cell_id = int(key.lstrip('cell ')) - name = group['name'].value.decode() if 'name' in group else '' - fill_type = group['fill_type'].value.decode() + name = group['name'][()].decode() if 'name' in group else '' + fill_type = group['fill_type'][()].decode() if fill_type == 'material': - fill = group['material'].value + fill = group['material'][()] elif fill_type == 'universe': - fill = group['fill'].value + fill = group['fill'][()] else: - fill = group['lattice'].value + fill = group['lattice'][()] - region = group['region'].value.decode() if 'region' in group else '' + region = group['region'][()].decode() if 'region' in group else '' # Create this Cell cell = openmc.Cell(cell_id=cell_id, name=name) if fill_type == 'universe': if 'translation' in group: - translation = group['translation'][...] + translation = group['translation'][()] translation = np.asarray(translation, dtype=np.float64) cell.translation = translation if 'rotation' in group: - rotation = group['rotation'][...] + rotation = group['rotation'][()] rotation = np.asarray(rotation, dtype=np.int) cell._rotation = rotation elif fill_type == 'material': - cell.temperature = group['temperature'][...] + cell.temperature = group['temperature'][()] # Store Cell fill information for after Universe/Lattice creation cell_fills[cell.id] = (fill_type, fill) diff --git a/openmc/surface.py b/openmc/surface.py index 0f10e7f48..3dac4ed5b 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -269,10 +269,10 @@ class Surface(IDManagerMixin, metaclass=ABCMeta): """ surface_id = int(group.name.split('/')[-1].lstrip('surface ')) - name = group['name'].value.decode() if 'name' in group else '' - surf_type = group['type'].value.decode() - bc = group['boundary_type'].value.decode() - coeffs = group['coefficients'][...] + name = group['name'][()].decode() if 'name' in group else '' + surf_type = group['type'][()].decode() + bc = group['boundary_type'][()].decode() + coeffs = group['coefficients'][()] # Create the Surface based on its type if surf_type == 'x-plane': diff --git a/openmc/tallies.py b/openmc/tallies.py index 291090b19..a5f3a17f3 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -217,7 +217,7 @@ class Tally(IDManagerMixin): f = h5py.File(self._sp_filename, 'r') # Extract Tally data from the file - data = f['tallies/tally {0}/results'.format(self.id)].value + data = f['tallies/tally {0}/results'.format(self.id)] sum = data[:, :, 0] sum_sq = data[:, :, 1] diff --git a/openmc/universe.py b/openmc/universe.py index 044da12e3..ee038ebef 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -124,7 +124,7 @@ class Universe(IDManagerMixin): """ universe_id = int(group.name.split('/')[-1].lstrip('universe ')) - cell_ids = group['cells'].value + cell_ids = group['cells'][()] # Create this Universe universe = cls(universe_id) diff --git a/openmc/volume.py b/openmc/volume.py index af7c356ae..7ac4fdd0c 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -211,9 +211,9 @@ class VolumeCalculation(object): domain_id = int(obj_name[7:]) ids.append(domain_id) group = f[obj_name] - volume = ufloat(*group['volume'].value) - nucnames = group['nuclides'].value - atoms_ = group['atoms'].value + volume = ufloat(*group['volume'][()]) + nucnames = group['nuclides'][()] + atoms_ = group['atoms'][()] atom_dict = OrderedDict() for name_i, atoms_i in zip(nucnames, atoms_): From 7905b196c340747a7b07face47ec3ffbd82d82c5 Mon Sep 17 00:00:00 2001 From: liangjg Date: Wed, 27 Mar 2019 10:41:39 -0400 Subject: [PATCH 126/165] update _SUBSHELLS array --- openmc/data/photon.py | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/openmc/data/photon.py b/openmc/data/photon.py index d8f46f9a4..7d1a11475 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -20,18 +20,10 @@ from .function import Tabulated1D # Electron subshell labels -_SUBSHELLS = ['K', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5', - 'N1', 'N2', 'N3', 'N4', 'N5', 'N6', 'N7', 'O1', 'O2', - 'O3', 'O4', 'O5', 'O6', 'O7', 'O8', 'O9', 'P1', 'P2', - 'P3', 'P4', 'P5', 'P6', 'P7', 'P8', 'P9', 'P10', 'P11', - 'Q1', 'Q2', 'Q3'] - -# Helper function to map designator to subshell string or None -def _subshell(i): - if i == 0: - return None - else: - return _SUBSHELLS[i - 1] +_SUBSHELLS = [None, 'K', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5', + 'N1', 'N2', 'N3', 'N4', 'N5', 'N6', 'N7', 'O1', 'O2', 'O3', + 'O4', 'O5', 'O6', 'O7', 'O8', 'O9', 'P1', 'P2', 'P3', 'P4', + 'P5', 'P6', 'P7', 'P8', 'P9', 'P10', 'P11','Q1', 'Q2', 'Q3'] _REACTION_NAME = { 501: ('Total photon interaction', 'total'), @@ -224,7 +216,7 @@ class AtomicRelaxation(EqualityMixin): # Get shell designators n = ace.nxs[7] idx = ace.jxs[11] - shells = [_subshell(int(i)) for i in ace.xss[idx : idx+n]] + shells = [_SUBSHELLS[int(i)] for i in ace.xss[idx : idx+n]] # Get number of electrons for each shell idx = ace.jxs[12] @@ -244,8 +236,8 @@ class AtomicRelaxation(EqualityMixin): if n_transitions > 0: records = [] for j in range(n_transitions): - subj = _subshell(int(ace.xss[idx])) - subk = _subshell(int(ace.xss[idx + 1])) + subj = _SUBSHELLS[int(ace.xss[idx])] + subk = _SUBSHELLS[int(ace.xss[idx + 1])] etr = ace.xss[idx + 2]*EV_PER_MEV if j == 0: ftr = ace.xss[idx + 3] @@ -300,7 +292,7 @@ class AtomicRelaxation(EqualityMixin): # Read data for each subshell for i in range(n_subshells): params, list_items = get_list_record(file_obj) - subi = _subshell(int(params[0])) + subi = _SUBSHELLS[int(params[0])] n_transitions = int(params[5]) binding_energy[subi] = list_items[0] num_electrons[subi] = list_items[1] @@ -309,8 +301,8 @@ class AtomicRelaxation(EqualityMixin): # Read transition data records = [] for j in range(n_transitions): - subj = _subshell(int(list_items[6*(j+1)])) - subk = _subshell(int(list_items[6*(j+1) + 1])) + subj = _SUBSHELLS[int(list_items[6*(j+1)])] + subk = _SUBSHELLS[int(list_items[6*(j+1) + 1])] etr = list_items[6*(j+1) + 2] ftr = list_items[6*(j+1) + 3] records.append((subj, subk, etr, ftr)) @@ -343,7 +335,6 @@ class AtomicRelaxation(EqualityMixin): transitions = {} designators = [s.decode() for s in group.attrs['designators']] - shell_values = [None] + _SUBSHELLS columns = ['secondary', 'tertiary', 'energy (eV)', 'probability'] for shell in designators: # Shell group @@ -361,7 +352,7 @@ class AtomicRelaxation(EqualityMixin): columns=columns) # Replace float indexes back to subshell strings df[columns[:2]] = df[columns[:2]].replace( - np.arange(float(len(shell_values))), shell_values) + np.arange(float(len(_SUBSHELLS))), _SUBSHELLS) transitions[shell] = df return cls(binding_energy, num_electrons, transitions) @@ -384,10 +375,9 @@ class AtomicRelaxation(EqualityMixin): # Write transition data with replacements if shell in self.transitions: - shell_values = [None] + _SUBSHELLS df = self.transitions[shell].replace( - shell_values, range(len(shell_values))) - group.create_dataset('transitions', data=df.values.astype(float)) + _SUBSHELLS, np.arange(float(len(_SUBSHELLS)))) + group.create_dataset('transitions') class IncidentPhoton(EqualityMixin): @@ -572,7 +562,7 @@ class IncidentPhoton(EqualityMixin): idx += n_energy # Copy binding energy - shell = _subshell(d) + shell = _SUBSHELLS[d] e = data.atomic_relaxation.binding_energy[shell] rx.subshell_binding_energy = e From 8926a70bad0102706cb2699385c14a5a778e4571 Mon Sep 17 00:00:00 2001 From: liangjg Date: Wed, 27 Mar 2019 10:44:20 -0400 Subject: [PATCH 127/165] fix style issues suggested by @paulromano --- openmc/data/photon.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 7d1a11475..951958063 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -671,7 +671,7 @@ class IncidentPhoton(EqualityMixin): data = cls(Z) # Read energy grid - energy= group['energy'].value + energy = group['energy'].value # Read cross section data for mt, (name, key) in _REACTION_NAME.items(): @@ -685,7 +685,7 @@ class IncidentPhoton(EqualityMixin): data.reactions[mt] = PhotonReaction.from_hdf5(rgroup, mt, energy) # Check for necessary reactions - for mt in [502, 504, 522]: + for mt in (502, 504, 522): assert mt in data, "Reaction {} not found".format(mt) # Read atomic relaxation @@ -794,7 +794,6 @@ class IncidentPhoton(EqualityMixin): else: brem_group.create_dataset(key, data=value) - def _add_bremsstrahlung(self): """Add the data used in the thick-target bremsstrahlung approximation @@ -1103,7 +1102,7 @@ class PhotonReaction(EqualityMixin): if 'threshold_idx' in group['xs'].attrs: threshold_idx = group['xs'].attrs['threshold_idx'] - # Store + # Store cross section rx.xs = Tabulated1D(energy[threshold_idx:], xs, [len(xs)], [5]) # Check for anomalous scattering factor From 089864216431dbcadfb8b718859524b342bead66 Mon Sep 17 00:00:00 2001 From: liangjg Date: Wed, 27 Mar 2019 11:11:22 -0400 Subject: [PATCH 128/165] dataset.value -> dataset[()] in photon.py --- openmc/data/photon.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 951958063..db984c769 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -348,7 +348,7 @@ class AtomicRelaxation(EqualityMixin): # Read transition data if 'transitions' in sub_group: - df = pd.DataFrame(sub_group['transitions'].value, + df = pd.DataFrame(sub_group['transitions'][()], columns=columns) # Replace float indexes back to subshell strings df[columns[:2]] = df[columns[:2]].replace( @@ -611,12 +611,12 @@ class IncidentPhoton(EqualityMixin): if not _COMPTON_PROFILES: filename = os.path.join(os.path.dirname(__file__), 'compton_profiles.h5') with h5py.File(filename, 'r') as f: - _COMPTON_PROFILES['pz'] = f['pz'].value + _COMPTON_PROFILES['pz'] = f['pz'][()] for i in range(1, 101): group = f['{:03}'.format(i)] - num_electrons = group['num_electrons'].value - binding_energy = group['binding_energy'].value*EV_PER_MEV - J = group['J'].value + num_electrons = group['num_electrons'][()] + binding_energy = group['binding_energy'][()]*EV_PER_MEV + J = group['J'][()] _COMPTON_PROFILES[i] = {'num_electrons': num_electrons, 'binding_energy': binding_energy, 'J': J} @@ -671,7 +671,7 @@ class IncidentPhoton(EqualityMixin): data = cls(Z) # Read energy grid - energy = group['energy'].value + energy = group['energy'][()] # Read cross section data for mt, (name, key) in _REACTION_NAME.items(): @@ -695,12 +695,12 @@ class IncidentPhoton(EqualityMixin): if 'compton_profiles' in group: rgroup = group['compton_profiles'] profile = data.compton_profiles - profile['num_electrons'] = rgroup['num_electrons'].value - profile['binding_energy'] = rgroup['binding_energy'].value + profile['num_electrons'] = rgroup['num_electrons'][()] + profile['binding_energy'] = rgroup['binding_energy'][()] # Get electron momentum values - pz = rgroup['pz'].value - J = rgroup['J'].value + pz = rgroup['pz'][()] + J = rgroup['J'][()] if pz.size != J.shape[1]: raise ValueError("'J' array shape is not consistent with the " "'pz' array shape") @@ -712,7 +712,7 @@ class IncidentPhoton(EqualityMixin): data.bremsstrahlung['I'] = rgroup.attrs['I'] for key in ('dcs', 'electron_energy', 'ionization_energy', 'num_electrons', 'photon_energy'): - data.bremsstrahlung[key] = rgroup[key].value + data.bremsstrahlung[key] = rgroup[key][()] return data @@ -807,8 +807,8 @@ class IncidentPhoton(EqualityMixin): group = f['{:03}'.format(i)] _BREMSSTRAHLUNG[i] = { 'I': group.attrs['I'], - 'num_electrons': group['num_electrons'].value, - 'ionization_energy': group['ionization_energy'].value + 'num_electrons': group['num_electrons'][()], + 'ionization_energy': group['ionization_energy'][()] } filename = os.path.join(os.path.dirname(__file__), 'BREMX.DAT') @@ -1093,7 +1093,7 @@ class PhotonReaction(EqualityMixin): rx = cls(mt) # Cross sections - xs = group['xs'].value + xs = group['xs'][()] # Replace zero elements to small non-zero to enable log-log xs[xs == 0.0] = np.exp(-500.0) From ea71b9e3770ebe43955e33af3938292f493d848f Mon Sep 17 00:00:00 2001 From: liangjg Date: Wed, 27 Mar 2019 11:45:48 -0400 Subject: [PATCH 129/165] replace all dataset.value with dataset[()] (or occasionally dataset[...]) --- openmc/data/angle_distribution.py | 2 +- openmc/data/correlated.py | 6 +-- openmc/data/energy_distribution.py | 2 +- openmc/data/function.py | 2 +- openmc/data/kalbach_mann.py | 2 +- openmc/data/multipole.py | 16 +++---- openmc/data/neutron.py | 2 +- openmc/data/reaction.py | 2 +- openmc/data/thermal.py | 8 ++-- openmc/data/urr.py | 4 +- openmc/deplete/results_list.py | 2 +- openmc/filter.py | 32 ++++++------- openmc/filter_expansion.py | 32 ++++++------- openmc/lattice.py | 18 +++---- openmc/material.py | 10 ++-- openmc/mesh.py | 10 ++-- openmc/mgxs_library.py | 8 ++-- openmc/particle_restart.py | 22 ++++----- openmc/statepoint.py | 76 +++++++++++++++--------------- openmc/summary.py | 18 +++---- openmc/surface.py | 6 +-- openmc/tallies.py | 2 +- openmc/universe.py | 2 +- openmc/volume.py | 6 +-- 24 files changed, 145 insertions(+), 145 deletions(-) diff --git a/openmc/data/angle_distribution.py b/openmc/data/angle_distribution.py index a1f498ba6..638590cff 100644 --- a/openmc/data/angle_distribution.py +++ b/openmc/data/angle_distribution.py @@ -115,7 +115,7 @@ class AngleDistribution(EqualityMixin): Angular distribution """ - energy = group['energy'].value + energy = group['energy'][()] data = group['mu'] offsets = data.attrs['offsets'] interpolation = data.attrs['interpolation'] diff --git a/openmc/data/correlated.py b/openmc/data/correlated.py index 8cc4509ce..b760f2e2f 100644 --- a/openmc/data/correlated.py +++ b/openmc/data/correlated.py @@ -210,15 +210,15 @@ class CorrelatedAngleEnergy(AngleEnergy): interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] - energy = group['energy'].value + energy = group['energy'][()] offsets = group['energy_out'].attrs['offsets'] interpolation = group['energy_out'].attrs['interpolation'] n_discrete_lines = group['energy_out'].attrs['n_discrete_lines'] - dset_eout = group['energy_out'].value + dset_eout = group['energy_out'][()] energy_out = [] - dset_mu = group['mu'].value + dset_mu = group['mu'][()] mu = [] n_energy = len(energy) diff --git a/openmc/data/energy_distribution.py b/openmc/data/energy_distribution.py index 9e01a4b30..bff97bf81 100644 --- a/openmc/data/energy_distribution.py +++ b/openmc/data/energy_distribution.py @@ -1144,7 +1144,7 @@ class ContinuousTabular(EnergyDistribution): interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] - energy = group['energy'].value + energy = group['energy'][()] data = group['distribution'] offsets = data.attrs['offsets'] diff --git a/openmc/data/function.py b/openmc/data/function.py index 36443e761..582d4ee6f 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -434,7 +434,7 @@ class Polynomial(np.polynomial.Polynomial, Function1D): if dataset.attrs['type'].decode() != cls.__name__: raise ValueError("Expected an HDF5 attribute 'type' equal to '" + cls.__name__ + "'") - return cls(dataset.value) + return cls(dataset[()]) class Combination(EqualityMixin): diff --git a/openmc/data/kalbach_mann.py b/openmc/data/kalbach_mann.py index 4be0c15d5..c7df015a7 100644 --- a/openmc/data/kalbach_mann.py +++ b/openmc/data/kalbach_mann.py @@ -202,7 +202,7 @@ class KalbachMann(AngleEnergy): interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] - energy = group['energy'].value + energy = group['energy'][()] data = group['distribution'] offsets = data.attrs['offsets'] diff --git a/openmc/data/multipole.py b/openmc/data/multipole.py index 9022061a0..6178161ef 100644 --- a/openmc/data/multipole.py +++ b/openmc/data/multipole.py @@ -356,24 +356,24 @@ class WindowedMultipole(EqualityMixin): # Read scalars. - out.spacing = group['spacing'].value - out.sqrtAWR = group['sqrtAWR'].value - out.E_min = group['E_min'].value - out.E_max = group['E_max'].value + out.spacing = group['spacing'][()] + out.sqrtAWR = group['sqrtAWR'][()] + out.E_min = group['E_min'][()] + out.E_max = group['E_max'][()] # Read arrays. err = "WMP '{}' array shape is not consistent with the '{}' array shape" - out.data = group['data'].value + out.data = group['data'][()] - out.windows = group['windows'].value + out.windows = group['windows'][()] - out.broaden_poly = group['broaden_poly'].value.astype(np.bool) + out.broaden_poly = group['broaden_poly'][...].astype(np.bool) if out.broaden_poly.shape[0] != out.windows.shape[0]: raise ValueError(err.format('broaden_poly', 'windows')) - out.curvefit = group['curvefit'].value + out.curvefit = group['curvefit'][()] if out.curvefit.shape[0] != out.windows.shape[0]: raise ValueError(err.format('curvefit', 'windows')) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 2ff55700f..c93720902 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -521,7 +521,7 @@ class IncidentNeutron(EqualityMixin): kTg = group['kTs'] kTs = [] for temp in kTg: - kTs.append(kTg[temp].value) + kTs.append(kTg[temp][()]) data = cls(name, atomic_number, mass_number, metastable, atomic_weight_ratio, kTs) diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index a988f2d6d..c5abc73c3 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -938,7 +938,7 @@ class Reaction(EqualityMixin): 'Could not create reaction cross section for MT={} ' 'at T={} because no corresponding energy grid ' 'exists.'.format(mt, T)) - xs = Tgroup['xs'].value + xs = Tgroup['xs'][()] threshold_idx = Tgroup['xs'].attrs['threshold_idx'] - 1 tabulated_xs = Tabulated1D(energy[T][threshold_idx:], xs) tabulated_xs._threshold_idx = threshold_idx diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index b10cdeba4..ef1fa3b02 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -414,7 +414,7 @@ class ThermalScattering(EqualityMixin): kTg = group['kTs'] kTs = [] for temp in kTg: - kTs.append(kTg[temp].value) + kTs.append(kTg[temp][()]) temperatures = [str(int(round(kT / K_BOLTZMANN))) + "K" for kT in kTs] table = cls(name, atomic_weight_ratio, kTs) @@ -438,7 +438,7 @@ class ThermalScattering(EqualityMixin): # Angular distribution if 'mu_out' in elastic_group: - table.elastic_mu_out[T] = elastic_group['mu_out'].value + table.elastic_mu_out[T] = elastic_group['mu_out'][()] # Read thermal inelastic scattering if 'inelastic' in Tgroup: @@ -446,8 +446,8 @@ class ThermalScattering(EqualityMixin): table.inelastic_xs[T] = Tabulated1D.from_hdf5( inelastic_group['xs']) if table.secondary_mode in ('equal', 'skewed'): - table.inelastic_e_out[T] = inelastic_group['energy_out'].value - table.inelastic_mu_out[T] = inelastic_group['mu_out'].value + table.inelastic_e_out[T] = inelastic_group['energy_out'][()] + table.inelastic_mu_out[T] = inelastic_group['mu_out'][()] elif table.secondary_mode == 'continuous': table.inelastic_dist[T] = AngleEnergy.from_hdf5( inelastic_group) diff --git a/openmc/data/urr.py b/openmc/data/urr.py index 0edccf6f0..53961a50a 100644 --- a/openmc/data/urr.py +++ b/openmc/data/urr.py @@ -166,8 +166,8 @@ class ProbabilityTables(EqualityMixin): absorption_flag = group.attrs['absorption'] multiply_smooth = bool(group.attrs['multiply_smooth']) - energy = group['energy'].value - table = group['table'].value + energy = group['energy'][()] + table = group['table'][()] return cls(energy, table, interpolation, inelastic_flag, absorption_flag, multiply_smooth) diff --git a/openmc/deplete/results_list.py b/openmc/deplete/results_list.py index 58e4b66dc..9fb6eec86 100644 --- a/openmc/deplete/results_list.py +++ b/openmc/deplete/results_list.py @@ -20,7 +20,7 @@ class ResultsList(list): check_filetype_version(fh, 'depletion results', _VERSION_RESULTS[0]) # Get number of results stored - n = fh["number"].value.shape[0] + n = fh["number"][...].shape[0] for i in range(n): self.append(Results.from_hdf5(fh, i)) diff --git a/openmc/filter.py b/openmc/filter.py index ef68a4961..49d3ff5de 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -170,19 +170,19 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): # If the HDF5 'type' variable matches this class's short_name, then # there is no overriden from_hdf5 method. Pass the bins to __init__. - if group['type'].value.decode() == cls.short_name.lower(): - out = cls(group['bins'].value, filter_id=filter_id) - out._num_bins = group['n_bins'].value + if group['type'][()].decode() == cls.short_name.lower(): + out = cls(group['bins'][()], filter_id=filter_id) + out._num_bins = group['n_bins'][()] return out # Search through all subclasses and find the one matching the HDF5 # 'type'. Call that class's from_hdf5 method. for subclass in cls._recursive_subclasses(): - if group['type'].value.decode() == subclass.short_name.lower(): + if group['type'][()].decode() == subclass.short_name.lower(): return subclass.from_hdf5(group, **kwargs) raise ValueError("Unrecognized Filter class: '" - + group['type'].value.decode() + "'") + + group['type'][()].decode() + "'") @property def bins(self): @@ -618,16 +618,16 @@ class MeshFilter(Filter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") if 'meshes' not in kwargs: raise ValueError(cls.__name__ + " requires a 'meshes' keyword " "argument.") - mesh_id = group['bins'].value + mesh_id = group['bins'][()] mesh_obj = kwargs['meshes'][mesh_id] filter_id = int(group.name.split('/')[-1].lstrip('filter ')) @@ -1191,15 +1191,15 @@ class DistribcellFilter(Filter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - out = cls(group['bins'].value, filter_id=filter_id) - out._num_bins = group['n_bins'].value + out = cls(group['bins'][()], filter_id=filter_id) + out._num_bins = group['n_bins'][()] return out @@ -1638,13 +1638,13 @@ class EnergyFunctionFilter(Filter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") - energy = group['energy'].value - y = group['y'].value + energy = group['energy'][()] + y = group['y'][()] filter_id = int(group.name.split('/')[-1].lstrip('filter ')) return cls(energy, y, filter_id=filter_id) diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index 59457b685..cc085df8a 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -92,14 +92,14 @@ class LegendreFilter(ExpansionFilter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - out = cls(group['order'].value, filter_id) + out = cls(group['order'][()], filter_id) return out @@ -198,15 +198,15 @@ class SpatialLegendreFilter(ExpansionFilter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - order = group['order'].value - axis = group['axis'].value.decode() - min_, max_ = group['min'].value, group['max'].value + order = group['order'][()] + axis = group['axis'][()].decode() + min_, max_ = group['min'][()], group['max'][()] return cls(order, axis, min_, max_, filter_id) @@ -294,15 +294,15 @@ class SphericalHarmonicsFilter(ExpansionFilter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - out = cls(group['order'].value, filter_id) - out.cosine = group['cosine'].value.decode() + out = cls(group['order'][()], filter_id) + out.cosine = group['cosine'][()].decode() return out @@ -437,14 +437,14 @@ class ZernikeFilter(ExpansionFilter): @classmethod def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): + if group['type'][()].decode() != cls.short_name.lower(): raise ValueError("Expected HDF5 data for filter type '" + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") + + group['type'][()].decode() + " instead") filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - order = group['order'].value - x, y, r = group['x'].value, group['y'].value, group['r'].value + order = group['order'][()] + x, y, r = group['x'][()], group['y'][()], group['r'][()] return cls(order, x, y, r, filter_id) diff --git a/openmc/lattice.py b/openmc/lattice.py index 8bf4e4757..fb0a7a1bd 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -100,14 +100,14 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): """ lattice_id = int(group.name.split('/')[-1].lstrip('lattice ')) - name = group['name'].value.decode() if 'name' in group else '' - lattice_type = group['type'].value.decode() + name = group['name'][()].decode() if 'name' in group else '' + lattice_type = group['type'][()].decode() if lattice_type == 'rectangular': dimension = group['dimension'][...] lower_left = group['lower_left'][...] pitch = group['pitch'][...] - outer = group['outer'].value + outer = group['outer'][()] universe_ids = group['universes'][...] # Create the Lattice @@ -136,13 +136,13 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): lattice.universes = uarray elif lattice_type == 'hexagonal': - n_rings = group['n_rings'].value - n_axial = group['n_axial'].value - center = group['center'][...] - pitch = group['pitch'][...] - outer = group['outer'].value + n_rings = group['n_rings'][()] + n_axial = group['n_axial'][()] + center = group['center'][()] + pitch = group['pitch'][()] + outer = group['outer'][()] - universe_ids = group['universes'][...] + universe_ids = group['universes'][()] # Create the Lattice lattice = openmc.HexLattice(lattice_id, name) diff --git a/openmc/material.py b/openmc/material.py index 42c56aced..da913c778 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -277,8 +277,8 @@ class Material(IDManagerMixin): """ mat_id = int(group.name.split('/')[-1].lstrip('material ')) - name = group['name'].value.decode() if 'name' in group else '' - density = group['atom_density'].value + name = group['name'][()].decode() if 'name' in group else '' + density = group['atom_density'][()] if 'nuclide_densities' in group: nuc_densities = group['nuclide_densities'][...] @@ -290,7 +290,7 @@ class Material(IDManagerMixin): # Read the names of the S(a,b) tables for this Material and add them if 'sab_names' in group: - sab_tables = group['sab_names'].value + sab_tables = group['sab_names'][()] for sab_table in sab_tables: name = sab_table.decode() material.add_s_alpha_beta(name) @@ -299,13 +299,13 @@ class Material(IDManagerMixin): material.set_density(density=density, units='atom/b-cm') if 'nuclides' in group: - nuclides = group['nuclides'].value + nuclides = group['nuclides'][()] # Add all nuclides to the Material for fullname, density in zip(nuclides, nuc_densities): name = fullname.decode().strip() material.add_nuclide(name, percent=density, percent_type='ao') if 'macroscopics' in group: - macroscopics = group['macroscopics'].value + macroscopics = group['macroscopics'][()] # Add all macroscopics to the Material for fullname in macroscopics: name = fullname.decode().strip() diff --git a/openmc/mesh.py b/openmc/mesh.py index f454a6f88..ba07ec178 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -174,11 +174,11 @@ class Mesh(IDManagerMixin): # Read and assign mesh properties mesh = cls(mesh_id) - mesh.type = group['type'].value.decode() - mesh.dimension = group['dimension'].value - mesh.lower_left = group['lower_left'].value - mesh.upper_right = group['upper_right'].value - mesh.width = group['width'].value + mesh.type = group['type'][()].decode() + mesh.dimension = group['dimension'][()] + mesh.lower_left = group['lower_left'][()] + mesh.upper_right = group['upper_right'][()] + mesh.width = group['width'][()] return mesh diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 51c91ef17..b98902030 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -2183,7 +2183,7 @@ class XSdata(object): kTs_group = group['kTs'] float_temperatures = [] for temperature in temperatures: - kT = kTs_group[temperature].value + kT = kTs_group[temperature][()] float_temperatures.append(kT / openmc.data.K_BOLTZMANN) attrs = group.attrs.keys() @@ -2219,7 +2219,7 @@ class XSdata(object): for xs_type in xs_types: set_func = 'set_' + xs_type.replace(' ', '_').replace('-', '_') if xs_type in temperature_group: - getattr(data, set_func)(temperature_group[xs_type].value, + getattr(data, set_func)(temperature_group[xs_type][()], float_temp) scatt_group = temperature_group['scatter_data'] @@ -2227,7 +2227,7 @@ class XSdata(object): # Get scatter matrix and 'un-flatten' it g_max = scatt_group['g_max'] g_min = scatt_group['g_min'] - flat_scatter = scatt_group['scatter_matrix'].value + flat_scatter = scatt_group['scatter_matrix'][()] scatter_matrix = np.zeros(data.xs_shapes["[G][G'][Order]"]) G = data.energy_groups.num_groups if data.representation == 'isotropic': @@ -2259,7 +2259,7 @@ class XSdata(object): # Repeat for multiplicity if 'multiplicity_matrix' in scatt_group: - flat_mult = scatt_group['multiplicity_matrix'].value + flat_mult = scatt_group['multiplicity_matrix'][()] mult_matrix = np.zeros(data.xs_shapes["[G][G']"]) flat_index = 0 for p in range(Np): diff --git a/openmc/particle_restart.py b/openmc/particle_restart.py index bc8666969..68a761458 100644 --- a/openmc/particle_restart.py +++ b/openmc/particle_restart.py @@ -49,44 +49,44 @@ class Particle(object): @property def current_batch(self): - return self._f['current_batch'].value + return self._f['current_batch'][()] @property def current_generation(self): - return self._f['current_generation'].value + return self._f['current_generation'][()] @property def energy(self): - return self._f['energy'].value + return self._f['energy'][()] @property def generations_per_batch(self): - return self._f['generations_per_batch'].value + return self._f['generations_per_batch'][()] @property def id(self): - return self._f['id'].value + return self._f['id'][()] @property def type(self): - return self._f['type'].value + return self._f['type'][()] @property def n_particles(self): - return self._f['n_particles'].value + return self._f['n_particles'][()] @property def run_mode(self): - return self._f['run_mode'].value.decode() + return self._f['run_mode'][()].decode() @property def uvw(self): - return self._f['uvw'].value + return self._f['uvw'][()] @property def weight(self): - return self._f['weight'].value + return self._f['weight'][()] @property def xyz(self): - return self._f['xyz'].value + return self._f['xyz'][()] diff --git a/openmc/statepoint.py b/openmc/statepoint.py index df8560379..3dc653584 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -161,35 +161,35 @@ class StatePoint(object): @property def cmfd_balance(self): - return self._f['cmfd/cmfd_balance'].value if self.cmfd_on else None + return self._f['cmfd/cmfd_balance'][()] if self.cmfd_on else None @property def cmfd_dominance(self): - return self._f['cmfd/cmfd_dominance'].value if self.cmfd_on else None + return self._f['cmfd/cmfd_dominance'][()] if self.cmfd_on else None @property def cmfd_entropy(self): - return self._f['cmfd/cmfd_entropy'].value if self.cmfd_on else None + return self._f['cmfd/cmfd_entropy'][()] if self.cmfd_on else None @property def cmfd_indices(self): - return self._f['cmfd/indices'].value if self.cmfd_on else None + return self._f['cmfd/indices'][()] if self.cmfd_on else None @property def cmfd_src(self): if self.cmfd_on: - data = self._f['cmfd/cmfd_src'].value + data = self._f['cmfd/cmfd_src'][()] return np.reshape(data, tuple(self.cmfd_indices), order='F') else: return None @property def cmfd_srccmp(self): - return self._f['cmfd/cmfd_srccmp'].value if self.cmfd_on else None + return self._f['cmfd/cmfd_srccmp'][()] if self.cmfd_on else None @property def current_batch(self): - return self._f['current_batch'].value + return self._f['current_batch'][()] @property def date_and_time(self): @@ -199,7 +199,7 @@ class StatePoint(object): @property def entropy(self): if self.run_mode == 'eigenvalue': - return self._f['entropy'].value + return self._f['entropy'][()] else: return None @@ -220,14 +220,14 @@ class StatePoint(object): @property def generations_per_batch(self): if self.run_mode == 'eigenvalue': - return self._f['generations_per_batch'].value + return self._f['generations_per_batch'][()] else: return None @property def global_tallies(self): if self._global_tallies is None: - data = self._f['global_tallies'].value + data = self._f['global_tallies'][()] gt = np.zeros(data.shape[0], dtype=[ ('name', 'a14'), ('sum', 'f8'), ('sum_sq', 'f8'), ('mean', 'f8'), ('std_dev', 'f8')]) @@ -248,42 +248,42 @@ class StatePoint(object): @property def k_cmfd(self): if self.cmfd_on: - return self._f['cmfd/k_cmfd'].value + return self._f['cmfd/k_cmfd'][()] else: return None @property def k_generation(self): if self.run_mode == 'eigenvalue': - return self._f['k_generation'].value + return self._f['k_generation'][()] else: return None @property def k_combined(self): if self.run_mode == 'eigenvalue': - return ufloat(*self._f['k_combined'].value) + return ufloat(*self._f['k_combined'][()]) else: return None @property def k_col_abs(self): if self.run_mode == 'eigenvalue': - return self._f['k_col_abs'].value + return self._f['k_col_abs'][()] else: return None @property def k_col_tra(self): if self.run_mode == 'eigenvalue': - return self._f['k_col_tra'].value + return self._f['k_col_tra'][()] else: return None @property def k_abs_tra(self): if self.run_mode == 'eigenvalue': - return self._f['k_abs_tra'].value + return self._f['k_abs_tra'][()] else: return None @@ -303,22 +303,22 @@ class StatePoint(object): @property def n_batches(self): - return self._f['n_batches'].value + return self._f['n_batches'][()] @property def n_inactive(self): if self.run_mode == 'eigenvalue': - return self._f['n_inactive'].value + return self._f['n_inactive'][()] else: return None @property def n_particles(self): - return self._f['n_particles'].value + return self._f['n_particles'][()] @property def n_realizations(self): - return self._f['n_realizations'].value + return self._f['n_realizations'][()] @property def path(self): @@ -330,20 +330,20 @@ class StatePoint(object): @property def run_mode(self): - return self._f['run_mode'].value.decode() + return self._f['run_mode'][()].decode() @property def runtime(self): - return {name: dataset.value + return {name: dataset[()] for name, dataset in self._f['runtime'].items()} @property def seed(self): - return self._f['seed'].value + return self._f['seed'][()] @property def source(self): - return self._f['source_bank'].value if self.source_present else None + return self._f['source_bank'][()] if self.source_present else None @property def source_present(self): @@ -376,24 +376,24 @@ class StatePoint(object): group = tallies_group['tally {}'.format(tally_id)] # Read the number of realizations - n_realizations = group['n_realizations'].value + n_realizations = group['n_realizations'][()] # Create Tally object and assign basic properties tally = openmc.Tally(tally_id) tally._sp_filename = self._f.filename - tally.name = group['name'].value.decode() if 'name' in group else '' - tally.estimator = group['estimator'].value.decode() + tally.name = group['name'][()].decode() if 'name' in group else '' + tally.estimator = group['estimator'][()].decode() tally.num_realizations = n_realizations # Read derivative information. if 'derivative' in group: - deriv_id = group['derivative'].value + deriv_id = group['derivative'][()] tally.derivative = self.tally_derivatives[deriv_id] # Read all filters - n_filters = group['n_filters'].value + n_filters = group['n_filters'][()] if n_filters > 0: - filter_ids = group['filters'].value + filter_ids = group['filters'][()] filters_group = self._f['tallies/filters'] for filter_id in filter_ids: filter_group = filters_group['filter {}'.format( @@ -403,15 +403,15 @@ class StatePoint(object): tally.filters.append(new_filter) # Read nuclide bins - nuclide_names = group['nuclides'].value + nuclide_names = group['nuclides'][()] # Add all nuclides to the Tally for name in nuclide_names: nuclide = openmc.Nuclide(name.decode().strip()) tally.nuclides.append(nuclide) - scores = group['score_bins'].value - n_score_bins = group['n_score_bins'].value + scores = group['score_bins'][()] + n_score_bins = group['n_score_bins'][()] # Add the scores to the Tally for j, score in enumerate(scores): @@ -445,14 +445,14 @@ class StatePoint(object): group = self._f['tallies/derivatives/derivative {}' .format(d_id)] deriv = openmc.TallyDerivative(derivative_id=d_id) - deriv.variable = group['independent variable'].value.decode() + deriv.variable = group['independent variable'][()].decode() if deriv.variable == 'density': - deriv.material = group['material'].value + deriv.material = group['material'][()] elif deriv.variable == 'nuclide_density': - deriv.material = group['material'].value - deriv.nuclide = group['nuclide'].value.decode() + deriv.material = group['material'][()] + deriv.nuclide = group['nuclide'][()].decode() elif deriv.variable == 'temperature': - deriv.material = group['material'].value + deriv.material = group['material'][()] self._derivs[d_id] = deriv self._derivs_read = True diff --git a/openmc/summary.py b/openmc/summary.py index 866dd8288..266c6b27a 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -85,14 +85,14 @@ class Summary(object): def _read_nuclides(self): if 'nuclides/names' in self._f: - names = self._f['nuclides/names'].value - awrs = self._f['nuclides/awrs'].value + names = self._f['nuclides/names'][()] + awrs = self._f['nuclides/awrs'][()] for name, awr in zip(names, awrs): self._nuclides[name.decode()] = awr def _read_macroscopics(self): if 'macroscopics/names' in self._f: - names = self._f['macroscopics/names'].value + names = self._f['macroscopics/names'][()] for name in names: self._macroscopics = name.decode() @@ -130,17 +130,17 @@ class Summary(object): for key, group in self._f['geometry/cells'].items(): cell_id = int(key.lstrip('cell ')) - name = group['name'].value.decode() if 'name' in group else '' - fill_type = group['fill_type'].value.decode() + name = group['name'][()].decode() if 'name' in group else '' + fill_type = group['fill_type'][()].decode() if fill_type == 'material': - fill = group['material'].value + fill = group['material'][()] elif fill_type == 'universe': - fill = group['fill'].value + fill = group['fill'][()] else: - fill = group['lattice'].value + fill = group['lattice'][()] - region = group['region'].value.decode() if 'region' in group else '' + region = group['region'][()].decode() if 'region' in group else '' # Create this Cell cell = openmc.Cell(cell_id=cell_id, name=name) diff --git a/openmc/surface.py b/openmc/surface.py index 0f10e7f48..dc251485d 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -269,9 +269,9 @@ class Surface(IDManagerMixin, metaclass=ABCMeta): """ surface_id = int(group.name.split('/')[-1].lstrip('surface ')) - name = group['name'].value.decode() if 'name' in group else '' - surf_type = group['type'].value.decode() - bc = group['boundary_type'].value.decode() + name = group['name'][()].decode() if 'name' in group else '' + surf_type = group['type'][()].decode() + bc = group['boundary_type'][()].decode() coeffs = group['coefficients'][...] # Create the Surface based on its type diff --git a/openmc/tallies.py b/openmc/tallies.py index 291090b19..d3786d21c 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -217,7 +217,7 @@ class Tally(IDManagerMixin): f = h5py.File(self._sp_filename, 'r') # Extract Tally data from the file - data = f['tallies/tally {0}/results'.format(self.id)].value + data = f['tallies/tally {0}/results'.format(self.id)][()] sum = data[:, :, 0] sum_sq = data[:, :, 1] diff --git a/openmc/universe.py b/openmc/universe.py index 044da12e3..ee038ebef 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -124,7 +124,7 @@ class Universe(IDManagerMixin): """ universe_id = int(group.name.split('/')[-1].lstrip('universe ')) - cell_ids = group['cells'].value + cell_ids = group['cells'][()] # Create this Universe universe = cls(universe_id) diff --git a/openmc/volume.py b/openmc/volume.py index af7c356ae..7ac4fdd0c 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -211,9 +211,9 @@ class VolumeCalculation(object): domain_id = int(obj_name[7:]) ids.append(domain_id) group = f[obj_name] - volume = ufloat(*group['volume'].value) - nucnames = group['nuclides'].value - atoms_ = group['atoms'].value + volume = ufloat(*group['volume'][()]) + nucnames = group['nuclides'][()] + atoms_ = group['atoms'][()] atom_dict = OrderedDict() for name_i, atoms_i in zip(nucnames, atoms_): From 0f248381d15ee807f496de6708f1cecb4dfb9205 Mon Sep 17 00:00:00 2001 From: liangjg Date: Wed, 27 Mar 2019 12:37:02 -0400 Subject: [PATCH 130/165] updated photon data test to check cross sections and data by from_hdf5() --- openmc/data/function.py | 4 ++-- openmc/data/photon.py | 4 ++-- openmc/data/thermal.py | 4 ++-- tests/unit_tests/test_data_photon.py | 16 +++++++++++++++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/openmc/data/function.py b/openmc/data/function.py index 582d4ee6f..f167a3c23 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -349,8 +349,8 @@ class Tabulated1D(Function1D): raise ValueError("Expected an HDF5 attribute 'type' equal to '" + cls.__name__ + "'") - x = dataset.value[0, :] - y = dataset.value[1, :] + x = dataset[0, :] + y = dataset[1, :] breakpoints = dataset.attrs['breakpoints'] interpolation = dataset.attrs['interpolation'] return cls(x, y, breakpoints, interpolation) diff --git a/openmc/data/photon.py b/openmc/data/photon.py index db984c769..e038ca05d 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -376,8 +376,8 @@ class AtomicRelaxation(EqualityMixin): # Write transition data with replacements if shell in self.transitions: df = self.transitions[shell].replace( - _SUBSHELLS, np.arange(float(len(_SUBSHELLS)))) - group.create_dataset('transitions') + _SUBSHELLS, range(len(_SUBSHELLS))) + group.create_dataset('transitions', data=df.values.astype(float)) class IncidentPhoton(EqualityMixin): diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index ef1fa3b02..27ed7aa29 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -200,8 +200,8 @@ class CoherentElastic(EqualityMixin): Coherent elastic scattering cross section """ - bragg_edges = dataset.value[0, :] - factors = dataset.value[1, :] + bragg_edges = dataset[0, :] + factors = dataset[1, :] return cls(bragg_edges, factors) diff --git a/tests/unit_tests/test_data_photon.py b/tests/unit_tests/test_data_photon.py index f0a107a05..9bbbcc8ec 100644 --- a/tests/unit_tests/test_data_photon.py +++ b/tests/unit_tests/test_data_photon.py @@ -129,6 +129,20 @@ def test_export_to_hdf5(tmpdir, element): filename = str(tmpdir.join('tmp.h5')) element.export_to_hdf5(filename) assert os.path.exists(filename) - # Read in data from hdf5 and export again + # Read in data from hdf5 element2 = openmc.data.IncidentPhoton.from_hdf5(filename) + # Check for some cross section and datasets of element and element2 + energy = np.logspace(np.log10(1.0), np.log10(1.0e10), num=100) + for mt in (502, 504, 515, 517, 522, 541, 570): + xs = element[mt].xs(energy) + xs2 = element2[mt].xs(energy) + assert np.allclose(xs, xs2) + assert element[502].scattering_factor == element2[502].scattering_factor + assert element.atomic_relaxation.transitions['O3'].equals( + element2.atomic_relaxation.transitions['O3']) + assert (element.compton_profiles['binding_energy'] == + element2.compton_profiles['binding_energy']).all() + assert (element.bremsstrahlung['electron_energy'] == + element2.bremsstrahlung['electron_energy']).all() + # Export to hdf5 again element2.export_to_hdf5(filename, 'w') From 6bcec6fa19e0707190f3d11cf5c9b979ddad2734 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 27 Mar 2019 21:24:46 -0400 Subject: [PATCH 131/165] Remove operator tokens from simple cell RPN --- src/cell.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index c7b92c829..45817de42 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -336,6 +336,16 @@ CSGCell::CSGCell(pugi::xml_node cell_node) } } + // If this cell is simple, remove all the superfluous operator tokens. + if (simple_) { + std::vector stack; + for (auto token : rpn_) { + if (token < OP_UNION) stack.push_back(token); + } + rpn_ = std::vector(stack.rbegin(), stack.rend()); + rpn_.shrink_to_fit(); + } + // Read the translation vector. if (check_for_node(cell_node, "translation")) { if (fill_ == C_NONE) { @@ -522,19 +532,17 @@ bool CSGCell::contains_simple(Position r, Direction u, int32_t on_surface) const { for (int32_t token : rpn_) { - if (token < OP_UNION) { - // If the token is not an operator, evaluate the sense of particle with - // respect to the surface and see if the token matches the sense. If the - // particle's surface attribute is set and matches the token, that - // overrides the determination based on sense(). - if (token == on_surface) { - } else if (-token == on_surface) { - return false; - } else { - // Note the off-by-one indexing - bool sense = model::surfaces[abs(token)-1]->sense(r, u); - if (sense != (token > 0)) {return false;} - } + // Assume that no tokens are operators. Evaluate the sense of particle with + // respect to the surface and see if the token matches the sense. If the + // particle's surface attribute is set and matches the token, that + // overrides the determination based on sense(). + if (token == on_surface) { + } else if (-token == on_surface) { + return false; + } else { + // Note the off-by-one indexing + bool sense = model::surfaces[abs(token)-1]->sense(r, u); + if (sense != (token > 0)) {return false;} } } return true; From f6ace6ece7d0b206040ee2ed7fa726ca8e43a632 Mon Sep 17 00:00:00 2001 From: liangjg Date: Thu, 28 Mar 2019 17:03:06 -0400 Subject: [PATCH 132/165] fix photon analog tally: do not zero out p->wgt_last_ before tallying --- src/physics.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/physics.cpp b/src/physics.cpp index 1cfd31658..258cea924 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -56,7 +56,6 @@ void collision(Particle* p) if (p->E_ < settings::energy_cutoff[type]) { p->alive_ = false; p->wgt_ = 0.0; - p->wgt_last_ = 0.0; } // Display information about collision From e36f67c5bb3ea4705ce3eb42f1178f97802fb801 Mon Sep 17 00:00:00 2001 From: liangjg Date: Thu, 28 Mar 2019 21:07:44 -0400 Subject: [PATCH 133/165] fix particle tally filter bug: the index is stored wrong --- src/tallies/tally.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 682db3540..1cbd53424 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -718,7 +718,7 @@ void read_tallies_xml() const auto& f = model::tally_filters[i_filter].get(); auto pf = dynamic_cast(f); - if (pf) particle_filter_index = j; + if (pf) particle_filter_index = i_filter; // Change the tally estimator if a filter demands it std::string filt_type = f->type(); From a8e942b7405b4da3d8e1fe7670a17a9628ea189e Mon Sep 17 00:00:00 2001 From: liangjg Date: Thu, 28 Mar 2019 20:00:27 -0400 Subject: [PATCH 134/165] update photon tally test to cover analog estimator --- .../photon_production/inputs_true.dat | 5 +++++ tests/regression_tests/photon_production/test.py | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/regression_tests/photon_production/inputs_true.dat b/tests/regression_tests/photon_production/inputs_true.dat index 427078c88..bfee6a712 100644 --- a/tests/regression_tests/photon_production/inputs_true.dat +++ b/tests/regression_tests/photon_production/inputs_true.dat @@ -47,4 +47,9 @@ 1 2 current + + 2 + total + analog + diff --git a/tests/regression_tests/photon_production/test.py b/tests/regression_tests/photon_production/test.py index ac39b065c..4e5127109 100644 --- a/tests/regression_tests/photon_production/test.py +++ b/tests/regression_tests/photon_production/test.py @@ -48,10 +48,14 @@ class SourceTestHarness(PyAPITestHarness): surface_filter = openmc.SurfaceFilter(cyl) particle_filter = openmc.ParticleFilter('photon') - tally = openmc.Tally() - tally.filters = [surface_filter, particle_filter] - tally.scores = ['current'] - tallies = openmc.Tallies([tally]) + current_tally = openmc.Tally() + current_tally.filters = [surface_filter, particle_filter] + current_tally.scores = ['current'] + total_tally = openmc.Tally() + total_tally.filters = [particle_filter] + total_tally.scores = ['total'] + total_tally.estimator = 'analog' + tallies = openmc.Tallies([current_tally, total_tally]) tallies.export_to_xml() def _get_results(self): From c24a8b2f18b233d46570285f7e21e09a535a4409 Mon Sep 17 00:00:00 2001 From: liangjg Date: Thu, 28 Mar 2019 21:54:50 -0400 Subject: [PATCH 135/165] add tracklength and collision tally for comparison --- .../photon_production/inputs_true.dat | 10 ++++++ .../photon_production/test.py | 31 +++++++++++++------ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/tests/regression_tests/photon_production/inputs_true.dat b/tests/regression_tests/photon_production/inputs_true.dat index bfee6a712..f2c52b445 100644 --- a/tests/regression_tests/photon_production/inputs_true.dat +++ b/tests/regression_tests/photon_production/inputs_true.dat @@ -48,6 +48,16 @@ current + 2 + total + tracklength + + + 2 + total + collision + + 2 total analog diff --git a/tests/regression_tests/photon_production/test.py b/tests/regression_tests/photon_production/test.py index 4e5127109..55fcabea5 100644 --- a/tests/regression_tests/photon_production/test.py +++ b/tests/regression_tests/photon_production/test.py @@ -51,21 +51,34 @@ class SourceTestHarness(PyAPITestHarness): current_tally = openmc.Tally() current_tally.filters = [surface_filter, particle_filter] current_tally.scores = ['current'] - total_tally = openmc.Tally() - total_tally.filters = [particle_filter] - total_tally.scores = ['total'] - total_tally.estimator = 'analog' - tallies = openmc.Tallies([current_tally, total_tally]) + total_tally_tracklength = openmc.Tally() + total_tally_tracklength.filters = [particle_filter] + total_tally_tracklength.scores = ['total'] + total_tally_tracklength.estimator = 'tracklength' + total_tally_collision = openmc.Tally() + total_tally_collision.filters = [particle_filter] + total_tally_collision.scores = ['total'] + total_tally_collision.estimator = 'collision' + total_tally_analog = openmc.Tally() + total_tally_analog.filters = [particle_filter] + total_tally_analog.scores = ['total'] + total_tally_analog.estimator = 'analog' + tallies = openmc.Tallies([current_tally, total_tally_tracklength, + total_tally_collision, total_tally_analog]) tallies.export_to_xml() def _get_results(self): with openmc.StatePoint(self._sp_name) as sp: outstr = '' - t = sp.get_tally() - outstr += 'tally {}:\n'.format(t.id) - outstr += 'sum = {:12.6E}\n'.format(t.sum[0, 0, 0]) - outstr += 'sum_sq = {:12.6E}\n'.format(t.sum_sq[0, 0, 0]) + for i, tally_ind in enumerate(sp.tallies): + tally = sp.tallies[tally_ind] + results = np.zeros((tally.sum.size * 2, )) + results[0::2] = tally.sum.ravel() + results[1::2] = tally.sum_sq.ravel() + results = ['{0:12.6E}'.format(x) for x in results] + outstr += 'tally {}:\n'.format(i + 1) + outstr += '\n'.join(results) + '\n' return outstr From ac048527c81c742e79bd709960174e4d394daacd Mon Sep 17 00:00:00 2001 From: liangjg Date: Thu, 28 Mar 2019 22:15:09 -0400 Subject: [PATCH 136/165] change cylinder size to make sure collision occurs --- .../photon_production/inputs_true.dat | 2 +- .../photon_production/results_true.dat | 13 +++++++++++-- tests/regression_tests/photon_production/test.py | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/regression_tests/photon_production/inputs_true.dat b/tests/regression_tests/photon_production/inputs_true.dat index f2c52b445..1d43c8913 100644 --- a/tests/regression_tests/photon_production/inputs_true.dat +++ b/tests/regression_tests/photon_production/inputs_true.dat @@ -3,7 +3,7 @@ - + diff --git a/tests/regression_tests/photon_production/results_true.dat b/tests/regression_tests/photon_production/results_true.dat index 3d9cf68ed..7df7e5dbc 100644 --- a/tests/regression_tests/photon_production/results_true.dat +++ b/tests/regression_tests/photon_production/results_true.dat @@ -1,3 +1,12 @@ tally 1: -sum = 7.938000E-01 -sum_sq = 6.301184E-01 +9.403000E-01 +8.841641E-01 +tally 2: +8.281718E-01 +6.858685E-01 +tally 3: +8.242000E-01 +6.793056E-01 +tally 4: +8.242000E-01 +6.793056E-01 diff --git a/tests/regression_tests/photon_production/test.py b/tests/regression_tests/photon_production/test.py index 55fcabea5..47215fff3 100644 --- a/tests/regression_tests/photon_production/test.py +++ b/tests/regression_tests/photon_production/test.py @@ -14,7 +14,7 @@ class SourceTestHarness(PyAPITestHarness): materials = openmc.Materials([mat]) materials.export_to_xml() - cyl = openmc.XCylinder(boundary_type='vacuum', r=1.0e-6) + cyl = openmc.XCylinder(boundary_type='vacuum', r=1.0) x_plane_left = openmc.XPlane(boundary_type='vacuum', x0=-1.0) x_plane_center = openmc.XPlane(boundary_type='transmission', x0=1.0) x_plane_right = openmc.XPlane(boundary_type='vacuum', x0=1.0e9) From 2dc02c57743ad1ec49868b73e2cc7d4e139b8cf1 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 31 Mar 2019 07:38:18 -0400 Subject: [PATCH 137/165] Remove unneeded rpn tokens in-place --- src/cell.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 45817de42..1baf7b44e 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -325,7 +325,6 @@ CSGCell::CSGCell(pugi::xml_node cell_node) // Convert the infix region spec to RPN. rpn_ = generate_rpn(id_, region_); - rpn_.shrink_to_fit(); // Check if this is a simple cell. simple_ = true; @@ -338,13 +337,18 @@ CSGCell::CSGCell(pugi::xml_node cell_node) // If this cell is simple, remove all the superfluous operator tokens. if (simple_) { - std::vector stack; - for (auto token : rpn_) { - if (token < OP_UNION) stack.push_back(token); + size_t i0 = 0; + size_t i1 = 0; + while (i1 < rpn_.size()) { + if (rpn_[i1] < OP_UNION) { + rpn_[i0] = rpn_[i1]; + ++i0; + } + ++i1; } - rpn_ = std::vector(stack.rbegin(), stack.rend()); - rpn_.shrink_to_fit(); + rpn_.resize(i0); } + rpn_.shrink_to_fit(); // Read the translation vector. if (check_for_node(cell_node, "translation")) { From 4b76c28a3bfb587b49a1233e66ef770844fb16d2 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 31 Mar 2019 10:55:26 -0400 Subject: [PATCH 138/165] Optimize find_cell on universes with many z-planes --- include/openmc/cell.h | 39 ++++++++++++++++++ include/openmc/geometry_aux.h | 5 +++ include/openmc/surface.h | 2 +- src/cell.cpp | 78 +++++++++++++++++++++++++++++++++++ src/geometry.cpp | 14 ++++++- src/geometry_aux.cpp | 29 +++++++++++++ 6 files changed, 165 insertions(+), 2 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index d4c220635..355e23ff3 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -43,6 +43,7 @@ constexpr int32_t OP_UNION {std::numeric_limits::max() - 4}; class Cell; class Universe; +class UniversePartitioner; namespace model { extern std::vector> cells; @@ -65,6 +66,8 @@ public: //! \brief Write universe information to an HDF5 group. //! \param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; + + std::unique_ptr partitioner_; }; //============================================================================== @@ -193,6 +196,42 @@ public: }; #endif +//============================================================================== + +class UniversePartitioner +{ +public: + UniversePartitioner(const Universe& univ); + + const std::vector& get_cells(Position r, Direction u) const + {return get_cells(r, u, 0, surfs_.size()-1, (surfs_.size()-1)/2);} + + const std::vector& get_cells(Position r, Direction u, + int left, int right, int middle) const + { + auto i_surf = surfs_[middle]; + const auto& surf = *model::surfaces[i_surf]; + if (surf.sense(r, u)) { + int right_leaf = right - (right - middle) / 2; + if (right_leaf != middle) { + return get_cells(r, u, middle+1, right, right_leaf); + } else { + return cells_[middle+1]; + } + } else { + int left_leaf = left + (middle - left) / 2; + if (left_leaf != middle) { + return get_cells(r, u, left, middle-1, left_leaf); + } else { + return cells_[middle]; + } + } + } + + std::vector> cells_; + std::vector surfs_; +}; + //============================================================================== // Non-member functions //============================================================================== diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index ffcdcf885..8236af2f7 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -10,6 +10,11 @@ namespace openmc { +extern int search_numerator1; +extern int search_denominator1; +extern int search_numerator2; +extern int search_denominator2; + void read_geometry_xml(); //============================================================================== diff --git a/include/openmc/surface.h b/include/openmc/surface.h index bebff35ee..c862e14c9 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -220,8 +220,8 @@ public: class SurfaceZPlane : public PeriodicSurface { - double z0_; public: + double z0_; explicit SurfaceZPlane(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; diff --git a/src/cell.cpp b/src/cell.cpp index c7b92c829..db1190813 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -635,6 +635,84 @@ void DAGCell::to_hdf5(hid_t group_id) const { return; } #endif +//============================================================================== +//============================================================================== + +UniversePartitioner::UniversePartitioner(const Universe& univ) +{ + std::unordered_set surf_set; + for (auto i_cell : univ.cells_) { + for (auto token : model::cells[i_cell]->rpn_) { + if (token < OP_UNION) { + auto i_surf = std::abs(token) - 1; + const auto* surf = model::surfaces[i_surf].get(); + if (const auto* zplane = dynamic_cast(surf)) { + if (surf_set.find(i_surf) == surf_set.end()) { + surf_set.insert(i_surf); + surfs_.push_back(i_surf); + } + } + } + } + } + + struct { + bool operator()(int32_t i_surf, int32_t j_surf) const + { + const auto* surf = model::surfaces[i_surf].get(); + const auto* zplane = dynamic_cast(surf); + double zi = zplane->z0_; + surf = model::surfaces[j_surf].get(); + zplane = dynamic_cast(surf); + double zj = zplane->z0_; + return zi < zj; + } + } compare_surfs; + std::sort(surfs_.begin(), surfs_.end(), compare_surfs); + + cells_.resize(surfs_.size() + 1); + + for (auto i_cell : univ.cells_) { + int32_t min_token = 0, max_token = 0; + double min_z, max_z; + for (auto token : model::cells[i_cell]->rpn_) { + if (token < OP_UNION) { + const auto* surf = model::surfaces[std::abs(token) - 1].get(); + if (const auto* zplane = dynamic_cast(surf)) { + if (min_token == 0 || zplane->z0_ < min_z) { + min_token = token; + min_z = zplane->z0_; + } + if (max_token == 0 || zplane->z0_ > max_z) { + max_token = token; + max_z = zplane->z0_; + } + } + } + } + + if (min_token == 0) { + min_token = -(surfs_.front() + 1); + max_token = surfs_.back() + 1; + } + + bool in_partition = min_token < 0; + + for (auto i = 0; i < surfs_.size(); ++i) { + if (in_partition) { + cells_[i].push_back(i_cell); + + if (max_token == -(surfs_[i] + 1)) + in_partition = false; + } else { + in_partition = min_token == surfs_[i] + 1; + } + } + if (in_partition) + cells_.back().push_back(i_cell); + } +} + //============================================================================== // Non-method functions //============================================================================== diff --git a/src/geometry.cpp b/src/geometry.cpp index 8791dd957..5e6ea34ca 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -11,6 +11,8 @@ #include "openmc/simulation.h" #include "openmc/surface.h" +#include "openmc/geometry_aux.h" + namespace openmc { @@ -69,6 +71,7 @@ find_cell_inner(Particle* p, const NeighborList* neighbor_list) bool found = false; int32_t i_cell; if (neighbor_list) { + ++search_numerator1; for (auto it = neighbor_list->cbegin(); it != neighbor_list->cend(); ++it) { i_cell = *it; @@ -80,6 +83,7 @@ find_cell_inner(Particle* p, const NeighborList* neighbor_list) Position r {p->r_local()}; Direction u {p->u_local()}; auto surf = p->surface_; + ++search_denominator1; if (model::cells[i_cell]->contains(r, u, surf)) { p->coord_[p->n_coord_-1].cell = i_cell; found = true; @@ -88,8 +92,15 @@ find_cell_inner(Particle* p, const NeighborList* neighbor_list) } } else { + ++search_numerator2; int i_universe = p->coord_[p->n_coord_-1].universe; - const auto& cells {model::universes[i_universe]->cells_}; + //const auto& cells {model::universes[i_universe]->cells_}; + const auto& univ {*model::universes[i_universe]}; + const auto& cells { + !univ.partitioner_ ? + model::universes[i_universe]->cells_ + : univ.partitioner_->get_cells(p->r_local(), p->u_local()) + }; for (auto it = cells.cbegin(); it != cells.cend(); it++) { i_cell = *it; @@ -101,6 +112,7 @@ find_cell_inner(Particle* p, const NeighborList* neighbor_list) Position r {p->r_local()}; Direction u {p->u_local()}; auto surf = p->surface_; + ++search_denominator2; if (model::cells[i_cell]->contains(r, u, surf)) { p->coord_[p->n_coord_-1].cell = i_cell; found = true; diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index e19b5f946..1108bca29 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -23,6 +23,11 @@ namespace openmc { +int search_denominator1 {0}; +int search_numerator1 {0}; +int search_denominator2 {0}; +int search_numerator2 {0}; + void read_geometry_xml() { #ifdef DAGMC @@ -219,6 +224,28 @@ void finalize_geometry(std::vector>& nuc_temps, // Determine number of nested coordinate levels in the geometry model::n_coord_levels = maximum_levels(model::root_universe); + + for (const auto& univ : model::universes) { + if (univ->cells_.size() > 10) { + std::unordered_set surf_inds; + for (auto i_cell : univ->cells_) { + for (auto token : model::cells[i_cell]->rpn_) { + if (token < OP_UNION) surf_inds.insert(std::abs(token) - 1); + } + } + int n_zplanes = 0; + for (auto i_surf : surf_inds) { + if (dynamic_cast(model::surfaces[i_surf].get())) { + ++n_zplanes; + if (n_zplanes > 5) { + univ->partitioner_ = std::make_unique( + UniversePartitioner(*univ)); + break; + } + } + } + } + } } //============================================================================== @@ -519,6 +546,8 @@ maximum_levels(int32_t univ) void free_memory_geometry() { + std::cout << "SEARCH EFFICIENCY = " << static_cast(search_numerator1) / search_denominator1 << "\n"; + std::cout << "SEARCH EFFICIENCY = " << static_cast(search_numerator2) / search_denominator2 << "\n"; model::cells.clear(); model::cell_map.clear(); From 5d5b82f0ae99d8199977dc5fc5dd2018f0edda30 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 31 Mar 2019 12:29:18 -0400 Subject: [PATCH 139/165] Cleanup UniversePartitioner code --- include/openmc/cell.h | 41 ++++++++++++++++++---- include/openmc/geometry_aux.h | 5 --- include/openmc/surface.h | 38 +++++++++++++------- src/cell.cpp | 29 ++++++++++------ src/geometry.cpp | 11 ++---- src/geometry_aux.cpp | 65 +++++++++++++++++++---------------- 6 files changed, 117 insertions(+), 72 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 355e23ff3..2cd0bd3fa 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -196,40 +196,69 @@ public: }; #endif +//============================================================================== +//! Speeds up geometry searches by grouping cells in a search tree. +// +//! Currently this object only works with universes that are divided up by a +//! bunch of z-planes. It could be generalized to other planes, cylinders, +//! and spheres. //============================================================================== class UniversePartitioner { public: - UniversePartitioner(const Universe& univ); + explicit UniversePartitioner(const Universe& univ); + //! Return the list of cells that could contain the given coordinates. const std::vector& get_cells(Position r, Direction u) const {return get_cells(r, u, 0, surfs_.size()-1, (surfs_.size()-1)/2);} - const std::vector& get_cells(Position r, Direction u, - int left, int right, int middle) const +private: + //! Perform a binary search for the given coordinates. + // + //! \param left The lower search bound of the `surfs_` vector + //! \param right The upper search bound of the `surfs_` vector + //! \param middle The index of the `Surface` to test against + const std::vector& + get_cells(Position r, Direction u, int left, int right, int middle) const { + // Check the sense of the coordinates for the current surface. auto i_surf = surfs_[middle]; const auto& surf = *model::surfaces[i_surf]; if (surf.sense(r, u)) { + // The coordinates lie in the positive halfspace. Recurse if there are + // more surfaces to check. Otherwise, return the cells on the positive + // side of this surface. int right_leaf = right - (right - middle) / 2; if (right_leaf != middle) { return get_cells(r, u, middle+1, right, right_leaf); } else { - return cells_[middle+1]; + return partitions_[middle+1]; } } else { + // The coordinates lie in the negative halfspace. Recurse if there are + // more surfaces to check. Otherwise, return the cells on the negative + // side of this surface. int left_leaf = left + (middle - left) / 2; if (left_leaf != middle) { return get_cells(r, u, left, middle-1, left_leaf); } else { - return cells_[middle]; + return partitions_[middle]; } } } - std::vector> cells_; + //! A sorted vector of indices to surfaces that partition the universe std::vector surfs_; + + //! Vectors listing the indices of the cells that lie within each partition + // + //! There are n+1 partitions with n surfaces. `partitions_.front()` gives the + //! cells that lie on the negative side of `surfs_.front()`. + //! `partitions_.back()` gives the cells that lie on the positive side of + //! `surfs_.back()`. Otherwise, `partitions_[i]` gives cells sandwiched + //! between `surfs_[i-1]` and `surfs_[i]`. + std::vector> partitions_; }; //============================================================================== diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 8236af2f7..ffcdcf885 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -10,11 +10,6 @@ namespace openmc { -extern int search_numerator1; -extern int search_denominator1; -extern int search_numerator2; -extern int search_denominator2; - void read_geometry_xml(); //============================================================================== diff --git a/include/openmc/surface.h b/include/openmc/surface.h index c862e14c9..4db397a59 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -180,7 +180,6 @@ public: class SurfaceXPlane : public PeriodicSurface { - double x0_; public: explicit SurfaceXPlane(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -190,6 +189,8 @@ public: bool periodic_translate(const PeriodicSurface* other, Position& r, Direction& u) const; BoundingBox bounding_box() const; + + double x0_; }; //============================================================================== @@ -200,7 +201,6 @@ public: class SurfaceYPlane : public PeriodicSurface { - double y0_; public: explicit SurfaceYPlane(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -210,6 +210,8 @@ public: bool periodic_translate(const PeriodicSurface* other, Position& r, Direction& u) const; BoundingBox bounding_box() const; + + double y0_; }; //============================================================================== @@ -221,7 +223,6 @@ public: class SurfaceZPlane : public PeriodicSurface { public: - double z0_; explicit SurfaceZPlane(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; @@ -230,6 +231,8 @@ public: bool periodic_translate(const PeriodicSurface* other, Position& r, Direction& u) const; BoundingBox bounding_box() const; + + double z0_; }; //============================================================================== @@ -240,7 +243,6 @@ public: class SurfacePlane : public PeriodicSurface { - double A_, B_, C_, D_; public: explicit SurfacePlane(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -250,6 +252,8 @@ public: bool periodic_translate(const PeriodicSurface* other, Position& r, Direction& u) const; BoundingBox bounding_box() const; + + double A_, B_, C_, D_; }; //============================================================================== @@ -261,13 +265,14 @@ public: class SurfaceXCylinder : public CSGSurface { - double y0_, z0_, radius_; public: explicit SurfaceXCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; + + double y0_, z0_, radius_; }; //============================================================================== @@ -279,13 +284,14 @@ public: class SurfaceYCylinder : public CSGSurface { - double x0_, z0_, radius_; public: explicit SurfaceYCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; + + double x0_, z0_, radius_; }; //============================================================================== @@ -297,13 +303,14 @@ public: class SurfaceZCylinder : public CSGSurface { - double x0_, y0_, radius_; public: explicit SurfaceZCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; + + double x0_, y0_, radius_; }; //============================================================================== @@ -315,13 +322,14 @@ public: class SurfaceSphere : public CSGSurface { - double x0_, y0_, z0_, radius_; public: explicit SurfaceSphere(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; + + double x0_, y0_, z0_, radius_; }; //============================================================================== @@ -333,13 +341,14 @@ public: class SurfaceXCone : public CSGSurface { - double x0_, y0_, z0_, radius_sq_; public: explicit SurfaceXCone(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; + + double x0_, y0_, z0_, radius_sq_; }; //============================================================================== @@ -351,13 +360,14 @@ public: class SurfaceYCone : public CSGSurface { - double x0_, y0_, z0_, radius_sq_; public: explicit SurfaceYCone(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; + + double x0_, y0_, z0_, radius_sq_; }; //============================================================================== @@ -369,13 +379,14 @@ public: class SurfaceZCone : public CSGSurface { - double x0_, y0_, z0_, radius_sq_; public: explicit SurfaceZCone(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; + + double x0_, y0_, z0_, radius_sq_; }; //============================================================================== @@ -386,14 +397,15 @@ public: class SurfaceQuadric : public CSGSurface { - // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 - double A_, B_, C_, D_, E_, F_, G_, H_, J_, K_; public: explicit SurfaceQuadric(pugi::xml_node surf_node); double evaluate(Position r) const; double distance(Position r, Direction u, bool coincident) const; Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; + + // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 + double A_, B_, C_, D_, E_, F_, G_, H_, J_, K_; }; //============================================================================== diff --git a/src/cell.cpp b/src/cell.cpp index db1190813..5e803c4cd 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -636,10 +636,13 @@ void DAGCell::to_hdf5(hid_t group_id) const { return; } #endif //============================================================================== +// UniversePartitioner implementation //============================================================================== UniversePartitioner::UniversePartitioner(const Universe& univ) { + // Find all of the z-planes in this universe. Add them to the surfs_ member. + // Use surf_set for O(1) searches that ensure surfs_ entries are not repeated. std::unordered_set surf_set; for (auto i_cell : univ.cells_) { for (auto token : model::cells[i_cell]->rpn_) { @@ -656,6 +659,8 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) } } + // Define a functor for comparing z-planes by their location, and use it to + // sort the surfs_ member. struct { bool operator()(int32_t i_surf, int32_t j_surf) const { @@ -670,9 +675,10 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) } compare_surfs; std::sort(surfs_.begin(), surfs_.end(), compare_surfs); - cells_.resize(surfs_.size() + 1); - + // Populate the partition lists. + partitions_.resize(surfs_.size() + 1); for (auto i_cell : univ.cells_) { + // Find the tokens for bounding z-planes. int32_t min_token = 0, max_token = 0; double min_z, max_z; for (auto token : model::cells[i_cell]->rpn_) { @@ -691,25 +697,28 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) } } + // If there are no bounding z-planes, add this cell to all partitions. if (min_token == 0) { - min_token = -(surfs_.front() + 1); - max_token = surfs_.back() + 1; + for (auto& p : partitions_) p.push_back(i_cell); + continue; } + // Iterate over partitions, and add this cell to each appropriate one. + // Since surfs_ is sorted, we know this cell belongs to every partition + // between min_token and max_token. bool in_partition = min_token < 0; - for (auto i = 0; i < surfs_.size(); ++i) { if (in_partition) { - cells_[i].push_back(i_cell); - - if (max_token == -(surfs_[i] + 1)) + partitions_[i].push_back(i_cell); + if (max_token == -(surfs_[i] + 1)) { in_partition = false; + break; + } } else { in_partition = min_token == surfs_[i] + 1; } } - if (in_partition) - cells_.back().push_back(i_cell); + if (in_partition) partitions_.back().push_back(i_cell); } } diff --git a/src/geometry.cpp b/src/geometry.cpp index 5e6ea34ca..bbd7b9d0e 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -11,8 +11,6 @@ #include "openmc/simulation.h" #include "openmc/surface.h" -#include "openmc/geometry_aux.h" - namespace openmc { @@ -71,7 +69,6 @@ find_cell_inner(Particle* p, const NeighborList* neighbor_list) bool found = false; int32_t i_cell; if (neighbor_list) { - ++search_numerator1; for (auto it = neighbor_list->cbegin(); it != neighbor_list->cend(); ++it) { i_cell = *it; @@ -83,7 +80,6 @@ find_cell_inner(Particle* p, const NeighborList* neighbor_list) Position r {p->r_local()}; Direction u {p->u_local()}; auto surf = p->surface_; - ++search_denominator1; if (model::cells[i_cell]->contains(r, u, surf)) { p->coord_[p->n_coord_-1].cell = i_cell; found = true; @@ -92,13 +88,11 @@ find_cell_inner(Particle* p, const NeighborList* neighbor_list) } } else { - ++search_numerator2; int i_universe = p->coord_[p->n_coord_-1].universe; - //const auto& cells {model::universes[i_universe]->cells_}; const auto& univ {*model::universes[i_universe]}; const auto& cells { - !univ.partitioner_ ? - model::universes[i_universe]->cells_ + !univ.partitioner_ + ? model::universes[i_universe]->cells_ : univ.partitioner_->get_cells(p->r_local(), p->u_local()) }; for (auto it = cells.cbegin(); it != cells.cend(); it++) { @@ -112,7 +106,6 @@ find_cell_inner(Particle* p, const NeighborList* neighbor_list) Position r {p->r_local()}; Direction u {p->u_local()}; auto surf = p->surface_; - ++search_denominator2; if (model::cells[i_cell]->contains(r, u, surf)) { p->coord_[p->n_coord_-1].cell = i_cell; found = true; diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 1108bca29..38d3a8a0e 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -23,11 +23,6 @@ namespace openmc { -int search_denominator1 {0}; -int search_numerator1 {0}; -int search_denominator2 {0}; -int search_numerator2 {0}; - void read_geometry_xml() { #ifdef DAGMC @@ -125,6 +120,41 @@ adjust_indices() } } +//============================================================================== +//! Partition some universes with many z-planes for faster find_cell searches. + +void +partition_universes() +{ + // Iterate over universes with more than 10 cells. (Fewer than 10 is likely + // not worth partitioning.) + for (const auto& univ : model::universes) { + if (univ->cells_.size() > 10) { + // Collect the set of surfaces in this universe. + std::unordered_set surf_inds; + for (auto i_cell : univ->cells_) { + for (auto token : model::cells[i_cell]->rpn_) { + if (token < OP_UNION) surf_inds.insert(std::abs(token) - 1); + } + } + + // Partition the universe if there are more than 5 z-planes. (Fewer than + // five is likely no worth it.) + int n_zplanes = 0; + for (auto i_surf : surf_inds) { + if (dynamic_cast(model::surfaces[i_surf].get())) { + ++n_zplanes; + if (n_zplanes > 5) { + univ->partitioner_ = std::make_unique( + UniversePartitioner(*univ)); + break; + } + } + } + } + } +} + //============================================================================== void @@ -215,6 +245,7 @@ void finalize_geometry(std::vector>& nuc_temps, // Perform some final operations to set up the geometry adjust_indices(); count_cell_instances(model::root_universe); + partition_universes(); // Assign temperatures to cells that don't have temperatures already assigned assign_temperatures(); @@ -224,28 +255,6 @@ void finalize_geometry(std::vector>& nuc_temps, // Determine number of nested coordinate levels in the geometry model::n_coord_levels = maximum_levels(model::root_universe); - - for (const auto& univ : model::universes) { - if (univ->cells_.size() > 10) { - std::unordered_set surf_inds; - for (auto i_cell : univ->cells_) { - for (auto token : model::cells[i_cell]->rpn_) { - if (token < OP_UNION) surf_inds.insert(std::abs(token) - 1); - } - } - int n_zplanes = 0; - for (auto i_surf : surf_inds) { - if (dynamic_cast(model::surfaces[i_surf].get())) { - ++n_zplanes; - if (n_zplanes > 5) { - univ->partitioner_ = std::make_unique( - UniversePartitioner(*univ)); - break; - } - } - } - } - } } //============================================================================== @@ -546,8 +555,6 @@ maximum_levels(int32_t univ) void free_memory_geometry() { - std::cout << "SEARCH EFFICIENCY = " << static_cast(search_numerator1) / search_denominator1 << "\n"; - std::cout << "SEARCH EFFICIENCY = " << static_cast(search_numerator2) / search_denominator2 << "\n"; model::cells.clear(); model::cell_map.clear(); From aa62941f9f0c2e337dce4d6909336666c6cc57b1 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 29 Mar 2019 15:19:25 -0500 Subject: [PATCH 140/165] Handle the z-direction the same way as in RectLattice. --- src/lattice.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index eb6282bac..c25f49aa3 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -713,7 +713,6 @@ HexLattice::get_indices(Position r, Direction u) const // The implementation for HexLattice currently doesn't use direction // information. As a result, we move the position slightly forward to // determine what lattice index the particle is most likely to be in. - r += TINY_BIT * u; // Offset the xyz by the lattice center. Position r_o {r.x - center_.x, r.y - center_.y, r.z}; @@ -722,11 +721,16 @@ HexLattice::get_indices(Position r, Direction u) const // Index the z direction. std::array out; if (is_3d_) { - out[2] = std::floor(r_o.z / pitch_[1] + 0.5 * n_axial_); - } else { - out[2] = 0; + double iz_ {r_o.z / pitch_[1] + 0.5 * n_axial_}; + long iz_close {std::lround(iz_)}; + if (std::abs(iz_ - iz_close) < FP_COINCIDENT) { + out[2] = (u.z > 0) ? iz_close : iz_close - 1; + } else { + out[2] = std::floor(iz_); + } } + // Convert coordinates into skewed bases. The (x, alpha) basis is used to // find the index of the global coordinates to within 4 cells. double alpha = r_o.y - r_o.x / std::sqrt(3.0); @@ -738,6 +742,8 @@ HexLattice::get_indices(Position r, Direction u) const out[0] += n_rings_-1; out[1] += n_rings_-1; + r += TINY_BIT * u; + // Calculate the (squared) distance between the particle and the centers of // the four possible cells. Regular hexagonal tiles form a Voronoi // tessellation so the xyz should be in the hexagonal cell that it is closest From 2c3c9b2ccc607ae2c679f8b8a0ecf8ca09748160 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 29 Mar 2019 15:27:31 -0500 Subject: [PATCH 141/165] Moving from array to variables. --- src/lattice.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index c25f49aa3..ed8c564ef 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -710,6 +710,9 @@ const std::array HexLattice::get_indices(Position r, Direction u) const { + // result variables + int ix{}, ia{}, iz{}; + // The implementation for HexLattice currently doesn't use direction // information. As a result, we move the position slightly forward to // determine what lattice index the particle is most likely to be in. @@ -719,14 +722,13 @@ HexLattice::get_indices(Position r, Direction u) const if (is_3d_) {r_o.z -= center_.z;} // Index the z direction. - std::array out; if (is_3d_) { double iz_ {r_o.z / pitch_[1] + 0.5 * n_axial_}; long iz_close {std::lround(iz_)}; if (std::abs(iz_ - iz_close) < FP_COINCIDENT) { - out[2] = (u.z > 0) ? iz_close : iz_close - 1; + iz = (u.z > 0) ? iz_close : iz_close - 1; } else { - out[2] = std::floor(iz_); + iz = std::floor(iz_); } } @@ -734,13 +736,13 @@ HexLattice::get_indices(Position r, Direction u) const // Convert coordinates into skewed bases. The (x, alpha) basis is used to // find the index of the global coordinates to within 4 cells. double alpha = r_o.y - r_o.x / std::sqrt(3.0); - out[0] = std::floor(r_o.x / (0.5*std::sqrt(3.0) * pitch_[0])); - out[1] = std::floor(alpha / pitch_[0]); + ix = std::floor(r_o.x / (0.5*std::sqrt(3.0) * pitch_[0])); + ia = std::floor(alpha / pitch_[0]); // Add offset to indices (the center cell is (i_x, i_alpha) = (0, 0) but // the array is offset so that the indices never go below 0). - out[0] += n_rings_-1; - out[1] += n_rings_-1; + ix += n_rings_-1; + ia += n_rings_-1; r += TINY_BIT * u; @@ -756,7 +758,7 @@ HexLattice::get_indices(Position r, Direction u) const double d_min {INFTY}; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { - const std::array i_xyz {out[0] + j, out[1] + i, 0}; + const std::array i_xyz {ix + j, ia + i, 0}; Position r_t = get_local_position(r, i_xyz); double d = r_t.x*r_t.x + r_t.y*r_t.y; if (d < d_min) { @@ -770,15 +772,15 @@ HexLattice::get_indices(Position r, Direction u) const // Select the minimum squared distance which corresponds to the cell the // coordinates are in. if (k_min == 2) { - ++out[0]; + ++ix; } else if (k_min == 3) { - ++out[1]; + ++ia; } else if (k_min == 4) { - ++out[0]; - ++out[1]; + ++ix; + ++ia; } - return out; + return {ix, ia, iz}; } //============================================================================== From 4f7fafae2782eb404c1fd714bb9e39047a875896 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 29 Mar 2019 17:15:30 -0500 Subject: [PATCH 142/165] Adding dot product check for coincident particles. --- src/lattice.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index ed8c564ef..9257dddca 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -744,7 +744,7 @@ HexLattice::get_indices(Position r, Direction u) const ix += n_rings_-1; ia += n_rings_-1; - r += TINY_BIT * u; + // r += TINY_BIT * u; // Calculate the (squared) distance between the particle and the centers of // the four possible cells. Regular hexagonal tiles form a Voronoi @@ -756,14 +756,21 @@ HexLattice::get_indices(Position r, Direction u) const int k {1}; int k_min {1}; double d_min {INFTY}; + double dp_min {INFTY}; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { const std::array i_xyz {ix + j, ia + i, 0}; Position r_t = get_local_position(r, i_xyz); double d = r_t.x*r_t.x + r_t.y*r_t.y; - if (d < d_min) { + bool coincident = std::abs(d - d_min) < 1.e-08; + if (d < d_min || coincident) { + r_t /= r_t.norm(); + double dp = u.x * r_t.x + u.y * r_t.y; + if (coincident && dp > dp_min) { continue; } + // update values d_min = d; k_min = k; + dp_min = dp; } k++; } From b8d5cfcefb7b94c376f51292bb9bda461b5f3ffb Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 29 Mar 2019 18:40:29 -0500 Subject: [PATCH 143/165] Doing coincidence calc only once. --- src/lattice.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index 9257dddca..2cd678d38 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -732,7 +732,6 @@ HexLattice::get_indices(Position r, Direction u) const } } - // Convert coordinates into skewed bases. The (x, alpha) basis is used to // find the index of the global coordinates to within 4 cells. double alpha = r_o.y - r_o.x / std::sqrt(3.0); @@ -762,9 +761,9 @@ HexLattice::get_indices(Position r, Direction u) const const std::array i_xyz {ix + j, ia + i, 0}; Position r_t = get_local_position(r, i_xyz); double d = r_t.x*r_t.x + r_t.y*r_t.y; - bool coincident = std::abs(d - d_min) < 1.e-08; + bool coincident = std::abs(d - d_min) < FP_COINCIDENT; if (d < d_min || coincident) { - r_t /= r_t.norm(); + r_t /= std::sqrt(d); double dp = u.x * r_t.x + u.y * r_t.y; if (coincident && dp > dp_min) { continue; } // update values From c69d53ee86b0afd0033499e501226f856ccba563 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 30 Mar 2019 09:05:06 -0500 Subject: [PATCH 144/165] fix fix fix to the k increment. --- src/lattice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index 2cd678d38..e5ea20910 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -765,7 +765,7 @@ HexLattice::get_indices(Position r, Direction u) const if (d < d_min || coincident) { r_t /= std::sqrt(d); double dp = u.x * r_t.x + u.y * r_t.y; - if (coincident && dp > dp_min) { continue; } + if (coincident && dp > dp_min) { k++; continue; } // update values d_min = d; k_min = k; From e62dd935a67b0803f0895ab557c084cf80c60cd1 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 30 Mar 2019 15:42:11 -0500 Subject: [PATCH 145/165] Adding coincidence check when comparing d_surf, d_lat. --- src/geometry.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/geometry.cpp b/src/geometry.cpp index 8791dd957..f4c24bcd5 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -32,6 +32,10 @@ std::vector overlap_check_count; // Non-member functions //============================================================================== +bool coincident(const double& d1, const double& d2) { + return std::abs(d1 - d2) < FP_COINCIDENT; +} + bool check_cell_overlap(Particle* p) { int n_coord = p->n_coord_; @@ -396,7 +400,7 @@ BoundaryInfo distance_to_boundary(Particle* p) // a higher level then we need to make sure that the higher level boundary // is selected. This logic must consider floating point precision. double& d = info.distance; - if (d_surf < d_lat) { + if (d_surf < d_lat && !coincident(d_surf, d_lat)) { if (d == INFINITY || (d - d_surf)/d >= FP_REL_PRECISION) { d = d_surf; From 865ad405bac749b2db861d1dc7236465e09c1b1a Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 30 Mar 2019 16:00:32 -0500 Subject: [PATCH 146/165] Cleaning up the get_indices function for HexLattice a bit. --- src/lattice.cpp | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index e5ea20910..2d3afbc8b 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -743,8 +743,6 @@ HexLattice::get_indices(Position r, Direction u) const ix += n_rings_-1; ia += n_rings_-1; - // r += TINY_BIT * u; - // Calculate the (squared) distance between the particle and the centers of // the four possible cells. Regular hexagonal tiles form a Voronoi // tessellation so the xyz should be in the hexagonal cell that it is closest @@ -752,39 +750,48 @@ HexLattice::get_indices(Position r, Direction u) const // remainders of the floor divisions above because it provides better finite // precision performance. Squared distances are used becasue they are more // computationally efficient than normal distances. - int k {1}; - int k_min {1}; + + // COINCIDENCE CHECK + // if a distance to center, d, is the same as the current minimum + // distance, d_min, the particle is on an edge or vertex. In this case, + // the dot product of the position vector and direction vector for the current + // indices, dp, and the dot product for the currently selected + // indices, dp_min, are compared. The cell the particle is moving into is kept + // (the cell with the lowest dot prouct as the vectors will be completely + // opposed if the particle is moving directly toward the center of the + // cell, i.e. dot product == -1) + int ix_delta {}; + int ia_delta {}; double d_min {INFTY}; double dp_min {INFTY}; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { + // get local coordinates const std::array i_xyz {ix + j, ia + i, 0}; Position r_t = get_local_position(r, i_xyz); + // calculate distance double d = r_t.x*r_t.x + r_t.y*r_t.y; - bool coincident = std::abs(d - d_min) < FP_COINCIDENT; - if (d < d_min || coincident) { + // check for coincidence + bool on_boundary = std::abs(d - d_min) < FP_COINCIDENT; + if (d < d_min || on_boundary) { + // find dot product r_t /= std::sqrt(d); double dp = u.x * r_t.x + u.y * r_t.y; - if (coincident && dp > dp_min) { k++; continue; } + // do not update values if particle is on a + // bouncary and not moving into this cell + if (on_boundary && dp > dp_min) { continue; } // update values d_min = d; - k_min = k; + ix_delta = j; + ia_delta = i; dp_min = dp; } - k++; } } - // Select the minimum squared distance which corresponds to the cell the - // coordinates are in. - if (k_min == 2) { - ++ix; - } else if (k_min == 3) { - ++ia; - } else if (k_min == 4) { - ++ix; - ++ia; - } + // update indices + ix += ix_delta; + ia += ia_delta; return {ix, ia, iz}; } From da9a8761850c499de5012f5fc6563623ad5e7663 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Apr 2019 09:44:57 -0500 Subject: [PATCH 147/165] Some corrections to comments. Adding coincident to geometry header. --- include/openmc/geometry.h | 6 ++++++ src/lattice.cpp | 28 ++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/include/openmc/geometry.h b/include/openmc/geometry.h index 5feca2992..43b595bc1 100644 --- a/include/openmc/geometry.h +++ b/include/openmc/geometry.h @@ -35,6 +35,12 @@ struct BoundaryInfo { std::array lattice_translation {}; //!< which way lattice indices will change }; +//============================================================================== +//! Check two distances by coincidence tolerance +//============================================================================== + +bool coincident(const double& d1, const double& d2); + //============================================================================== //! Check for overlapping cells at a particle's position. //============================================================================== diff --git a/src/lattice.cpp b/src/lattice.cpp index 2d3afbc8b..73de24307 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -713,15 +713,11 @@ HexLattice::get_indices(Position r, Direction u) const // result variables int ix{}, ia{}, iz{}; - // The implementation for HexLattice currently doesn't use direction - // information. As a result, we move the position slightly forward to - // determine what lattice index the particle is most likely to be in. - // Offset the xyz by the lattice center. Position r_o {r.x - center_.x, r.y - center_.y, r.z}; if (is_3d_) {r_o.z -= center_.z;} - // Index the z direction. + // Index the z direction. Same as in RectLattice::get_indices. if (is_3d_) { double iz_ {r_o.z / pitch_[1] + 0.5 * n_axial_}; long iz_close {std::lround(iz_)}; @@ -752,14 +748,14 @@ HexLattice::get_indices(Position r, Direction u) const // computationally efficient than normal distances. // COINCIDENCE CHECK - // if a distance to center, d, is the same as the current minimum - // distance, d_min, the particle is on an edge or vertex. In this case, - // the dot product of the position vector and direction vector for the current - // indices, dp, and the dot product for the currently selected - // indices, dp_min, are compared. The cell the particle is moving into is kept - // (the cell with the lowest dot prouct as the vectors will be completely - // opposed if the particle is moving directly toward the center of the - // cell, i.e. dot product == -1) + // if a distance to center, d, is within the coincidence tolerance of the + // current minimum distance, d_min, the particle is on an edge or vertex. + // In this case, the dot product of the position vector and direction vector + // for the current indices, dp, and the dot product for the currently selected + // indices, dp_min, are compared. The cell which the particle is moving into + // is kept (i.e. the cell with the lowest dot prouct as the vectors will be + // completely opposed if the particle is moving directly toward the center of + // the cell). int ix_delta {}; int ia_delta {}; double d_min {INFTY}; @@ -774,11 +770,11 @@ HexLattice::get_indices(Position r, Direction u) const // check for coincidence bool on_boundary = std::abs(d - d_min) < FP_COINCIDENT; if (d < d_min || on_boundary) { - // find dot product + // normalize r_t and find dot product r_t /= std::sqrt(d); double dp = u.x * r_t.x + u.y * r_t.y; // do not update values if particle is on a - // bouncary and not moving into this cell + // boundary and not moving into this cell if (on_boundary && dp > dp_min) { continue; } // update values d_min = d; @@ -789,7 +785,7 @@ HexLattice::get_indices(Position r, Direction u) const } } - // update indices + // update outgoing indices ix += ix_delta; ia += ia_delta; From 8673c924acc115b973ae812bda33fa9aacde05f3 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Apr 2019 17:30:12 -0500 Subject: [PATCH 148/165] Adding test for hex lattice with coincident interior surface. --- .../lattice_hex_coincident/geometry.xml | 34 ++++++++++ .../lattice_hex_coincident/materials.xml | 62 +++++++++++++++++++ .../lattice_hex_coincident/results_true.dat | 2 + .../lattice_hex_coincident/settings.xml | 20 ++++++ .../lattice_hex_coincident/test.py | 6 ++ 5 files changed, 124 insertions(+) create mode 100644 tests/regression_tests/lattice_hex_coincident/geometry.xml create mode 100644 tests/regression_tests/lattice_hex_coincident/materials.xml create mode 100644 tests/regression_tests/lattice_hex_coincident/results_true.dat create mode 100644 tests/regression_tests/lattice_hex_coincident/settings.xml create mode 100644 tests/regression_tests/lattice_hex_coincident/test.py diff --git a/tests/regression_tests/lattice_hex_coincident/geometry.xml b/tests/regression_tests/lattice_hex_coincident/geometry.xml new file mode 100644 index 000000000..3c31f091d --- /dev/null +++ b/tests/regression_tests/lattice_hex_coincident/geometry.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + 1.4 + 3 +

0.0 0.0
+ + 2 +2 2 + 1 +2 2 + 2 + + + + + + + + + + + + + + diff --git a/tests/regression_tests/lattice_hex_coincident/materials.xml b/tests/regression_tests/lattice_hex_coincident/materials.xml new file mode 100644 index 000000000..ae9743c66 --- /dev/null +++ b/tests/regression_tests/lattice_hex_coincident/materials.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/regression_tests/lattice_hex_coincident/results_true.dat b/tests/regression_tests/lattice_hex_coincident/results_true.dat new file mode 100644 index 000000000..36e8f2d47 --- /dev/null +++ b/tests/regression_tests/lattice_hex_coincident/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +1.328686E+00 1.538567E-02 diff --git a/tests/regression_tests/lattice_hex_coincident/settings.xml b/tests/regression_tests/lattice_hex_coincident/settings.xml new file mode 100644 index 000000000..02c22e610 --- /dev/null +++ b/tests/regression_tests/lattice_hex_coincident/settings.xml @@ -0,0 +1,20 @@ + + + eigenvalue + 1000 + 10 + 5 + + + -0.9899494936611666 -0.9899494936611666 0.0 0.9899494936611666 0.9899494936611666 10.0 + + + + false + + 46 + interpolation + + true + + diff --git a/tests/regression_tests/lattice_hex_coincident/test.py b/tests/regression_tests/lattice_hex_coincident/test.py new file mode 100644 index 000000000..eb63f84df --- /dev/null +++ b/tests/regression_tests/lattice_hex_coincident/test.py @@ -0,0 +1,6 @@ +from tests.testing_harness import TestHarness + + +def test_lattice_hex(): + harness = TestHarness('statepoint.10.h5') + harness.main() From f08f012bc2fe135ca5e35b8a1ea4da3cd5b53574 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Apr 2019 18:10:35 -0500 Subject: [PATCH 149/165] Simplifying model materials and settings. Updating test results. --- .../lattice_hex_coincident/geometry.xml | 14 +++---- .../lattice_hex_coincident/materials.xml | 41 +++---------------- .../lattice_hex_coincident/results_true.dat | 2 +- .../lattice_hex_coincident/settings.xml | 6 +-- 4 files changed, 14 insertions(+), 49 deletions(-) diff --git a/tests/regression_tests/lattice_hex_coincident/geometry.xml b/tests/regression_tests/lattice_hex_coincident/geometry.xml index 3c31f091d..aa2d09189 100644 --- a/tests/regression_tests/lattice_hex_coincident/geometry.xml +++ b/tests/regression_tests/lattice_hex_coincident/geometry.xml @@ -1,14 +1,14 @@ - - - - - - + + + + + + - + 1.4 3
0.0 0.0
diff --git a/tests/regression_tests/lattice_hex_coincident/materials.xml b/tests/regression_tests/lattice_hex_coincident/materials.xml index ae9743c66..164aa27fe 100644 --- a/tests/regression_tests/lattice_hex_coincident/materials.xml +++ b/tests/regression_tests/lattice_hex_coincident/materials.xml @@ -1,62 +1,31 @@ - + - - - - + - - - - - - - + - - - - - + - + - - - - - - - - - - - - - - - - - - diff --git a/tests/regression_tests/lattice_hex_coincident/results_true.dat b/tests/regression_tests/lattice_hex_coincident/results_true.dat index 36e8f2d47..ba047f674 100644 --- a/tests/regression_tests/lattice_hex_coincident/results_true.dat +++ b/tests/regression_tests/lattice_hex_coincident/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.328686E+00 1.538567E-02 +1.741370E+00 1.384609E-03 diff --git a/tests/regression_tests/lattice_hex_coincident/settings.xml b/tests/regression_tests/lattice_hex_coincident/settings.xml index 02c22e610..0d72a853b 100644 --- a/tests/regression_tests/lattice_hex_coincident/settings.xml +++ b/tests/regression_tests/lattice_hex_coincident/settings.xml @@ -12,9 +12,5 @@ false - 46 - interpolation - - true - + 22 From 28998395d37e80ae4044a88d5203ac44d77992dd Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Apr 2019 21:02:15 -0500 Subject: [PATCH 150/165] Updating test name. --- tests/regression_tests/lattice_hex_coincident/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression_tests/lattice_hex_coincident/test.py b/tests/regression_tests/lattice_hex_coincident/test.py index eb63f84df..06ee724f9 100644 --- a/tests/regression_tests/lattice_hex_coincident/test.py +++ b/tests/regression_tests/lattice_hex_coincident/test.py @@ -1,6 +1,6 @@ from tests.testing_harness import TestHarness -def test_lattice_hex(): +def test_lattice_hex_coincident_surf(): harness = TestHarness('statepoint.10.h5') harness.main() From 0d01ffa553643118ef1d3cf31af6fb922946661a Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 Apr 2019 21:22:38 -0500 Subject: [PATCH 151/165] Adding __init__.py to new test directory. --- tests/regression_tests/lattice_hex_coincident/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/regression_tests/lattice_hex_coincident/__init__.py diff --git a/tests/regression_tests/lattice_hex_coincident/__init__.py b/tests/regression_tests/lattice_hex_coincident/__init__.py new file mode 100644 index 000000000..e69de29bb From 02ff7d017dbfe523dbba8d59c7406cd7d567b52d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Apr 2019 10:17:51 -0500 Subject: [PATCH 152/165] Changed variable name. Caught some spelling mistakes. --- src/lattice.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index 73de24307..de077bbe6 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -717,7 +717,8 @@ HexLattice::get_indices(Position r, Direction u) const Position r_o {r.x - center_.x, r.y - center_.y, r.z}; if (is_3d_) {r_o.z -= center_.z;} - // Index the z direction. Same as in RectLattice::get_indices. + // Index the z direction. Same as the technique used in + // RectLattice::get_indices. if (is_3d_) { double iz_ {r_o.z / pitch_[1] + 0.5 * n_axial_}; long iz_close {std::lround(iz_)}; @@ -744,7 +745,7 @@ HexLattice::get_indices(Position r, Direction u) const // tessellation so the xyz should be in the hexagonal cell that it is closest // to the center of. This method is used over a method that uses the // remainders of the floor divisions above because it provides better finite - // precision performance. Squared distances are used becasue they are more + // precision performance. Squared distances are used because they are more // computationally efficient than normal distances. // COINCIDENCE CHECK @@ -753,11 +754,11 @@ HexLattice::get_indices(Position r, Direction u) const // In this case, the dot product of the position vector and direction vector // for the current indices, dp, and the dot product for the currently selected // indices, dp_min, are compared. The cell which the particle is moving into - // is kept (i.e. the cell with the lowest dot prouct as the vectors will be + // is kept (i.e. the cell with the lowest dot product as the vectors will be // completely opposed if the particle is moving directly toward the center of // the cell). - int ix_delta {}; - int ia_delta {}; + int ix_chg {}; + int ia_chg {}; double d_min {INFTY}; double dp_min {INFTY}; for (int i = 0; i < 2; i++) { @@ -778,16 +779,16 @@ HexLattice::get_indices(Position r, Direction u) const if (on_boundary && dp > dp_min) { continue; } // update values d_min = d; - ix_delta = j; - ia_delta = i; + ix_chg = j; + ia_chg = i; dp_min = dp; } } } // update outgoing indices - ix += ix_delta; - ia += ia_delta; + ix += ix_chg; + ia += ia_chg; return {ix, ia, iz}; } From 200f47bf91c2cbb083d8bc76b9f40261d3215fcf Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 26 Mar 2019 19:24:25 -0500 Subject: [PATCH 153/165] Fixes for 2D mesh tally plotting. --- scripts/openmc-plot-mesh-tally | 36 +++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/scripts/openmc-plot-mesh-tally b/scripts/openmc-plot-mesh-tally index 61ada852c..7c42b7281 100755 --- a/scripts/openmc-plot-mesh-tally +++ b/scripts/openmc-plot-mesh-tally @@ -216,24 +216,42 @@ class MeshPlotter(tk.Frame): index = self.filterBoxes[f.short_name].current() spec_list.append((type(f), (index,))) + dims = (self.nx, self.ny, self.nz) + text = self.basisBox.get() if text == 'xy': - dims = (self.nx, self.ny) + h_ind = 0 + v_ind = 1 elif text == 'yz': - dims = (self.ny, self.nz) + h_ind = 1 + v_ind = 2 else: - dims = (self.nx, self.nz) + h_ind = 0 + v_ind = 2 + + axial_ind = 3 - (h_ind + v_ind) + print(h_ind, v_ind) + print(dims) + dims = (dims[h_ind], dims[v_ind]) + + mesh_dim = len(self.mesh.dimension) + if mesh_dim == 3: + mesh_indices = [0,0,0] + else: + mesh_indices = [0,0] + matrix = np.zeros(dims) for i in range(dims[0]): for j in range(dims[1]): - if text == 'xy': - meshtuple = (i + 1, j + 1, axial_level) - elif text == 'yz': - meshtuple = (axial_level, i + 1, j + 1) + if mesh_dim == 3: + mesh_indices[h_ind] = i + 1 + mesh_indices[v_ind] = j + 1 + mesh_indices[axial_ind] = axial_level else: - meshtuple = (i + 1, axial_level, j + 1) + mesh_indices[0] = i + 1 + mesh_indices[1] = j + 1 filters, filter_bins = zip(*spec_list + [ - (type(mesh_filter), (meshtuple,))]) + (type(mesh_filter), (tuple(mesh_indices),))]) mean = selectedTally.get_values( [self.scoreBox.get()], filters, filter_bins) stdev = selectedTally.get_values( From fe3d85d0d086321c09d777bfb09cdede7e27289b Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 27 Mar 2019 13:56:53 -0500 Subject: [PATCH 154/165] Fix to depletion script. --- examples/python/pincell_depletion/run_depletion.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/python/pincell_depletion/run_depletion.py b/examples/python/pincell_depletion/run_depletion.py index ba34a3706..c4319eb96 100644 --- a/examples/python/pincell_depletion/run_depletion.py +++ b/examples/python/pincell_depletion/run_depletion.py @@ -16,7 +16,7 @@ particles = 1000 time_step = 1*24*60*60 # s final_time = 5*24*60*60 # s time_steps = np.full(final_time // time_step, time_step) - +print(time_steps) chain_file = './chain_simple.xml' power = 174 # W/cm, for 2D simulations only (use W for 3D) @@ -100,7 +100,7 @@ geometry = openmc.Geometry(root) # Compute cell areas area = {} -area[fuel] = np.pi * fuel_or.coefficients['R'] ** 2 +area[fuel] = np.pi * fuel_or.coefficients['r'] ** 2 # Set materials volume for depletion. Set to an area for 2D simulations uo2.volume = area[fuel] From cc09ba4a5bf2edd95624e386b72803d83ddc9f4f Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Apr 2019 13:46:56 -0500 Subject: [PATCH 155/165] Fixes to indexing syntax for a couple jupyter examples. --- examples/jupyter/post-processing.ipynb | 563 +++++++++++-------------- examples/jupyter/search.ipynb | 188 +++++++-- 2 files changed, 413 insertions(+), 338 deletions(-) diff --git a/examples/jupyter/post-processing.ipynb b/examples/jupyter/post-processing.ipynb index fd25e810d..c8792fa6d 100644 --- a/examples/jupyter/post-processing.ipynb +++ b/examples/jupyter/post-processing.ipynb @@ -10,9 +10,7 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", @@ -40,9 +38,7 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# 1.6 enriched fuel\n", @@ -75,9 +71,7 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate a Materials collection\n", @@ -97,10 +91,17 @@ { "cell_type": "code", "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [], + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n" + ] + } + ], "source": [ "# Create cylinders for the fuel and clad\n", "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, R=0.39218)\n", @@ -125,9 +126,7 @@ { "cell_type": "code", "execution_count": 5, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Create a Universe to encapsulate a fuel pin\n", @@ -162,9 +161,7 @@ { "cell_type": "code", "execution_count": 6, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Create root Cell\n", @@ -189,9 +186,7 @@ { "cell_type": "code", "execution_count": 7, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Create Geometry and set root Universe\n", @@ -201,9 +196,7 @@ { "cell_type": "code", "execution_count": 8, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Export to \"geometry.xml\"\n", @@ -220,9 +213,7 @@ { "cell_type": "code", "execution_count": 9, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# OpenMC simulation parameters\n", @@ -255,9 +246,7 @@ { "cell_type": "code", "execution_count": 10, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate a Plot\n", @@ -283,21 +272,8 @@ { "cell_type": "code", "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "metadata": {}, + "outputs": [], "source": [ "# Run openmc in plotting mode\n", "openmc.plot_geometry(output=False)" @@ -306,13 +282,11 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB+EMBQIvI1Ad4sUAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTctMTItMDRUMjA6NDc6\nMzUtMDY6MDBGrChsAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE3LTEyLTA0VDIwOjQ3OjM1LTA2OjAw\nN/GQ0AAAAABJRU5ErkJggg==\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEVyEhLpgJFNv8T///98iBL0AAAAAWJLR0QDEQxM8gAAAAd0SU1FB+MEAg0jGz+ZgBkAAAKlSURBVGje7ZrBscIwDETxwSWkn5TAgXCgBPqhBA6kyj/fDhCIJa2zZAwz0pmHpZWdSazd7Tw8PDw8PDw8vinCMBzW03HIsRLvhnv0HL7qD+IwjzXKzaNaxeEt9kz21RWEBV5XQbfka3pQWL4qgdLyNQkUcbwFT/FP4zjWt+D+++OY4laZQJgtnqNOwe5l9XkGmIIL/PEHUAGTeuc5P15wBbu34ucSIAXkX77h4xUtIBSXnxIAOhCLy98TANNfLj8lYBYQCuLPWmAWEBe9f90DUPdKy08JWB0U1HsoaAgQxPSnAgwBopz+VABQvoDnAnqTP0r8zealzfPcQqqAQSs/C6AKGLX0pwKs8uX0cwGaAHr6uYC9wSt46qDCB4RXBDTkMwWMhnxZQF3+s8pf1AZY5VsCWuVnAUQ+YPxB43X5koAiH035soCa/AaeBOw34m359AaQPCK/1oAAyJ8aIPBI+7QGRkD+3IBt+A6QPzeg34SH2pcauN+Kt9uXGljkse0jb6BP8AD+vwGKPLZ95A0UofbnDbAFj20/eQN+gD8h/LgRD25/8QCA2088AD/Oo8dPOoDo8ZMOoPPNeej4pwdAgUcfX9IDzHnnf5lnz88XnH/nSf4M8cIL7I+/P3yCP0G88P7W+v2z9ft36+8P9vuJ/X5r/f3Jfj83//5vff/R+v6Hvb9i78/Y+7vW94/N71/Z+2P2/pq9P2fv7+n5ATu/YOcn7PyGnR+x8yt6ftYN3PzOENCcH7LzS3Z+Ss9vO62DV5uPmgAXSz5+fs7O72n/QBQLwPwLrH+C9W/Q/hHWv8L6Z2j/ThZgvX+I9S/R/inWv8X6x2j/Guufo/17rH+Q9S/S/knWv0n7R2n/Kuufpf27tH+Y9i/vWP+0h4eHh4eHh8cW8QcxLJDBvLKoigAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOS0wNC0wMlQxMzozNToyNy0wNTowMIPRP68AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTktMDQtMDJUMTM6MzU6MjctMDU6MDDyjIcTAAAAAElFTkSuQmCC\n", "text/plain": [ "" ] @@ -340,9 +314,7 @@ { "cell_type": "code", "execution_count": 13, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate an empty Tallies object\n", @@ -352,9 +324,7 @@ { "cell_type": "code", "execution_count": 14, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Create mesh which will be used for tally\n", @@ -376,9 +346,7 @@ { "cell_type": "code", "execution_count": 15, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# Export to \"tallies.xml\"\n", @@ -396,7 +364,6 @@ "cell_type": "code", "execution_count": 16, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -404,197 +371,185 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", + " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%%%%%%\n", + " ##################### %%%%%%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%\n", + " ################# %%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%\n", + " ############ %%%%%%%%%%%%%%%\n", + " ######## %%%%%%%%%%%%%%\n", + " %%%%%%%%%%%\n", "\n", " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2017 Massachusetts Institute of Technology\n", + " Copyright | 2011-2019 MIT and OpenMC contributors\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.9.0\n", - " Git SHA1 | 9b7cebf7bc34d60e0f1750c3d6cb103df11e8dc4\n", - " Date/Time | 2017-12-04 20:47:36\n", - " OpenMP Threads | 4\n", + " Version | 0.10.0\n", + " Git SHA1 | fe3d85d0d086321c09d777bfb09cdede7e27289b\n", + " Date/Time | 2019-04-02 13:35:28\n", + " OpenMP Threads | 2\n", "\n", " Reading settings XML file...\n", " Reading cross sections XML file...\n", " Reading materials XML file...\n", " Reading geometry XML file...\n", - " Building neighboring cells lists for each surface...\n", - " Reading U235 from /home/romano/openmc/scripts/nndc_hdf5/U235.h5\n", - " Reading U238 from /home/romano/openmc/scripts/nndc_hdf5/U238.h5\n", - " Reading O16 from /home/romano/openmc/scripts/nndc_hdf5/O16.h5\n", - " Reading H1 from /home/romano/openmc/scripts/nndc_hdf5/H1.h5\n", - " Reading B10 from /home/romano/openmc/scripts/nndc_hdf5/B10.h5\n", - " Reading Zr90 from /home/romano/openmc/scripts/nndc_hdf5/Zr90.h5\n", - " Maximum neutron transport energy: 2.00000E+07 eV for U235\n", + " Reading U235 from /home/shriwise/opt/openmc/xs/nndc_hdf5/U235.h5\n", + " Reading U238 from /home/shriwise/opt/openmc/xs/nndc_hdf5/U238.h5\n", + " Reading O16 from /home/shriwise/opt/openmc/xs/nndc_hdf5/O16.h5\n", + " Reading H1 from /home/shriwise/opt/openmc/xs/nndc_hdf5/H1.h5\n", + " Reading B10 from /home/shriwise/opt/openmc/xs/nndc_hdf5/B10.h5\n", + " Reading Zr90 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Zr90.h5\n", + " Maximum neutron transport energy: 20000000.000000 eV for U235\n", " Reading tallies XML file...\n", " Writing summary.h5 file...\n", " Initializing source particles...\n", "\n", " ====================> K EIGENVALUE SIMULATION <====================\n", "\n", - " Bat./Gen. k Average k \n", - " ========= ======== ==================== \n", - " 1/1 1.04359 \n", - " 2/1 1.04323 \n", - " 3/1 1.04711 \n", - " 4/1 1.03892 \n", - " 5/1 1.02442 \n", - " 6/1 1.02046 \n", - " 7/1 1.05998 \n", - " 8/1 1.04184 \n", - " 9/1 1.04786 \n", - " 10/1 1.06636 \n", - " 11/1 1.07229 \n", - " 12/1 1.04413 1.05821 +/- 0.01408\n", - " 13/1 1.06376 1.06006 +/- 0.00834\n", - " 14/1 1.06898 1.06229 +/- 0.00630\n", - " 15/1 1.05095 1.06002 +/- 0.00538\n", - " 16/1 1.04453 1.05744 +/- 0.00510\n", - " 17/1 1.05626 1.05727 +/- 0.00431\n", - " 18/1 1.03423 1.05439 +/- 0.00472\n", - " 19/1 1.04240 1.05306 +/- 0.00437\n", - " 20/1 1.03719 1.05147 +/- 0.00422\n", - " 21/1 1.04308 1.05071 +/- 0.00389\n", - " 22/1 1.03956 1.04978 +/- 0.00367\n", - " 23/1 1.05824 1.05043 +/- 0.00344\n", - " 24/1 1.03151 1.04908 +/- 0.00346\n", - " 25/1 1.02695 1.04760 +/- 0.00354\n", - " 26/1 1.02581 1.04624 +/- 0.00358\n", - " 27/1 1.09932 1.04936 +/- 0.00459\n", - " 28/1 1.05983 1.04995 +/- 0.00437\n", - " 29/1 1.03381 1.04910 +/- 0.00422\n", - " 30/1 1.06727 1.05001 +/- 0.00410\n", - " 31/1 1.03180 1.04914 +/- 0.00400\n", - " 32/1 1.04520 1.04896 +/- 0.00382\n", - " 33/1 1.07158 1.04994 +/- 0.00378\n", - " 34/1 1.04283 1.04965 +/- 0.00363\n", - " 35/1 1.03272 1.04897 +/- 0.00354\n", - " 36/1 1.02730 1.04814 +/- 0.00351\n", - " 37/1 1.01975 1.04709 +/- 0.00353\n", - " 38/1 1.04815 1.04712 +/- 0.00341\n", - " 39/1 1.02642 1.04641 +/- 0.00336\n", - " 40/1 1.04063 1.04622 +/- 0.00325\n", - " 41/1 0.97384 1.04388 +/- 0.00392\n", - " 42/1 1.06049 1.04440 +/- 0.00383\n", - " 43/1 1.04467 1.04441 +/- 0.00371\n", - " 44/1 1.04454 1.04441 +/- 0.00360\n", - " 45/1 1.06529 1.04501 +/- 0.00355\n", - " 46/1 1.05496 1.04529 +/- 0.00346\n", - " 47/1 1.03717 1.04507 +/- 0.00337\n", - " 48/1 1.03874 1.04490 +/- 0.00328\n", - " 49/1 1.02083 1.04428 +/- 0.00326\n", - " 50/1 1.04847 1.04439 +/- 0.00318\n", - " 51/1 1.03789 1.04423 +/- 0.00310\n", - " 52/1 1.04447 1.04423 +/- 0.00303\n", - " 53/1 1.01942 1.04366 +/- 0.00301\n", - " 54/1 1.04639 1.04372 +/- 0.00294\n", - " 55/1 1.02539 1.04331 +/- 0.00291\n", - " 56/1 1.06312 1.04374 +/- 0.00288\n", - " 57/1 1.05854 1.04406 +/- 0.00283\n", - " 58/1 1.05150 1.04421 +/- 0.00278\n", - " 59/1 1.04321 1.04419 +/- 0.00272\n", - " 60/1 1.04762 1.04426 +/- 0.00266\n", - " 61/1 0.99442 1.04328 +/- 0.00279\n", - " 62/1 1.06907 1.04378 +/- 0.00278\n", - " 63/1 1.03170 1.04355 +/- 0.00274\n", - " 64/1 1.04308 1.04354 +/- 0.00268\n", - " 65/1 1.01439 1.04301 +/- 0.00269\n", - " 66/1 1.04581 1.04306 +/- 0.00264\n", - " 67/1 1.04404 1.04308 +/- 0.00259\n", - " 68/1 1.03158 1.04288 +/- 0.00256\n", - " 69/1 1.04953 1.04299 +/- 0.00251\n", - " 70/1 1.06338 1.04333 +/- 0.00250\n", - " 71/1 1.03768 1.04324 +/- 0.00246\n", - " 72/1 1.02531 1.04295 +/- 0.00243\n", - " 73/1 1.04552 1.04299 +/- 0.00240\n", - " 74/1 1.04293 1.04299 +/- 0.00236\n", - " 75/1 1.05928 1.04324 +/- 0.00233\n", - " 76/1 1.05057 1.04335 +/- 0.00230\n", - " 77/1 1.01846 1.04298 +/- 0.00230\n", - " 78/1 1.05755 1.04320 +/- 0.00227\n", - " 79/1 1.05222 1.04333 +/- 0.00224\n", - " 80/1 1.04860 1.04340 +/- 0.00221\n", - " 81/1 1.03026 1.04322 +/- 0.00219\n", - " 82/1 1.02360 1.04294 +/- 0.00218\n", - " 83/1 1.06679 1.04327 +/- 0.00217\n", - " 84/1 1.06297 1.04354 +/- 0.00216\n", - " 85/1 1.04426 1.04355 +/- 0.00213\n", - " 86/1 1.00337 1.04302 +/- 0.00217\n", - " 87/1 1.04787 1.04308 +/- 0.00214\n", - " 88/1 1.04332 1.04308 +/- 0.00211\n", - " 89/1 1.04369 1.04309 +/- 0.00208\n", - " 90/1 1.05006 1.04318 +/- 0.00206\n", - " 91/1 1.05394 1.04331 +/- 0.00204\n", - " 92/1 1.06017 1.04352 +/- 0.00202\n", - " 93/1 1.02032 1.04324 +/- 0.00202\n", - " 94/1 1.04816 1.04330 +/- 0.00200\n", - " 95/1 1.06601 1.04356 +/- 0.00199\n", - " 96/1 1.02876 1.04339 +/- 0.00197\n", - " 97/1 1.03929 1.04334 +/- 0.00195\n", - " 98/1 1.01958 1.04307 +/- 0.00195\n", - " 99/1 1.01899 1.04280 +/- 0.00195\n", - " 100/1 1.05150 1.04290 +/- 0.00193\n", + " Bat./Gen. k Average k\n", + " ========= ======== ====================\n", + " 1/1 1.04359\n", + " 2/1 1.04323\n", + " 3/1 1.04711\n", + " 4/1 1.03892\n", + " 5/1 1.02459\n", + " 6/1 1.03936\n", + " 7/1 1.03529\n", + " 8/1 1.01590\n", + " 9/1 1.03060\n", + " 10/1 1.02892\n", + " 11/1 1.03987\n", + " 12/1 1.04395 1.04191 +/- 0.00204\n", + " 13/1 1.04971 1.04451 +/- 0.00285\n", + " 14/1 1.03880 1.04308 +/- 0.00247\n", + " 15/1 1.03092 1.04065 +/- 0.00310\n", + " 16/1 1.04653 1.04163 +/- 0.00271\n", + " 17/1 1.04114 1.04156 +/- 0.00229\n", + " 18/1 1.06033 1.04391 +/- 0.00307\n", + " 19/1 1.04163 1.04365 +/- 0.00272\n", + " 20/1 1.04992 1.04428 +/- 0.00251\n", + " 21/1 1.01577 1.04169 +/- 0.00345\n", + " 22/1 1.03611 1.04122 +/- 0.00318\n", + " 23/1 1.03251 1.04055 +/- 0.00300\n", + " 24/1 1.03996 1.04051 +/- 0.00278\n", + " 25/1 1.06132 1.04190 +/- 0.00294\n", + " 26/1 1.03581 1.04152 +/- 0.00277\n", + " 27/1 1.05195 1.04213 +/- 0.00268\n", + " 28/1 1.03721 1.04186 +/- 0.00254\n", + " 29/1 1.03475 1.04148 +/- 0.00243\n", + " 30/1 1.03057 1.04094 +/- 0.00237\n", + " 31/1 1.04407 1.04109 +/- 0.00226\n", + " 32/1 1.04661 1.04134 +/- 0.00217\n", + " 33/1 1.03286 1.04097 +/- 0.00210\n", + " 34/1 1.01253 1.03978 +/- 0.00234\n", + " 35/1 1.03488 1.03959 +/- 0.00225\n", + " 36/1 1.02509 1.03903 +/- 0.00223\n", + " 37/1 1.03647 1.03894 +/- 0.00215\n", + " 38/1 1.06387 1.03983 +/- 0.00226\n", + " 39/1 1.02418 1.03929 +/- 0.00224\n", + " 40/1 1.05815 1.03992 +/- 0.00226\n", + " 41/1 1.04433 1.04006 +/- 0.00219\n", + " 42/1 1.04627 1.04025 +/- 0.00213\n", + " 43/1 1.05089 1.04057 +/- 0.00209\n", + " 44/1 1.02985 1.04026 +/- 0.00205\n", + " 45/1 1.06236 1.04089 +/- 0.00209\n", + " 46/1 1.04283 1.04094 +/- 0.00203\n", + " 47/1 1.04404 1.04103 +/- 0.00197\n", + " 48/1 1.05946 1.04151 +/- 0.00198\n", + " 49/1 1.03286 1.04129 +/- 0.00194\n", + " 50/1 1.07609 1.04216 +/- 0.00208\n", + " 51/1 1.02097 1.04164 +/- 0.00210\n", + " 52/1 1.08390 1.04265 +/- 0.00228\n", + " 53/1 1.01654 1.04204 +/- 0.00231\n", + " 54/1 1.02701 1.04170 +/- 0.00228\n", + " 55/1 1.04845 1.04185 +/- 0.00223\n", + " 56/1 1.05401 1.04212 +/- 0.00220\n", + " 57/1 1.04673 1.04221 +/- 0.00216\n", + " 58/1 1.04093 1.04219 +/- 0.00211\n", + " 59/1 1.03205 1.04198 +/- 0.00208\n", + " 60/1 1.05368 1.04221 +/- 0.00205\n", + " 61/1 1.02273 1.04183 +/- 0.00204\n", + " 62/1 1.03259 1.04165 +/- 0.00201\n", + " 63/1 1.06216 1.04204 +/- 0.00201\n", + " 64/1 1.03658 1.04194 +/- 0.00198\n", + " 65/1 1.02072 1.04155 +/- 0.00198\n", + " 66/1 1.03019 1.04135 +/- 0.00195\n", + " 67/1 1.05241 1.04155 +/- 0.00193\n", + " 68/1 1.05906 1.04185 +/- 0.00192\n", + " 69/1 1.05263 1.04203 +/- 0.00190\n", + " 70/1 1.02176 1.04169 +/- 0.00189\n", + " 71/1 1.03390 1.04157 +/- 0.00187\n", + " 72/1 1.05470 1.04178 +/- 0.00185\n", + " 73/1 1.03892 1.04173 +/- 0.00182\n", + " 74/1 0.98570 1.04086 +/- 0.00199\n", + " 75/1 1.02591 1.04063 +/- 0.00198\n", + " 76/1 1.02944 1.04046 +/- 0.00195\n", + " 77/1 1.04456 1.04052 +/- 0.00192\n", + " 78/1 1.04877 1.04064 +/- 0.00190\n", + " 79/1 1.02922 1.04047 +/- 0.00188\n", + " 80/1 1.03456 1.04039 +/- 0.00185\n", + " 81/1 1.02594 1.04019 +/- 0.00184\n", + " 82/1 1.05772 1.04043 +/- 0.00183\n", + " 83/1 1.03401 1.04034 +/- 0.00181\n", + " 84/1 1.02023 1.04007 +/- 0.00180\n", + " 85/1 1.05036 1.04021 +/- 0.00178\n", + " 86/1 1.04087 1.04022 +/- 0.00176\n", + " 87/1 1.02683 1.04004 +/- 0.00175\n", + " 88/1 1.01558 1.03973 +/- 0.00175\n", + " 89/1 1.05942 1.03998 +/- 0.00175\n", + " 90/1 1.04540 1.04005 +/- 0.00173\n", + " 91/1 1.00511 1.03961 +/- 0.00176\n", + " 92/1 1.04518 1.03968 +/- 0.00174\n", + " 93/1 1.04876 1.03979 +/- 0.00172\n", + " 94/1 1.04409 1.03984 +/- 0.00170\n", + " 95/1 1.08677 1.04039 +/- 0.00177\n", + " 96/1 1.05201 1.04053 +/- 0.00175\n", + " 97/1 1.00706 1.04014 +/- 0.00178\n", + " 98/1 1.01253 1.03983 +/- 0.00178\n", + " 99/1 1.04419 1.03988 +/- 0.00176\n", + " 100/1 1.05087 1.04000 +/- 0.00175\n", " Creating state point statepoint.100.h5...\n", "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 6.5927E-01 seconds\n", - " Reading cross sections = 6.1679E-01 seconds\n", - " Total time in simulation = 1.2768E+02 seconds\n", - " Time in transport only = 1.2740E+02 seconds\n", - " Time in inactive batches = 2.7221E+00 seconds\n", - " Time in active batches = 1.2496E+02 seconds\n", - " Time synchronizing fission bank = 2.4179E-02 seconds\n", - " Sampling source sites = 1.7261E-02 seconds\n", - " SEND/RECV source sites = 6.7268E-03 seconds\n", - " Time accumulating tallies = 1.5442E-02 seconds\n", - " Total time for finalization = 1.6664E-01 seconds\n", - " Total time elapsed = 1.2854E+02 seconds\n", - " Calculation Rate (inactive) = 18368.1 neutrons/second\n", - " Calculation Rate (active) = 3601.09 neutrons/second\n", + " Total time for initialization = 2.4783e-01 seconds\n", + " Reading cross sections = 2.3853e-01 seconds\n", + " Total time in simulation = 1.2926e+02 seconds\n", + " Time in transport only = 1.2922e+02 seconds\n", + " Time in inactive batches = 2.0238e+00 seconds\n", + " Time in active batches = 1.2724e+02 seconds\n", + " Time synchronizing fission bank = 1.9768e-02 seconds\n", + " Sampling source sites = 1.6800e-02 seconds\n", + " SEND/RECV source sites = 2.8950e-03 seconds\n", + " Time accumulating tallies = 3.2764e-03 seconds\n", + " Total time for finalization = 2.5501e-02 seconds\n", + " Total time elapsed = 1.2954e+02 seconds\n", + " Calculation Rate (inactive) = 24706.2 particles/second\n", + " Calculation Rate (active) = 3536.71 particles/second\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 1.04331 +/- 0.00192\n", - " k-effective (Track-length) = 1.04290 +/- 0.00193\n", - " k-effective (Absorption) = 1.04136 +/- 0.00151\n", - " Combined k-effective = 1.04183 +/- 0.00122\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", + " k-effective (Collision) = 1.04002 +/- 0.00179\n", + " k-effective (Track-length) = 1.04000 +/- 0.00175\n", + " k-effective (Absorption) = 1.04116 +/- 0.00173\n", + " Combined k-effective = 1.04058 +/- 0.00138\n", + " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] - }, - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ @@ -620,7 +575,6 @@ "cell_type": "code", "execution_count": 17, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [], @@ -639,9 +593,7 @@ { "cell_type": "code", "execution_count": 18, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -673,25 +625,24 @@ { "cell_type": "code", "execution_count": 19, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([[[ 0.40981574, 0. ]],\n", + "array([[[0.40791951, 0. ]],\n", "\n", - " [[ 0.40963388, 0. ]],\n", + " [[0.40985691, 0. ]],\n", "\n", - " [[ 0.41117481, 0. ]],\n", + " [[0.40996961, 0. ]],\n", "\n", - " ..., \n", - " [[ 0.41179009, 0. ]],\n", + " ...,\n", "\n", - " [[ 0.41329412, 0. ]],\n", + " [[0.41165858, 0. ]],\n", "\n", - " [[ 0.41494587, 0. ]]])" + " [[0.40864517, 0. ]],\n", + "\n", + " [[0.4103825 , 0. ]]])" ] }, "execution_count": 19, @@ -713,9 +664,7 @@ { "cell_type": "code", "execution_count": 20, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -727,30 +676,32 @@ { "data": { "text/plain": [ - "(array([[[ 0.00455351, 0. ]],\n", + "(array([[[0.00453244, 0. ]],\n", " \n", - " [[ 0.00455149, 0. ]],\n", + " [[0.00455397, 0. ]],\n", " \n", - " [[ 0.00456861, 0. ]],\n", + " [[0.00455522, 0. ]],\n", " \n", - " ..., \n", - " [[ 0.00457545, 0. ]],\n", + " ...,\n", " \n", - " [[ 0.00459216, 0. ]],\n", + " [[0.00457398, 0. ]],\n", " \n", - " [[ 0.00461051, 0. ]]]),\n", - " array([[[ 2.00748004e-05, 0.00000000e+00]],\n", + " [[0.0045405 , 0. ]],\n", " \n", - " [[ 1.75039529e-05, 0.00000000e+00]],\n", + " [[0.00455981, 0. ]]]),\n", + " array([[[1.95627478e-05, 0.00000000e+00]],\n", " \n", - " [[ 1.96093103e-05, 0.00000000e+00]],\n", + " [[1.83614292e-05, 0.00000000e+00]],\n", " \n", - " ..., \n", - " [[ 1.69721143e-05, 0.00000000e+00]],\n", + " [[1.64302659e-05, 0.00000000e+00]],\n", " \n", - " [[ 1.58964240e-05, 0.00000000e+00]],\n", + " ...,\n", " \n", - " [[ 1.81009205e-05, 0.00000000e+00]]]))" + " [[1.72592008e-05, 0.00000000e+00]],\n", + " \n", + " [[1.67649181e-05, 0.00000000e+00]],\n", + " \n", + " [[1.73154805e-05, 0.00000000e+00]]]))" ] }, "execution_count": 20, @@ -773,9 +724,7 @@ { "cell_type": "code", "execution_count": 21, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -808,9 +757,7 @@ { "cell_type": "code", "execution_count": 22, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "flux.std_dev.shape = (100, 100)\n", @@ -822,14 +769,12 @@ { "cell_type": "code", "execution_count": 23, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 23, @@ -838,12 +783,14 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAC7CAYAAAB1qmWGAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsvXewXNl13vvbJ3RONydcXNyLHAZDDCZxZpgpUaZE0aai\ng57temW98pNki1KVJL9y1bNeSc9S2RKVynbxWbKyTMlUoiiREodBnBlOBDDAIAMXN+fUt3OfsN8f\na/fpBjkih+QIJDC9qlDoe/qcffbe5/Taa3/rW2sprTVd6UpXutKVu1+sb3QHutKVrnSlK6+PdBV6\nV7rSla7cI9JV6F3pSle6co9IV6F3pStd6co9Il2F3pWudKUr94h0FXpXutKVrtwj8nUpdKXUtyml\nriqlbiilfur16lRXuvKNlu673ZW7UdTXykNXStnANeBbgAXgBeAfa60vvX7d60pX7rx03+2u3K3y\n9VjoDwM3tNbTWusm8D+B978+3epKV76h0n23u3JXytej0MeA+Y6/F8yxrnTlbpfuu92Vu1Kcv+8b\nKKV+EPhBAOXGTsf6BwHQMYF6lK1RFVlXwlQIoQLArqqoDW3LPwAVQOi0P5MK5I+ajQrNBekgujZs\nti7UxBMeAIG28D1z3FftZc3SEJj7aoiVpI+Bq9DmnlbWx/fNBeZcOxYSVqU9bYHlmXP9dl/DWHtO\n7LhPUG9PvZuUC0Jt0ULALKXxm61zzEGtora1AtWBlmV6qgA4KsTX0r/dWhLLDqN5sJq0+2imKHTN\nsVhIIuYDUK/EUDEzmQ0LEnKybtqkUg0Aar6DKsuYw1RILlE3x12CUO6vtSLmSJsxc8NSLYHy28+W\n1jNLhmgzn8pTWL752gadkJMKiRrFRlLa9hXK0dHx7XIKf3OboFzpaPzvVzrfbRv7dIrcnbp1V95g\nUqdCUze+4rv99Sj0RWC84+895thtorX+MPBhgJ4jg/odv/4dnH3pAKH5keYvOgQJOTe5pmnmpM+7\nD9axV+PShqVJLYmSqOwNcUcrANhns3j3l+Xi6TSY4RZObgBQa7oEgVzn3chGSqI56BNbk6GrEJoF\n6YtOhmAbLekrknOi7VKrms3TopASfTUaFdHOE2Nyn2yswaWFkWjMifOidNwS+Gk5ZjXBqUnb1VGF\nuyvHS4d8VEP6mBovUVmRC3r2FCld6pWuDBlN3LTIXZE+7R5vYm/L59hkiX19WwAs7+bYWc8AkK7a\nkJNBWxsu4/cvyznbOdSlrHlA5j8L0g/IeLZnezh0bAGAuU9PUJuQVcROe0wObQJwY3YI6tLv3vEd\nGp7pi+OzW5bxW0qTNgvASE4GfGNlAOcVGaOX12jzzIJsgLttFggH3LJ84dQgNyPPZ/ugRXJEnoNV\ns9DmWYUFn+NPu1z50w/xOslX/W7nVK9+RL3r9bp/V7pymzynn3xN5309Cv0F4KBSahJ52b8f+Cdf\n7gKlNDErQFsa5ckPVlvQLMgP08sowrh8zj+fwE/JdfVTNUopUaKjUxssLffIFxM+lrG07clqpDzW\n18RScpMeLY0RJjTU5XNy1qXZK0rC8lS0W5iYWGe7KspodyVLkJTjTk2TnJepqlkJ/vFDzwGw3MjL\n/eoZjoytAHB1aSiyequjmsSGuX8cAtMXLxOSWBNlaKU9tCdjq5biOLsynu3NDImanJ9/Rr5PrQfU\nzVxZ8QBrjyja2kaK+WdlzOUjTZK35PzauI8qGkW7bbHzp4IahGMaDsuiyKyZZA1bSzIeUgETGVkg\nru4dxapIn6xMk9l1mXtrxyE0O6H9PZtc/Phh6fekh23GEF+xqD4k/b0yK/oxu3cXVRKF3hjQDB9Z\nk/muJSjHZe5z5+Oy+wJKUyGO2cHVDzawV2VsQTIkvin3SV92KU3evgv6OuWrfre70pVvBvmaFbrW\n2ldK/TDwScAGfkNrffF161lXuvINku673ZW7Vb4uDF1r/ZfAX77W86vFBGc/eRTnWBnrWjo63rJo\nrVDjGXghXI0TGIsrDBSJFenqUrIHyzXAa9EltOX4+MQ6W8a6TmSkjcZaCpWTz7nJHbwvCIQR39Zw\nSqCaXKqOY0l7868Mo1q4uNIYKJpmVtEYkHNUzeYPXnhErh2UNsq38qTn5WT1UAWnJtfFiorUmly3\n/K0+mSsyIKeqqA2L5Zq4lIzw7PK+DlC8ZhMajLjWL32yPJtAUCj0Tgy/dXo8pJmXP5KFOn5GJtTO\nNSMfQi2tUNNy/3CiTtbsZopJmbPsLYsgaSCPmMdnPvUmuWdKR/6M2Lk0lSNynTXQIHVZrj2/cpgw\nJ/c/fGCJq1dlJ5BcVwQGww/65DnsbqVxR+Xc2LbFzt8OS1/rEOuV4/VeTXPEOAtCRXXYwC9LsWgH\nl71pU56Qtt2yRXPIQ7uvXyror/bd7kpXvhnk790p2ik6EeIdqaJm0xF2WhvR2OJPY/CRFRbXCgCU\npoLIQRqbTtIYEK330MEZRpNFAC5sj1L3ZQiz8/38yCOfBuCvVo8DMHclA/1yXaUaxyArlCYh7Qq2\nvHVuAPugKGa7rihck3O27gOvV85p7LqRQ9Hv83DXDYwxKm0fvH+e2e0JAJxX0pT2y3XxdQdlHIR4\nFo74Lakcb2LH5Np0tsrWoozZqlv4hTZWH7smOPfuYdOPfovYtrSXu25HC16j3yJImQXi6Ry01sqY\nj3alveBmhprprz2foGFw7kPvnAXgejhObMdAG2kLvU9WJfd6ipjB+1OrIbVhGXuY86keFOWuSu3X\naPZvJ8Ao460TEBp/w8jQjoyllqCxJtCOConmNYjf7vi24tLX0Lfw9sp93ISPYzzBeikb9bd0rImy\ndeRD6UpX3qjSDf3vSle60pV7RO6ohY5vEa4nsGxN6BqnqKuxq7KurJwdJjSQy8DUFuvLYskFDZfk\nqFjRl9eHeKmyF4D79y6QdeXaYMTiV78gLANlrLvksV2q24ZxkvaojslxFSqyvyFOxOK3hOSTYgFu\njMTYGBMLMH4rgWUct42+kMyc3Kfwpg0WtoTRMlkQxsfF1WFiD2zLfT5WwApkWnO3Qry0gUuqVkSD\n1Br2DorTcX6jQGJJzg9dTTMt5/ieTf2IoeUYNkdiskQ1JgwWL2fh7pq2m2DXDAtoLIz67W2kIidr\nkNS4A8bqns9E0Mn0ar8cG6vQ6BXrO51toF+QuXdq0DA+aC9jMXhkFYCdcorGkmwF3F1FblrO2T4e\n4mTFQk9ddvGn5D7fOnIFgP/1O28n81aZt8Tv9RDfkTGWR13KMel3cLSMMdbF8l40UNrBGqVFeW6O\nS7Rry16MUR3RQkHtSlfewHJnFbql0YmAUFnEJ4Rl4c2maewXzEXZGsqiVLRWEUMlPa8o9hoqXNnB\nNuyPlzf2owbl2pN7Flkvi3KKzUsb1VGHRJ8osWbdIT1eAqC8kmHhu0SRaN9i55U+ABL7yxweFNbF\nhe1JYluiJO37yux5UCh9F2+MYY/KPedLApVUt1K85cRVOfdfLfDMkycA2J20okUkuWRTHZJpUCWH\nhecEZ/YzmjAnWLA9XkUZfrpfcckMySKWT8r9Fmf6sftEQTpugO1I2961PHFZT9CWReF6aO7v0Dwi\n49dNi2ZZ4A8rDqoq9/Faz0YrUnk5t7KWJmdgsPqAxhuXew78TZzt48KKaZTiJMz8eNmQ4sEWm0eT\nOi/n7N7fgKI8t9+7/KCMazxErxnK5Ht8+p+SZ7VzBLLTBkP3M3jGJ6A0PPSELAYvzo9jG8aLl9Ek\nl8xilYD0Upuj35WuvFGlC7l0pStd6co9InfWQg8U9q4DSmOdESvNymuSr0hkUeV4Izr1aN8K83H5\ne2VxDMtEK6YvxygdNFCEG0YW/dkbE6geMdHqGVmnnE0He0buE+71KZtzE6sOvmF0aFsTpA0n/WqG\nm8bqDWMhoYEAhnJlGgZGUW5If49Y+o8N3gJgMbeNH0p71dDmPe95EYC/vHoCXXbMfewITlG+In9d\nhrB1AuLG0g3LGVTeBDllfXpSYjEXazI/yf4q8c8K5FDvh+p++T4/AyXDkAnjmuKUtNc4UEc35bOb\n8ImdM95SRRQHYG22QkUVRw/OAHAxHKE0KVa2ToSkM/IcNt8UI6zL+cl8nfpgew6TN8zOIgfpRdOX\nBxuoM9JfP2nukw9RNRM7ULGojEo//B6PtOHm+2kbZRziteGQF546Is+zoqKdiOXpiPHTc91j4z63\n6xTtyhte7qhCt3xIbCosT3WEx6uIctf/2Rib98vnjXqGmfkBAHpPb9CYNlGTb94ldlmUtHZtQkNV\nyx7YwTEUuVpTlIe3mqNy2CwSNRvLRGQqD4IeQ3kpNMkXhH6yW0rCK4Idp47tEho2xtL5Yd70qGjg\nbL5GPi54RJ8rsNGz6/tYmhPYxkr6nAmE8WK5Ia6hTQ69bY2ZWRnPI0eneTE4HI2/ukcWKJUKiKXk\n/OZqikJCFPbiRcFqwlRI7YQ5N+mjNkWj+SmFmhB4JnYlQ/OgXGetxSM2UXw5Hj2HRq8mvm6iU1dl\nHkr74MyZAwCk9+6y97gERqbdBmcv7wPA8RS6YZRxNiR/ST6XH69Gyr33nMXa2+ThjmcrrKbkWTWH\npN920Sa1LPeuDusoCjU17VIy2VJiRR0peqeiSK63NXXxfpkfN9PE25GFLoy71IbDiP7ala68UaUL\nuXSlK13pyj0id5aHbokzyy0r6v0mrL6qUIfEulzvT0aBPVcXhnBXxeTyX+4nZfK9xC9l2T4ulnhq\nySYwsEjpeoEgbyJ0WvlY+gNsAymECY1bNFv6jEbHTRtXExTHTCBOxcIxQTS1ShzniPQr3EhyaVUC\nYHKpOtcviSl5PSuWs67b2GXDtvEV3/3oCwBUgjifuHwMgPn1nsjJG7N8nJZF/WwWb7AdKNUwUAOu\n5tKi3FP3G7J22UFlxNLt7yvhDsl4t9eH0YbvHh4tozfEERnfsXDL7blXbxG8Ql0sECRkjjYfl7b3\n/7Zm9j3Gin+mwLUpYdO4PXVyxjlbLRbI9MuupLySITZidkefTxIkpN/bb6uRMruMxfUC4bBY4C3u\nvltSeAb5SWyoCMqqTnoMPiWft46D1TSJ0ZKauvi6CV1IzLXi+2N4++Q+TgXCTCDJ1brSlTew3FkM\nXYPVVDgV6H9ZFNPG/S41E3wSX3XwDwhcoJQmf5/Q26qHXMILAn/UHBVl3wsfrNCXEbhk4/khbMPG\nsC62qH0hQY/Z6m+5hK3IoskKlER51YZCdNIE3wBVE/Goii7WkCijngsWWwlZUdKJZnR/WhBOIkAb\n2qBTsvlfLwmjY2JineQVuU49WKRmlPXTzx4TBQT4p2vYJlgm21eOGC2zMwP05kV5tiCkcj2NYwKF\ndisJ4rFWwFGIc1OUeHPIh5Qcr41omoYSGuQDYg1ppznoo0xirW8/8QoAf/OuBwhGZf6qYxq1Lc+k\n92Mpto9Kv+NlRWjGYNUt/IyhWCYt9FskcEjP5Wisydy6ZYu4sDOxjYKujGq8HjN/ISRXBKpx6i7F\nA2YebkF1VE7Rro6CqbycpmmudUuK3HnpY/HhOrSyanalK29g6UIuXelKV7pyj8idhVxssZoTWxbL\nj8mtY7vgroil1RhrYhvnnTNRYWtH9uaxuE992DBbNGSvGqdn1mVxVCzTZFPRXBBmRnNCtuKJXAM9\nb4JfOtJkN5dSJA2zpNEXoluWdlNFM6LjIcG0WPpbjzZJXZd+bZV7Ub2mfQMteNPZKDtgakmRPClm\nadVzqfcb1kopjq5J43ZAlL7Xarj0vyIXL74jTnVQ5qJ/tMjmtkmDmzGkcEczPiCwya8c+Ajf8+K/\nkrHtWjQMtKE8C92yonMe8XmZH3+8SiIu5zT9BE5Jxvzp2YPyfUZzaI8EDV29NULchNXXBhXNfpn7\n5kgIO9JezzXF9pvMTmBYoQz7JXvLovKwyXFwPUVl3EBbByRdQ9oK2b0mkUphXKMfkLwCzrM5mkLr\nZ+eoxmqaMfQ0qVcS0dy2cqm7Zdqpf6sOVt2KUkV0pStvVLmzkAuC5WoL8jfl7+SGz+YJ6UYQdwj6\nROno+bQUvAAavsXUAUlPOz0zGCkJZ6RK2kAQFTcRLQwHJiXv9/Sze7EnRbnU0zEyN0zQkqWirbtT\nUSTmDI47oklNiuKJuz7rvkkVW2znckmsWoRjhh65KApX54Iop3kzr2g+bbB1B0LD7lBFl7jJ9+1l\nQ2LH5D7VSpyVjCgsq6HxDP69E1iRIq/eMGlt+zymrwmu/p3nPxjlPrHSYZTiNrd/h50tWcTSZ5NU\nR2Wc2USTWqNNA3FLxldQlTkrTG1z9YbgHOlpF8/AKaX7G/T2CU2z6Tuoz4vW3X6wSfqaSfblgvuc\n3NPyIDTsGy8fEubN8zT+g3yyzk6rGxY0FmQO1ZCm77wc3jypSC+a/vmJqEhI6UCA0y9zYp1PUzsi\nn+Oz8eh5dqUrb2TpQi5d6UpXunKPyB210FUsxB6pUW2kSGwavvlJh+peY8U2LHKmlFo1HidxQSCU\n8W9ZpD8hDsLpcIjEqilxtp5BG8Ms40N5yjgJDXNi6tE55rbEyi7s2aEyIzzw0AHLVHNKbChKk9LI\n4AvQnBYLdP1hD5U25dPWEu0iHHuaaBNC3yqBllhxogpEXg7q42LOZ3qrZI1FW+/XNMYMVLMQo7xm\nqB6hIizIfZxtBwLD7mjaZHuNk9KkGqDk0rNHLPvt1Ryj4+I0Xn1lEDVkMh8qTWxB+leeCKIcL9Xz\nPYQtKnomwMu18Ar5b2cnTWFILPGdMIcyjtXYrQTbJptiYWKHWqvKWsOiMmmqIVUtchJjhdJQMYwf\nb8iL+lIxAVb+egG35ZzuiARKn9xi25NYA7sOXoaoDXu7ff+WpV/NpEibgLRmXpO/bLNWpytdeUPL\nHVXoMcdnYnCLm2tJ6n3yo49vaxJvFobE1ka2Xars5ji+iaxc2ClwdV3ggMxghVpRIIjkuqJ8ULb0\nsVUnUsBzK6IY3rz/FtdrUsM0DBXNo2a7vhaL4IrdI0Gk1KrfXaJ2TRRw8maMhsG/G70B7q7p70wc\nxxT7qQ2bHCx1oupKWhHVGi1vp7AflAVKAbZRRvVhHzcvCjicT0fl1hqTDZy4UZJ2B4SwbJgyrqZk\n0t6meqssTQufTw02eWxSNOqljXbFJPIe+fOixTcf9XC2zBeKKB9OK+d6UHHYqZscK/EAd1auC+Oa\n2JZMVjHoQWVNXvhA4Zo8Oe6tDOun2/1VQzLPybhHrcXguSDtlU82sA00pgB/WBa50uVeYgYG8tOa\nmKxb1C1NkJc5qdTiWJdE0ztNoufQ94rP7sQdRw+70pVvOulCLl3pSle6co/IHTVrGrUY0+fHSGxZ\nlB8R627wY3GafyZh85lvL/K+YfGM/Up1L/4+sfSCuotrtt3OywX0QbEG632QvilWZ2Wvj70ull9y\nRdapF+PjjAyIqbdVTpG8LJaudogCa1TJxjkhuwKtFcNfkLbXT1m4Y2ICNkpxrM1WZj9N08AVCRM+\nb3lQNcUjyPkR28Ladegflt1H5bODUinJnL/+qImUKvhkb5ngp1iMR94pKQaG4iU+euEUAPlbLcaJ\nxp2XrUB50ufwEQnPt5Tmxo5Y6ztzBeL7JRDI32wH/KSmY1SnxBq2iw6OgSc8Y0HbaZ+gLmN0V2Jk\n5+T78h5Fs1fG5gzU8BvyHOIpj7oJvdc9OgrICl0INuU5NBsJDv6JSaswZZhJt+J4xsrXCrRhrfi5\nAN/AWtlrLj3XZefV6I1HOzUr32gX9O7xqFVaaYdd/FS7QEZXuvJGlTu7T1USKBK6mnBLfvTbhy3q\ne0XRpJ8t8OG/fR8gaVaTrwi8UB8Mie20tuPQe95AF33tiNPUvIN3vygybare62sZlrKCVQ8dWqd4\nWrpxcmSJs5+RXCpOVRGeFQjHT2nWJCYIt6SoGeXlJH0a/UbZFS2cMVFSNZM/PP9CPIoCxdLYpkRe\n6Niszptk4vt8KiYPS/xmAtfAGF5vQGm/UVI2vLNHUsX+5txjvGlyHoCXt/cDkLthUXxINLHjhlxf\nNHBSyeXdp6Xk5QVgdVlgI9VUFI+KMtYpH2etXQKvBREpQ2u0PAhMdafkiqK430Ax6QB3UBbfMLDQ\nJu1ucytGYrsdeRs7Jovigb4Nzp+bNI1rNk+kovZBGD6txFvJVYVv3gMU1E2ZP6tJBKEEyXbyNFdp\neg8KJXR/zwYvfuGQ9Csu/3R3v9mVN7h0fwJd6UpXunKPyJ3NttiE5KJNoz+MnIxOFWLLYunWB0Pi\nGwbG8BX1k2IZps4k8Q1CEaY0jgkSKh9pRvBGkLRJnRXLvDZiLOR0gFU2RZL/aoimgXmeP3cQbepe\nNj0r4pCrvgbat6LjtlnuUqkGZXOfZtwhaRyWk3uFG399axxlfIJqNU5i0zg5ezR+r3yRvuXQ/04p\nnrGdS+K9JJa7Ltr4/dKXA/tW+dkz7wXgPQcvc3ZTcsbYw7IjKBbcqH8sxzn1uMAz5xdH+cxNCRAa\n6t0lVZBxBlmLxpZY4N96/BJ/3bgPgFOP3+TFackI+Ym3/SoA733qhxnrE3hqvSfDSEEYL+u7Geom\nTYKz5oKpeapdjZc1halXFXpLdjlzj/lY/eLwDZoWO8fk2fa8InPSfw5WHzOVow6VqC2LI9Yt2mAc\ntF4GdvcY56unSAwJ9NVsuLgmvfEL0xO0yhpVh0PGjq+y+LvdChddeWNL10LvSle60pV7RL6iha6U\nGgd+GxhCCH4f1lr/slKqF/gIsA+YAb5Xa7395doKY1AbC1BNFUUqhg4RbS8zB5U9JuFTr0f8pomg\nbIJvsPL0giKzIlZa6pM2q48a7HqkTi009L4BsRDH+3dYWBYKY+zlGLHLYq02DtdwYyYh10IqikTs\n6ylzqGcdgKcvHESvimW6m3CxTJ1Mu+jQMMUabry018yRJsiIRdkzWsQLxHT0lzPEciZh2KNleg2X\nfuHlETDOvcRkCb8o/Z7fLMCC9PFc7xhN33C3TfRoYtmmtlf64RcCrm4Ihm5ZmuEesa4fGZhhqyl+\ng1rg8uINKQ7xN5ePkliW9l6qHcQ21ML3fPrfyOADxeItk9YwHlL6W6mb2jgWoDJyz+S6ojEp1/lN\nm+Ss9Kt8rEl8wTin17MUzrRxccuT59ZzRXYNAOsPyHhL8zlsk0ahd2Irwv5TKxYxUwu1skdT25T7\nYIE29P3je5dJTEq/zszuxbZC1FcZ+f96vttd+fJiJRJYQxIHolupUwFVlfcpXF0nrHcDCb5eUVp/\n+ZSjSqkRYERrfUYplQVeAv4h8C+ALa31zymlfgro0Vr/5JdrK1vYo0+95d+wcZ9LfEvu23ehyvIT\n8isN4sLpBmicruBti0K1qxZBVhRw7opLbVCudXdVFCBjedDsM3lD5k31oPGAhMnmZz+wQ/i8KIxG\nX7uQslNV1Ewa1sRsjPqoyc6YaxKUREkVhktROL0qO7zjIXFAbjdF0axWsxzrkTwozy5NUDF1NEeG\nt9koCgzUrMT4pw88B8D54hgXbu6Rfu84xPeKM7exkMExi5vXE2L3tOuHAnAxS2NKJuixA9O8MC8L\nykjPLsd6BP5Zquapm8Cqpd0cuYS0UawlGC8I4+byzVHiiybDpcmGWN4Xok3Aj7Y1ylSI+oFTz/IX\nc8flnHN9xIoqej6HRgRCunh5nMOHhXEzt9WD/bxEH8W3Nb5h2WQXTKrfw3bk/Oy5qNgRvybZWWgU\n2jz0rAlU2nzMQ5m0BjoVcPrwDAAvXZkkbhaoWFERxGDmN36R2vL8a1brr+e7nVO9+hH1rtd663tK\nlOPgve1+AJaeiGOdFOPivZOX+IeFlwA4EWtgm0AyqwMYCJF3IUBzw5Pn/Ic7D/PxW/LOBS/nGX1K\n3mH3cy+jff8OjOibT57TT7Krt77iu/0VIRet9bLW+oz5XAIuA2PA+4HfMqf9FvJD6EpX7hrpvttd\nudfkK1rot52s1D7gb4ETwJzWumCOK2C79fffJemBcX3k/R/ET6mogEF+xmPzqFiL1TFN2hhY9X4I\nDooz0L2conHYVK8PVJSrO7ZtRUmZdE8TimJRt4pk2MM19JzQ5vxsgF0QS1yvJug7J+cUDxJZ6/Xx\nJo4piOFnA2J9hgfv2wQmdN3edRi6T6zxd49cBeDJ5cNs7IoFP9ZbZNE4CINbGYIRsS4KhUpUIu++\nvmWe/bOTMuZ9HsoU23ASHifHlgC4sDRKsyTjnNonlvDcmTF8k7xM1e0ownVo/wZ1kzN9smeT0aRQ\nCM9ujrG6KX0Jt2MM7d8AYCK3zXPXhFqYmJFdUH3Ej+qMxjdt6iapGAqIi3Vtb7lYo/IcvJrL0Unp\n69x2D1WTqIy8hzI8dLuhcI1F750UuClYTjJ2XOZvca0QZay0n8njVGRAtWFFdkY+F/dL3ABIDEBq\nSWyQ8pRPat7w0E+VaC6kWfqFX6Ix99ot9E75et/tN4qFrlx5tjvf9wDlD4jj/DdO/SYnTClIWyk8\nLe9LXQcklKHn6tuTpwV8qd6JLHilcI3H21aKupZ38XIzxg+e/2cApP4oT+EPzwCgvebrN8BvUnmt\nFvprZrkopTLAR4Ef1Vrvqg7AUmutlVKvujIopX4Q+EEAJ99DeVyRWtY083L9+skYrSuzR7YoIZh3\n6Gq0gVzCnhBdlBdJxwN0TF4OL6OitLXOQpzUCYE5i0VR4srSBAZGyIyUqdVMG71NNt5p+rcZizIC\nEihCkzdFBR1paO2A5HWTpvcd62RceYF6TOz5ymaeYcMQmZ4bJGPy0Tz81ossV0Wh3pgZ4p3HhWP+\n+Zkp0o8K1uFV49iOjOfU6AIX1yWb4nv2X46w8BeePCr9UETpT7StcU32xmIlyYEBUdZHsqu8KT0r\n9yz1E5iC1nZfGBXSCLUinpYxWCdlvB/Yd5m/nhO83Z0IqK+ZNAC2jrDp9LxFrWEI7H0+l68KbOTm\nG1E63qBHk98vz6F0uTd6tqkvpE2/oXlE+p3KNPDPFcwcQ/GQnDxybJXVlGSszN6CI/9M5u3Zs4ei\n8SdWHGqHTbZFpHAKX2PCxdfj3U6Q+tpufheIs0fYVlc/OM7Pv+/3AXh36nORAq7rABCDwsLC0/J7\nCqPvwFWVN44XAAAgAElEQVRWdH6AxjOGZNBhULayH8dRFEN5P1NWO1rsVDzkpYd+V/54CJ78aZnz\nH/rzf8mRDy0A4M8vvG7jvhvlNbFclFIu8sL/ntb6j83hVYNBtrDItVe7Vmv9Ya31g1rrB+1U+vXo\nc1e68rrJ6/Vuu8Rf7ZSudOWOymthuSjg14HLWutf7Pjqz4F/Dvyc+f/PvmJbWpyeQULhGNLDzgmf\n1KyJPjzbh7/XZA3cdSPnpv9AiUbZ/GCaFvnLcn5ljyZmClVUpzxGTPm2FsukspGKohlrYY7EpFir\n1fVsZOUn1y08kyfcPbRLddd44LUiNNGfe/qKzI8a6KaaIBuXPv7ZkjiChvuKHDVO0eWNPDnTjxf+\n6gRBUiyQ3NEdzm+YumrTaVIPGEeo5zDVL1kTl6u5KDnZ5xf3R+XoPMOIIeeRzhrWjBWixJhnJLfL\nB4Zk+/nXm8fZ9WU3UYjXcCy5dm6nQMlE0D70wCznArGue7Kym3ggM8uuKRby5NXDWCbDortr0TDP\npLw3JMyZ5GGJgKSBS6rzWcyOm9j1JLs5eVa5W6B0q0ydyZI4rPE/L+wcFNTHpb3sDYeEiUFYnO0j\ne0gcuNs9GRbKYsXbVYtGr9ll2DAyJOeMpHe5/tShKBr1tcrr+W7fa2IPyTO6/NP7+PQ/kKkZdeKU\nwha8YUXWdwg0DCxS1u2H0NSaRMdupwW7BGjc1larFWANkdVeNe1+8XWebpK1YtHxJxKyK375e3+J\npe+Sa97z8Q9y9Kdn5D6rr7oO39PyWlguTwCfR6LKW5va/wt4DvhDYC8wi1C7tr5cWy2c0T4wSfGU\nvDAbJ60oV0d6waLRY7bdz/osvs3Q9jIB8X6D3S6lo1wtzfsrkdK1p5NRselCRs7dPjsQVb5RAdSH\n5aFbPc0IItnYTeMYyKNei0XMltimjd4vkEoYWgQ78iK5vXUCXxaMmMmMGHN9HhiWrd5nLx9CGbxd\n9TR59yGBC76wtI9qVRTdgeH1KA2sry2mb4hmzg6XSMflB7P+ymCU7qC2z1AmUz56XdoYOLRBpWEq\nPTUcLFMgObyZIXFUFN2efJErc9L23pEtZqdlzlMDFSZ6BRZZ3hVGytH+1UhxJh2PowVhzaSsJh+9\n9iaZ72I8qrSUP7XBnqzc5/z8HoKagVGmY9SGjF8j45M/1/aPtCS+YbD6HU1l1LBmDtRJXTI01Ue3\nKS0J5GMXmgTFNg2yJe62jWeKgltZj7DisvKzv0xjduGrYbm87u/2XS1Ksfxjbwbgv//wLwNwf6zN\nStkO67dBJK5R1iFt6MRWiriS80thgGGtUrCsCDcXKKYFucj3Wav92ELa0EHnZ0/rCIKxUV+Cy0uf\nLF5uyvvyr3/thwEY+dAX4KvwFX4zyuuGoWutn+K2n9Jtcpe/wV15I0v33e7KvSZ3NPTfG0qz/M8e\nI38roDwqK224v0pvTrb93kx/lDFv6QkHv9DmnLYq3PccXqdxRSxN72YKt5WtL6kppAQa2LgkATKu\np3AFZcFPg06KRTfcV2T1ZXG6BemQhuFcW/GA3LBcUKnkmTT1O+e+sIegT8757sPnOF8UJ1GrkEap\nEefylrTnLsfwTHh8f0+ZT9+QJGDKCqNEWFMHNzm7IW0cLKzTc1zGf2V9iLGMyQ65N00tL9Z4uk++\nb17J4Y+KBR9qxWBWdiQ7ToLtaXEmk9LUzE7g+rUJjP+WOdUbFa3oy1SZygjMc/mKQC8je65hGd/f\nzG4vJU+s5Wc2J2lWzO5kw8E3penSsSYzO3JPpTTOhmEHpTSY3YKq2dSGTZyAKShi18Eyj7UyqqLP\najNG7bjsrFQlwfh+CfDqTVS5keiPxu+NyICCpAUGNvu+Ey/xpzdPotxuGbqvReyDUwCkfmOXj04K\nvNKyyquhfxsjxVa3W9Ig0Errsw00IogEbHO6h6bZsuLpcN6Z70uhxjWfY0pFDlRXKUphEB2P4JeO\n+wdakzC7AlfZnDK64pkfk7H8b//wfdT/d9nxBdenv5qpuevkjir0MKEpHfUIY26kaG0nYPOWyUh4\nuk4sKfBC4NukXxbcujYUUl8VOKD/zYusS/JB4lO71OflQSWXLTanpZ3Mstny7fdJLRscPq2iyjfb\nhWQEZwQNCz9lto6DIRM9osRvbvQw96woO22DU5J2/uDZR+kZE6W7Myd9cnYtMLVL/VzIvoOCp8/M\nD+Ca8YSLKQZOCqY3kdhkYFQm4Ed6n+eGUZ7/d/P9XFoViKRZdckMCOTTUtADp9ZYmZFUw/2pSjSv\n29sZ6DGUzIqDb2Cj/LwiNGhFkIwRZOSH8a7hqzy5IgtNatDcI4yRcwWzf/PgLf74ksAs6UydFlXF\nG2liG1rn3MWRiGGUv6bYOSznxIoWloGkkittRbD9gMzDW+67ylPXDwCQPZugNGnyuvQ2IwiruZhm\n/ZpEqq4cqTAxKGjHwkGL9Gfkedf7ieiRf7z4BI0Rr53npiuvWSrf/Qg/8/P/HwCn4pUIx25RBW2l\nbmNOdMIfLaQ7hAgrb2odwSyuEiUMUAlvZ7O022m326mgK6Yfbsf+qRLqaIGAFq9GlHtWtXvpmZ61\nFoU/2v9Jnv6kfP/vfvL/IPNHz325KbmrpfsL6EpXutKVe0TuqIXuFhV7/sqintcUpsUaXI1n8fbK\n2jzwNzFWnzABPGWL6pjJ7OdoPLNUz7wySotSUd1IkdwjsEMlnsKuyPrUSh+gMj7lPaYwRSokNEE5\nE73b9H+n5Bp/+tljUYBOoVBhqya7gupeP9rSW7sOmTlpe7c3xP+cWMlMSP8OvHk2ci56cZ+ZWclZ\nYScDvF2xIjNTu5ET84WdCf7R4FkA/tv2af54RtgyTd+h3grQSQS06M8HTIj91dlhLJNXperF+K4x\naePK3DD5gil1V9Bsr0hfyvvCKEd47rpF8RGx4v9i/gS7FdkVfP8RCc1+an0/ezOyOxmIlUilBb4a\nyZbwXzA7KAvc04ZjvpNi75hw32cTw2gD5/i1WJS+oPTWGiPG+bw9LXPy3JPH0Qa+2j3oo1IGBusv\nsl2Wuc/dsNg5bdg8gcUT/TcB+ExwiNkTAlvFtmya/a0ghBCr7LSJzF35irL4U48B8Okf+k8R48TF\noahNoNdt7JSWtaza/PGOtiyI4BSvw/foaQg7HKFN8zLGCCNLstP52bK4baWwzXUNfbuV3jrfBuq6\ndX6b7+7pMIKIEoYRU9NNHozJlX/zoV/loYM/CsCe//eZLzdFd6V8VZGiX6/E947rkZ/4t/Sfscjf\nELx0+gMJtNPugzZRk3bWI6iLch8f22T+llGSZSuKFgxjRLhrMt3EuyiKrJXsq3ZfDWshYc7VhCmT\nktVXUlUa0E2L44eEoXLxyjiFV+SeOw80UYa6l522qA2ZF3NfDW0iUd937AIAn1+aYigjC8uB7DoX\ntoWeOHNzCKtq+poNiOdlpWmU49gm+tKyQt59QCJOJ5Pr/NcX3y7H3TAqgD01Korzh/Z+ht9cehyA\nmO0zXxLIp1yP49rSXsNzeHRMAos+89Jx+vcJXLE+20NmRPp4sG+ds5dMEQrD8JnYu8HbhiQd78dm\nT3CgV+55fmkU30AoQdWhZ1CgouFsiQVT27VeixEumEIWPtECqffVIvjHqrUDRAZelP93DqkIWw8S\nmuYeU+gkX6dmcHutVVRpynp4h/K6yanTsLDqMrf5I5uUz/Ux/18+RH3xa4sU/XrlbmK53PjFR3nu\ne34BaCtrgKzlRJTBesfxFhMloaDaAZG04I+gQ4WEQGAWCBvdhlZQ1LXdcdxAdKpVvKS9GMQ7nmDn\nAuGqKGMyAe3PnZJQFp5p24qus0ioL7Vdj//PH2H/jz/7Kq1888nrlsulK13pSle6cnfInS1Bp8Gu\nW2wdh+J+2TrbdTkGEKQ0zrpxYiYdQsNP3/zsCJbhNocuNE3tycaIz9TIZtT89Ii02TTLlOsE5E/I\n9+VaHMsE2dTnsoTmpFRflZN5yRR4KTFKea/cf2CoyKYr8Ie3lsTrMZvMssvpo5IKcKUuO4LHR26x\nUBVrea2RZdxAF7PBcBSIg29FIfTHpxYjB+S55TE+MyPFKQYOlRgZlmtXLg3yI+/5BAAbnjgCP/jU\n9/FPTz0PwGK9wG5VLNdGPUbZjGd0ZJvPvCCZ6vomtynXxKEa27Ypx8SKPje3HwzjB+NInFvq43dW\nDFNm12XdBDU1SnEO7BMn783FgSil77XlQbJpkyZhOoVlOPveVoKBCRmD59t4CYGIPJNJbyBfZnNL\nHL+NAT8qR2eXLOwtU1v1ZpyE2Z1Ux32qJk0u6+mIFbH/2BLLRZn/3VIKf8hHu3dut3k3ys3//CgA\nZ773Q1H8Ridp84sDekBgkBZF3KNtfQe0rWeXNsslQOHScqxakQWeUJoWUONpi6zVZsLIue3rSmH7\nus72pI/yv0UbYbNoW+tex7mtPoVaU8ePPseNtX7++36Fk0j66LvFUv9KckcVuoqFqL0V9EKK1EkJ\nStnZyNCKLYtlmlim6pDlKCaPi6JdGs2TduWBlNYyhKaupZtpMrsqeHYy1cBNm5ZmRXFp5dL3kCj0\nvlSFqzcFCsns240of7eujPCRqik2qjTWhCimnd0UjsmZHsY1QxMCXTwwsMCnDBXxyKgouk8uHGXI\nVPhZ3sxHuLHbX0PfEojAaihGD8jxA9l1npyTvLH5dI0PjJ8D4GxxL98/Lpj21kiai2WhNj67JNWF\nrKLLH7wiRU8fmZzh+JAE/8SsIMoBs1tLkN9bjMYQrojSH3twheWX5Rw1XsXfkOM9+0T5Vutx9ppg\no8awQ8UEZ9hJn6UdUZxv2jdPwpbncH17gO1dmecH336V514W5kpsy2bdEszdLdTx66Kk03mBxpqB\nHaUoBlAGcklsKpqC4NAshMRMhK9qWmhDR1RaYdXk/JvzgwyZSNEgsPCtO2ub3G2y8O8e49z3C43v\ni9X2q+HiKdXK09JW1p4mwrYtBEYBqGobtwWdoKPjttLtBUATKWZXtQOO2swWhWcAAwtNxWRkS6h2\nr0LAENKoavB0C/vXkQ5JvArFsq5DErRojdZtLJjz3/crADy08aPs+Y93P6behVy60pWudOUekTtr\n1iiN44TUE5rdmyY/hwY9JIyG5maC5gFxjKm6zUZZrFtvNk3qsIm81uANyHo8NbDNVkWsxMFMmQ1H\nPu+MyTqVztaZ3RQY4fTYPFeNOfDwyByfvyVkduUrwopYkXbZwjeBMGHDxl0zaQB2Ffvycv9PXDwe\nBc60oJr1appNw9AINuPM12XXYCd8gpyxBio221WBhD6xdZTxPrEu5zZ6+ED2ZbmntvijhQfMZ8Xy\nhkl92zQbynTQujUX14fJmOIV2+UUQ3kTENWMRX1NDHp8viFwzsKNQZSBJFRoRc7IhNn59KZqLBmm\nTibRYGNTYB7LCWnUxVq/tjFIbU6Op/cV2T8kjtMzc+MRzLKz249tqjsFSyl0Uia9XJedV9kJsXMm\nOGozHmVjrA9owhGBcHK5GqXrhuM/VCVpYJvSYo6wVYQjVGyeNQFmvQGJJQfV7LJcvljK3/MIAM/8\n0C9gRcBESMPYxnWtI2s80Do6o+UUDWnDIkGHY9P9otSWgVbROZ3SCZ20LHdPW7dZ9AAeVmT920pD\nR1h/3bBjbHQU/NZ5T1S7nQBuC3KS9hT1KCCpfb1ANXL8c//nf+L9N34M4K7mqd9ZhV638W9kiU2V\no3wrG5f7SVwypeF6Q7KGZVI8HrC7JkogUbbYWhdlE1t3ooLMi7l8pBhvrfXhGcUcW5H/GweDKMfJ\n01cO4OZFAV7dGYyCWCrJANVssWY0sZvSF7cM9T6DBT5QJe9Kfy03JKhIH3dN5epcrEGx0i6T9i9O\ny9btz+dOkOyVZFvLG3mqRjGmk40ogVgs5vPfNt8ilyrNTk3arNddrEX5bBsYKJ1s0jSMk931DM2C\n9OP+0UWef0kUd2zbxnq3wEyfv3IQ6nL+oaMLHMoJ/fEvLt5HakoWgFY/RvIb+KHMw2oxy3uPSlWm\nv7pyDDZN5ah9dQ6eFLqn1oqyJ+PxmzZ+YPwgcU1omC2ZFStKk9w0VMXUzRi1Yem3TgQEhiph5z20\nifq1rJDhE9LXpdUC1VlZ2O3xGj15mYuNzSxer7SZXHDov+CzWOti6J1iH5jkZ39OgoY8HeK9Sn5h\nlzbk0vltG9u2SKgw+tySmAojGiJAwyj6ToVro6NzQtRt7BevdW2EsQfRYmHp2xeFMMoZDcWOe7YW\nBZt2wFFaWVSM8m6+GoOvIx9MeFteGotf+Pn/AsD/c+577tqI0i7k0pWudKUr94jcWadoIiB+uEjt\nZo7Kimzdw5N10kdMWtvFAvUBs72qWMT2i+NS3cwTWxSrL7muMIgGwUyG6UWx3k49eIPzC+JETN0n\n1/mhFWUvPD02H9XavLnVTzIm2/iKrcldN4UiTnh4++X8kd91WH1I7lnfiPPM2VNyz2MNxvaaPChF\ncTLeWu1rwyJZj9+/Io5L1w0olgSKcWYSpO+X68Zyu7zyijg6nb5aVMji/MYoVRPwY9lBVHiaVWnj\nLY9fZjAmc3WuuIfliuxaDmdWOTtkik0sZHj+rFjrw/s38I0Ffm1umIUrck81HFI1z6RlpDx9Yz/u\ntOwysqc3+NyCQFJ9vWWsPrnngwPzPL8mdUzX53twtwyveF+NnRmBSNRAg+N7xFl7LT+Ib9gt8Vsy\nrmZeRwXC/dAGU9A7KDsUTB6d4rVetvtNKoOaQ2igotjVFJWT8ty0Z1EYkd1Pdb2HtQcc/Oe7kEun\nxH69yv0x+S1YyopyrHTmXoG2Nd7UVlQEpQVnhCiqus34bsEiTW1FlrOnrcgyt9GR5VzvuK7e4Tgt\nhTESyqRh7oBAOmEcuxNaiQpptNtIqCDqYx2bhHF0Bjq8LRBJxtC2XOsaMLlhOjnrcRQnjE5I/HqJ\nylu5K+WOKnRds/Eu5Emc2CX3nImIfLweYb4p12O+LErSGq5HeVockzscoDxlk35BFE+pP0SbwJgz\nNydQpsTbREHwXEuFPNIzA8DTW/upGIhgMFPmYE6SP318/n6KbzLVe4oOqmgCiw4o6vtF2QwN7VA0\nucKdpsO+nPT3O/slUvMnp7+XsXFR1sVagkpJlJdXdyj0CETQOOoxkhWFdWlhhMFJOb83WeVz08IQ\nYSlB3vgKjvev8IItCni0R1grfW6F57f3AZCwPQaS0naPU+EHjgqd8bdvvYPRAzK2tZ1MlPhM2SEj\n3yJwyY3rI2QN66RhcsGHnk1jWF7oxlI+yiOzvpZjalzaezh7k49fuA8Qf4PXJz/Kt0/d5FxaFtNS\nOcnls9LvsWOrlP5ccrJEv1ulCExq+9jxIvXr4ifILCt2LPO8A0VsVk7KzsD2cRP5twnFBXNOQ7Fr\nAquYrOPGfCKu4xtcln9cokA/N/Wfo6jJUhhG+VZuT0l7+7UtJRnrUMotJepp6zYF3Fa0DinVzoMe\nYeHoNuauwuh4S5lLX159EW7RKl0VRp8TKriN9dK6NIYfKfG6VhGU0mLE2BCxYFzVZr9UdHhbvvZW\nQrLfnvoYj/244Okjv3B3MV+6kEtXutKVrtwjcmchl2RA/OQOlRt5Ku8yXu6rec6YWp8sJUiuG8hl\nPhU5Jb3VJM6AMCDCjXiUklWn/CgYxV53aBoLc64olttgpsxHbglr5EDvBkMJA1esj5HuFes7OVAl\nuGKsvqO7UZh7cysDxvlpKc3j4xJMdGFzhPWa7C4Klli/pw7P8PKcQB59PWXuPyDFk69uDbKxKrAI\nlsYrSNv/9MTz/M5ZCfLYTqaIx6Xf1v4mOzeElfP5tRyZXmm/xfa5me5npSx99Xw7CpT64/ophtMC\nP2SObZGJmTwoPZr/ePCjAPz7m/+ImxeFh+/0N6ibOfdMeoWpvWs4xhJbKWUpl2WXkbwZZ2ZHrvtP\npW+l0GcqLd3qRZkKUJ89f4T+UdlFjPbvsGLJmOfn+7AOSJu56/Jc6wMQkw0U5YUs2uTXKcccknPy\nLGujPol1kxnzWBileijtCyO4JnRMYXAgm6kTfKEHVe3aJ/bQIB/+oV+N/m7tWW63RDv/bsMvTf2l\nFrOrwttC9ju/b1vRwW2BSqXQja5ts1nCiGcOHWwY4+QMUGRNyalAq8jJ6nU4QT1tRdeJtS56oBK2\ni2fYHTuIzlwvr/ZmdO7nQq1vC7L6rz/0awD87O9+211V+aj7C+hKV7rSlXtE7iyGXrepXyyQ2lIE\nsRZtCZznxOlXmgpp3G/yilfcqNyZzvq458VKHXzbCg0Tfr6xlqPHYM71z/Zj+abcWU7+z/XWWQ7F\nWjyeXea3zolVrCsOn1HiOHzznhnOuGJdF3dSJNJi9cXfvElgaIZrW7kIr3askI2q9Penb7wPgKWl\nXt59/DIAnzp7nJQrlsbh3jUmC8aBuj7EWlks++PjC2RMdsQ9+SIJW84/e2OCRFHmZej4BqtFscYb\nSzJ2d3iebx2TknZ/ePkBTozJTqDYTFJsCMb/rj3XWKzJDsULbX5+/r2AJArLmBqt5bSDZaJg8eR+\n0zeGmTogzsxQK8YGhA66Opvgu98uYdFntsaZeUHmKjhY50ETqeoPtJ1il9eGeHSf7GaeuTXFnr0m\nI2NcOON2zSK+aSIC+xpR+oBSIknDFFpOLjlReocwpvFMbfEwpombXYF3PUfyiuwidvdbqON1wmSX\ntnj5P+zjlElwF2gHyzgLq2HQxpFp88wbup0MK6HCiCvejvBUkbOyqp3Iiq6GTvTMLXRHBKnGttqO\n1ZaFXcW5zXq2o6jRVl9tqmFbHbm3hf6Hpq92tBMQ3nqr8EX4Jfx3Ocdg/KGKqJdpS0Xl8qQAR6s9\nDSYHvKVUVCTj8n/Yx6F/ffdY6HdUoVtNSM9DkIDaqDwMd8ciLXqJ+FnF7pRJj1prP6BgI0Z1Qia4\neqs/CuzJDZXZ3DC1Jwc0jrmmPyfK9y09N3jhklRj+avYMRLXRAEoDd4lyd749GA/g4+IYgryiiGT\nEuDm4gDaKDs0bNREqyxfGWTwsDgJWxxuNFTMYtIzWmTzUwJR/MC/fJYLVVGAzmDIC08fAeDn1LfR\nbJqcKGf2cvIhSQ/79mNX+ZwjC00m1uAHTogi3f+AvFC/t/FmnlyWlAF+0+bWttB9KtU4j08KbzZj\nN3j2RUlN8PCD17iwIk7J08enOZMShko2V+PYgKQtaMEsT79ykKN5OfYDe57lP1/6FpmThOYPn39I\n5jjrYU/K3Grf5qXnpa+pyV1ijjwfr+nwwoI4Rf/9A3/Jf595AoADh5cBuHFjmJP/5BIAc6VeZk0W\nzeSCS22fLKa1LIyNyUK9U03SHJC5cmZT1IxTVA810cos3P0VanU3Sjf8RhRnjzil/+If/DJbgflt\nKYUbVfJREaWpMw8LiFKH21kuryauCiOl66rwdjjEbPY9bd/m9OxU+i1lbKmOz7QcmH7URl3btwcq\nGVUQVwFVkxKgqZ3bMjZ28tqDV+Gxt+CVutZRmt64uj3QKBqLDqO0v59874f44J7vBcBfWPw75+ab\nRbqQS1e60pWu3CNyZ52iIbhVaPSC8oxDpaLYeMiEx5etKLS7MebhJE2GtI04sR7jFA0sgm3Zmo/k\ndqP1tdSw8E0dhsUlcSw+nd1PslfoebWmS+OIfA5rDlVbrhzfs8n8gli6PQMlZkyyL8sJObJXrMqc\nW+cLF4VaOHFshaUtgXHiJto0lmny3PQ+AA6OrTH7kFiOL5X3cTozA8D/WH+MqdNCG3zbwHWuV03Y\n+h6bJwqSh/zXrryduClZl3PrPF+SnOUfq0kBjKVyju2iyQduaY72i0X94vw47+8TCuWndo5z8k0C\neTx3ZYqfeeJPAPiTtVNYa9KvgdENBuMCXXz8b01isnTA1d3B6Fm10gpMPbjJ472yg/jwp96FvWUi\n/zI6ym5Y3knyzqOS0713rMIfX5Tydb8x+3iUp721m+kfK0pREcAZraJMtsf6cMDjR28A8MyNKRZn\npI6olfGwHWNx7iqCVuh/oAjSYndN9mxx4cxke0f1BpSrHxwH4IDrUDXl3qyOGpwh7UyFrupIitUR\nzp9V/m2c8y8Wl5BQtS3rzsjPlLHKvQ4naqgtLNrRnJFDk6BNheywKVtWe6gtEpGD1I7gmRDVvi50\nI8u9M2K10zpvOXBvo1rqdvbIWIejONC67VhVSnY0wB7b4cqPmbn9sW9+C/01K3SllA28CCxqrb9D\nKdULfATYB8wA36u13v5ybYQO1PuUVAMyczzwrmVWPyvbRS+nUYOiSNLJJrZhcZQKFsdHRLnOFns4\nbuCFp2/sJ5cTJR3vqfO+A68A8NdzAm0slArkUqYy0lIhyreZHSxTnhOlvPriMAwYxewE5LKCbW+t\n55h+UhSqf6zC0B4Z2tJmHq8oC0pYlhcpd2ib9x4WGOGtmSt8JCX5M85vjvLypsAva1s59g8LVPOR\n6Qf4tgnB3He8JB++IbBEZS0dFXLe9RLc2BGlVmvKJvFg3zrpmMASxwsrfGZOFpnBQpkvlOXz2c2x\nqPLPd596iTPliWguHnzzNQB6Y1U+/pQoct1rFpBClXcPCj7/0bk3sbkteH/MDvj8prSdu2mx+6hJ\ngbCUILdfcPaG50Rb3q1mmuEBYbwsvzxMbL+wb06PymJWD1wqGzKuup0kPSc//ka/5sySCY6ai0fV\niHSoCFZMcJZNu0hJzeZ7npCcGxd2RnFLCvWl2V+/orwe7/U3WpQb49fe/z8AqQXaghGaYfiqRSA8\n3VaCttIRt7uzOEUnPNISi/a5Fe1En72OIKO6tjvaC29T+p1tt6CdFj4e0s626HakAbgtTUBH/ywV\nRvf8Yvy8kwkDouQ7lT63LTIiDQ1Zo+mbWpNR5r3UPr/+/g8D8HM/+SDaa77KjH7zyFdj0vxb4HLH\n3z8FPKm1Pgg8af7uSlfuNum+1125Z+Q1WehKqT3AtwM/C/yYOfx+4O3m828BnwV+8su2E4pjNDXn\nUAnWgOQAACAASURBVHirOCJnbg4RS8hq7ff4KLNtrlRSWMZa7ekps1oVZ9jh3nW2GgI7JFJNCqla\n1P5Hn3kYICppV9su0Hu/WMW5/gqO2f5XzvZx6Ik5AG6uDFAwTIu1jRwZY/FbRYfahMn86NmsLgtz\n5MC+VdaSYr1++4QksJqu9vPnMycA+NaTFzieES/vPx98iummwBifyJ6IYI65rR7+5IrAKP/qvqc4\ndUD68ouVd3PAWPGNwOFtIwJBfHxaClZcWhnGdWUMO+kktYrZKYQW/Xuk7abv8Ja9ApF8V+FFfntT\nStY9OjQTZZa7WR5ADcqY8yZJ2gf2vcyySUi+PtfDwF4xShfXC8zX5DWJD4BtSvo9/NbLXFgTh2u9\nGuOZW+J8TqUalHfEok7u340yNV5Yk51KpRbDul/6GruSoTIufdLJAN/UU9VjTRIzMjb/cBPf1B3V\n21YE1ameJn967SQAB4fW8dMa/VUiLq/Xe/2Nlu3vP807kk8DEhHqRparjlgcwRclqrI7QvU7Ldwo\n/D4qamF9EbdbLNe08tvWcsf3aeXflsu89V1nGgBLtUvQNToiSTslbNUf7XCwdvYzrfzIcreUjvot\nmRoNtz2KMA07uPZWlMjLo6NIh2on80ooRaOD8fJwXH4r299/msLvfIFvZnmtkMsvAT8BZDuODWmt\nl83nFWDoKzUSxqA6qgkSmh2TnVB5Cj9jtl9bTpQaN9lbw33aVKR5SLM7J+dvH0hxzNDl0okm82uC\nl4dbsfaNTEEEr1dHhZlPDS/wyroooL6HVyk3RWFMDW2wsCOK7ODYGjeWhHXx1jdfpBYI1DFT7GXN\nZHssNeLsbsqC8gdbsoCkCzW+fVKU+7zXx56YUBX/5+aj/NTQpwCwCPmZc0IhHO4pkTMvybXKMPMV\nWSwKuSpXF2Ua33P4MiMxgS5a492oZVh9ShTjC8cddFke3+joBh9bFOV2uHeNa0VZRH7fepS358X4\nfKE8FW2jLy6OsKdf4JJjPdL2r7/0ON9+QiArNFTNvIV1m2SP8UM4YVR16elzh3CL8mPUPQH5MWmv\nWo+jG4aq5iejFMTlfWbR3omRGJD2nJLCm5J50CUXTKBQKt3AS5pMjhUX2xTGLlyzqZTNPeeT+A/J\nwnDxxhhkA8nF/NXJ6/Jef6Ol8o92o7D1hLKjykO2UpGS6oReXAWWbina9ipYx/6StLgubWij0ZEG\n4DbIpUPpe7r9uf5FeHwYZV5sY/FteqSNd5vSNwXaVRty6WTWWF+USrcF11TDjtS8HVkiW7TFWMfC\n4ek2RNFZ9chGRXg6GsJWDpr3lyj8Dt/U8hVtGqXUdwBrWuuX/q5ztFSaftVfk1LqB5VSLyqlXgwq\nla+9p13pyusoX+97bdqI3m2Pxt9HN7vSla9KXouF/jjwnUqp9wIJIKeU+l1gVSk1orVeVkqNAK/K\nvtdafxj4MEBqaFynlhXNd+xSr5qq7vGQlMmkiAY/YzzkWUVtoP1b6r9/zbSneOnqPgCsXQfbFDU4\n8ugMl8+IAzCWlR/Xvv6tqGhDqC3ypk4mwL6s8Jz3Jrf4nXkJONpN1TG0XZ5bmOB7DgpzJGb5kTOy\n6rnk+mRhun9IvN7L1XwEZ1TCOH+6Ik7R7xx6mU9UhDf+9tR1ToyK4Vfx4kxlJODmsewNmnkZ85+u\nneLRoRk5x49zuSI7ig2TamC1mKV5SKzbgwObLMZkZ3FrqZ+fePCTAPz56v30JUwZPS/J/8/ee0ZJ\ncl1ngt8LkxlpKzPLe9fV3ncDDUeCogEpUiRlSc7KjcxIK0OJpHRG1OzszsyekcSVl8jRys2MtBIl\nOoFOoAFBgDAE0ADa++rq6vI2Kyt9RoZ7++O+eBnZ3SSAEdRoNPKe06eyMyMjXpi8777vfve7/7xB\n0M5qNSmTzD+390l8cYHeX6lRcJpuL6Pi0j3Zt2sWhkZRcf9wHhFR+PTJE3eC5YXUQpcJW/DA259X\nkS/TSkkvKogfoGi9Vg3DFsSZeISun/ZUFHqFzie/g0OfFiqMKQ+KEFqzriTh9gkHWdXARRu94oiC\nentAke+iEHjrcsAi7ssl4f6Lnmug+dlOssxNJ8EzjX6+f7H/7+BdE1kD1+uB+5fH5ZBslqDYVQhe\nk345faexjzBzA3xzRa74XDCYgeSn1CnnrCmiVwLFQpaAZRJC1KvOVehKQ+DLj8Q9zhrJzQDLRWUc\ndS8AFcn3GzCPLw0Q5JrrARkAnUFy0oP59ApvXE0dDfbLxw/8I35XIQaXr9h4q9mLOnTO+W8C+E0A\nYIy9CcCvc85/jDH2ewB+EsDHxN8vvti+PA0wOwD3UhJeF9286FUdjugN4RocqmCO1LUI0Csw7I0w\nikLvxL6chFC5hFZjYIcJlnA8BUqPoDZO0Q/dTJVQXiCH/vR8EhM7yQFPJNelauB/vffzaO+gpfv2\n9Bo2BC2wljdwpULwS38kjyfPULEO1Ibmw9NVwo3/7e5nYQr9ij+//AYpzfuG6BQyCt34Hzz3k0gb\n5Ix11ZXLxUtmL/7p6j75vq8O+T+n70K9Igpn0sS8sediYKKrT6FuoCow9J/d/20cLdJYtiTWMRYh\nHL5P38TfL99NY+mcwudnCZaZT2Twxu6ppnvzrs4zuGKS992ox7A7QXmAL83vwUaOrmc4ZsES/Vyd\nqiavQ/GtVSiij6uV8WBmRUOKvAa1j8arf50mn+KEB39lrVUY7ARdh/ToJnJrQvcm7iIsuhQdHL8q\nKaFO1ZDfVSyG3iM0QQ7E83j2me2A/dLlc1/J5/rVMvuN9Nzs1J+AKZxr9Ts4muC7NhgS4rk0AzS/\noJqi71CjSoORVuVak5JiENP24RRDsVGVWi6udNxBR+/xRrOLnGfIbT3Px8S9Jtw+yHIJB5gr/v6C\nk47KuMTOfXxcQQNaSrAG88dDQ+9FZ43X/v/pb6Mo6XC4DOdN5NC1R7/jwu5VtX8JcfdjAN7GGLsM\n4K3i/y1r2WvdWs91y16z9rIKizjn3wJl/cE53wDwlpd1NAa4IQ6708Ed26n4pThm4O52er1Ub8PD\nJ4gtApcBNVGMMpZDT5yi6LMLCXDReiw0qaN+UbSmu3cDO/opwXeeE1SRMSrI9lEpf7Ucxo6UaLxQ\n7MLYEK2k/27xLnxwy6MAgCv1blxOUVRej2vojxB0sCOyhEwvrQTy+Rh+bv9TAIC/PkMMkuP5QZya\nJQ71+3cfw4JJSc6/yL4RExE6TlS3sT+1AAD40tU9eHsn8dYfWt0N06SIprSZwDNJirQdW4NxlSLw\nilCU5F11GGKl8iODJ/BXZTr+rJnBs/MjAIB/u/1ZPJunfRw9swXvO0I66fNmGpuzVHmVa19DTRXF\nT6s07s3VIxgZobH+cP9xpFShNZPIS0465wx6B60y7JoOVqJ4oG+sgNki7U+NO7K9YCmfhpelc8jv\npjhHKymwO4hBYBkMxrJoOTiZQUzotHAO1FbomJejneBi386ICc9XwOy2sbBO5zN/vgeprTmsGA1G\nxMuxf/Fz/SrZ0n10bXWmNCVCfVMByXgh2EEU6HCOiuezSAJJwsC+/RWkzZWmpKTHg/v3pQSYLPf3\nOIPO/Ohfk69JkwXyNeRrsW+4AdZMY5tgItRgroSCKlxDLMCA8aEgNbAWCcJHjZVHsza6/1oFJPvF\nRXMS2ZUt+ri85kOP4pa0myvOpXHYHQ6i0zpOJamYKB41cUqj16OxDWSEDOvmRgL6Iv2Qs7EENiZF\nNeeWHMpVWqaVxxkiS3QKZ6/2QxdVlvuHqIjl2NQwtHXaR2ST4Ys2LZdCcQuO6DD0/t3HMKQTnn6x\n1oe39FLFY9UNoTdEDv3bhQmYorgnGq/jXJkmDEf0MI3rdYz1ESb+xek9SMfIod3bPY3TZXKYR9pn\nkNYJ2/7tPZ/Hp9YIZ++PFnCpQMwV5jFcWiPY4w3jU5hsp8lleZUmiIGuvJTJ/asL90IVDT16wkXZ\nGehUcQCnl2l/RntN9gl9+NgeqIJFElYcnMrSNvf0ztD1M3rlffr6+i7UHDq3dLiKkR5i7UxP9oAJ\n3JJrHIlRulfzq2n53Ui0joPdNHFpvbN4+AxRLju6adwbs2lom3TPPJ3DTtI5RMaKKK8KaCdTQ7yf\ntvc4oPvVqRUDEJDTHcOzeP4pKiDDgAn3Gx1A8ea2yH21je2la2TzZvw8yGyxZJVls4UkXIGm6tCg\nngpA9EDfuQeduQvWBItItkqQAslcmFzkXNCAUXTmUaUnGk2aba5K59/8WmlivwQLlYJjlpMLZ/Lc\nfNjE5o3zMYN6NYEcQ4kz2WhaZY0qUvvaPMS+Am5le/3WSresZS1r2W1mN1fLxWEIrWuknFilGbrg\nqPCSgm8dXcKxMCkCxnpzWNIpMtXmDYzeQVH3/LeGoIhpSItxqdCXTFUR1mkJVrAi8piKIEtE1jjq\nHSKhV9DQuZ0i6gUzhX+0KVp++NxO3L2VZAU0xZVRwlSxA11Jgm4SobpMAMGlWfzZx3fJsnNvtIau\nToIurlbaMS/apB3qcCQU06fncWyB9CGMsA1mUvSw/8AVaIKJslmP4kA7JXELVTqfsOZgpkBsEkXx\nkIkRLPK5qf34hb1PAAA+efUwfmzr8wCAvz5+Hx6Zp2TuA4fO4NEpej1TzuCtfbQSeXqd4Jmd6RV8\n9TTBXWPDa5ieJvp139AGDKGkGOupwDtGyU1ndwW/tO1xAMDvPP59uHsP6dHMldK4lKdVRskMgwlu\neKEkWvi112CHRc2AAhzYMivP11dLLK0kEBH9QpNGHbkBsbKYC0MVfU+fqUwQ9xyAuhyGlQC87yxD\nclvaA6MX5WszEEleX+ROUaouIYVg8riRrAzK3frPeAUaQjdg0FybFPUtuK3JNYQCEMgNeeaBz2Ri\nNVC0ZHINMcGEccEkzGJzpam9XTCJG2TzAAS9NCVOffgFrInX7p+ODi5hliCEBQBvG6HfzQXcmnZz\n16hhD3y8gs5EDTnBJsm0VXBqipzbSHwDhRrBKfnlpCwQCpWZpOLljmRRFI2U2xNVlGqEaSmMIy+c\nxvo8QQDROQ26aEda6wISV+jmFLd66IkRXnul0IGE6PDDGPDMGZKENdpreIHR5NLdVgIXy83La52S\nfYKQ0BVxVOg7yQFZloqdScLq/+H0HWjP0ADmqmnENTrOl7P7MNBOcE5npIzBIfphPr68BR/ZQoVI\nv3vpAXnZ/mI/VTP8+EO/gI4xgoec80msTNADPdqZw8efeCsAQG2z8alp6tLU17OJgx00EX5lchdG\nuwk6uSMzi8dXSZ/FX0af2uhDdy+NaW4tg22i69KWRFbiltNTPTD2Cz3yjQi+sEIQVry7jBfm6Frt\nHVjEscsjAICtwysoCsYLD9E+3rP1DE7nCWIr/s0Azi3TOKw+Cx2dtG8zZUqIa2YjDk1g426YwxWa\n58xl6H6K9lkYU6BXqRL59WQ/kn5OvvadWIg19L6rvJmi5wbQA9+RqQHaogcm4RUD4pqDNcEpahMF\n8PoL7nEGCw22im9BlkvV02Ww1HCuzbCKJ3F7F6asPL1x1ei1Y/F10P1zDGqqe2jouhjMk+dvcUVC\nLqST3ti3D2GFFQXfnzoOALiAvded+61gLcilZS1rWctuE7upEbqqeGiLm1AYR1p0o1+fS6N/lOCP\nh755B5wkzZjGkiaLSGqDtmwOEd5SxIEBSrodPTcue1m+sXcKX7xEsyYTUEh9dxU1oQ0TO2vIJVVs\npIC3dDSWq/8wdxgAwG0FoXVR2JRmeNsYqRPOVdO49BQpL47fM4uLy2JFsYMi8flwBkI+BnY5hC8L\nXZehnhyWNgiiCGsOFm1i5OzvXEKHaCaxVEtitkowykYujt++8A4ABDuEhGzsjz/x72h8MVdywkfu\nXpTR1NRyJ3btpEjc4wzZKkXFi0sZpAT3vSNVxpVFSrLOrLZDE5owtmi04WXD0LpoW9dWpDTC2c1e\nySZhDkObSPi+fewCLNHsYHKpG94mrVq0IQ+qiKgnZ3oQTtKqxBPJ1NP5fsw9S4li+4iHSC+tYN44\nMIMnZwXDZz0CW2+UXkfOEcfdbOfgSVp+s6qG3E7BinAAO46XreXyWjbFMHA4TPew5HEZ3wY1W6Ks\nwT8n+VzaKhhpX1+e32CXAH53o4byYdBklB8ow9evaTDhymhZvWFys/FXgQ8QUc9TwYSCIqP5oAyA\nCi456SWuN0kPhAPMGnlegUIpP2kaXF+ojEtI6lrz+6+qYDgcJr+lGAY807zxF15Fu6kO3bFUZBdS\nSExqKG2hGxad17BaILw2ssZQVemGaTWgLh6SVE8JeU1Q52ohiUu/747nka3T+w8+dxhvOkDI1mad\nHEDBMrCSJyda3qGgs5uc/29OPIynSwStTJc7UBSsGT1uwc7Q8du/FsNDb6DiI1gKErsIjriy1gGj\nj+Cf9RIdu6e9gJUzdA4qgMQAObHZqS5oKcJ/J1LreHJ6HABgdygYCJEje+j0HqQF1NDflZc/jOiQ\nLZ1xVqdqTs9WwETV5KzSDi8vqIIlBZsdBDcNJvLYNOm1ajg4d15MPhOreOcO0pvJWVE8c4nGwsp+\nlQ+HuyL0dTgQ7qf7M5bYwAcGCJN/OLsT7+o8AwB4urAFG0IkjS0aUAZorOfXuxERVaG/dcdn8FyF\njvO5SYJnVooJWH30eX/vJvIiP/DI8V1QTOGRQxypM/RoFu+uQRXiYHykhpFOEg1bebIf9S1CB8ZS\nkDwXel1BLkp3p3wdZTrKgoAXnNNKHm9yWj6OrFzjmH3WR7BY50b4eNBxmwGd8mAjaS8ArZS8kHTG\nBnNQ4Y2Co8aEQvc2iLUDkLAN0MDeDeY2RMO4EqAq8utYL/42dH0a3ZCCOu46uIRnaB8Q594wHcHJ\niSMqqqOV7k54s/PXXaNX215HMU3LWtaylt3edpN7ijJEZzVUe7lMKIYKgFBtRWXQQ/9OgiIWtG4o\nopRbUTwkzgvtFwWoCqXGz+7oxPhOSt6xmINvnSUWxw8fpLLcihvG/CniV+sWQ0j0Mf2Px98Lb5Gi\neK/Tkl2C7KqO4Qk6/hy6AcdvbeKhtExRcsdgHhUhCfvTW0lK8wuL+6AGtJkiokl0bE5DRZzn45cm\ngCJFKJOpLoxGKUGpRhz0JSmhen6mD1wcc8/EAtrDtBKYtHsAAHtHF3BxjmAJJWzDLlG0/sY3ncHl\nQiNiq9t0W4e7ctiM07WaudqFWYv20z2elZx922lEIIl+WjWUihHMnCWe+tVMB74l+pz+2K7ncL5K\n75/O9uFHRykpl90bk6uJbYlVPHj6AADgI8+9Hz+w4yQA4B3jtHp6dnUEboLiiPVCHPYajU+xmWyY\nkc/Gkd9NEZe2YKC4RUjsOgrmztL95N0u9g4TC+j0yVGSj3jplf+veeNRA7YoJlKk1iLxpoMRpnwf\njUbJNpiERVTGUfJ0ub3fBNp/JwjJWFBgiL17XJHStr5cLkCRrl/6H2SrWNfEjn5E7UMrKriM4BWg\nmfHis5+8UFNiNCgJYAWidVNAgVFxLiWuS82Ypu8FlnTB0v9gQtQFl31ZVTDUOe2HRw3cinZTHboX\nAmr9LoxlFaoo+CndV0XkBDlXN8wwL5oGqzagi0pEVeGoiyfMTnCpoR2bV7E6Q5ACRl2ENmn7B58g\nGuLYnkWMHyC8fSabweJ8uxyLLkS9NMOWuHBnsoyqTQf66Ju/jD8+92YAQDpexapoO1d3VOAEvf47\nneRzE0Ydyf3koEOaI4t5qtvr0IUmibcYhSqaWJfNML65TJNPImZKiOTOiauyKOjiUjcGBbzABf48\ntdEh8wO1zQj0YcLznvzWHvQcIDz/9HIfahu0v4HtBeQ4XVtmKkAbjWVlMQ2jTcxAOXoE7G4Lo2li\n0JxaGgZS4sG1FaQEU+eJ9S24eokcat/4Oo4XidlSMsOoO7SfshVGQmjP/Oq2x/B4nsTJfOniqhlC\nPUvjiyxpwB7atzsfRaEgxlpTkTlJ1zBc5Cj3+3K8YWgVQWcbsnD2Bcpr8KQLN6y8rjB0eBw684tl\nHAmtqIwFtEqaqXq+tokaoOgF2ScAmppA02FYAPJwpINXmNcoOPKUJkaLb0G2SlCfxeaqxLGDGHvj\n1Br7C1abJhRLHt9gboDaqEq6pAWlyen75xjE0KWQF/gNIQodQFTxOxZ50MUVteHK17eqvZ5+Ai1r\nWctadlvbTa6V5uAah+IAyj0UfSq1EOppsbyuMihxv4hAhysKR/rCdWQeoAKU5WISioAUTDOO0CbN\nvLEZFQ7l6BBZofdmrAG5qrI7bVkIlOnPg3fT682FNtSFPsrqcgoJIY372aVD2NtLcM7pr26Ht5US\ncKXNKPQYjTcpCpkW11JQRAHNeM86plZolZHKlHFfHxUqPRaeQEX0Mb2nb042z3huZRQTW0gd8djs\nEPQQ7TOVrGJTJAx3jRG0sPjZUTAKYhHvqMAW5f5W1MO8WH0MDm4g0ym6NIVqOC9kCrSKAs+mVdH3\nvekFPDpPMIoyQXAPLA0XV6kgSCuriPRRorY8n4QrVgg/Pfht/KNGq5JMuIL5MrFf0tEaMqJOYHti\nVUZuBTeKsFD183n8isKhiAYYtUEb4Ut009wuF8YVWsa62yvY3Enn3nGCoTxEN7F3x5psHq1HbehT\ndD61Tgv1gUbT6teDsaqJqifgEdYMufgNjvXA9kElQdJeoTdybmMrnXkycm/WWxH3jnEJuQAB6V2l\nmfNtiSjWgNdUzu9H3QY8mQz1P69yXX6uM1tG7LSyaETFQTZLcBw+OyfBbJnkbWjQOHJFEEzmBqNZ\nBUBUaZT7+3IKLucy4RxnupQpZtVbj+ECtCL0lrWsZS27bewmR+gMzGHQS0DlPFEP3ShHNE8zo6c1\n8GK1pMJto2h1vRxDSbR9Q12RAlG6DdQ7BNYX4tAFj7peo6iD5XSEhwijtQuGJJ7mFlLIDFACTk/X\nUZymsTCNo1KkDO3SkAI1LWbjAwV0RQhzzkSqmMwRdpwvUxTZ1VHEyhJFq9Nr7djdTzrdOTOKr13e\nSeNbjICn6XzOZnuxv5Oi7u3Dy7i8QRE950yWv6eNGiKiycRsnvZtvbkgo3J7LYZEtzi3jAUmVA3n\n5zrwxjuepfe5ir2DlEM4xQfkta25Ovi3aZ9OSlDWhkyETtE1tvpclNZE84i4g6jQd//9i29DV5yO\nuVZLYHmTVhyOrWG2RNH9yegg9DCd5+8d/By2hAnbf+Q0XQcWcsGT9HnifAiqaAnrbLFgispg1VNk\n45L1uzwoIvewON0BPU33IRatY+JddG5L5TYc6ZzBP0QJu389mLeelcm6oDiXypgUlNIZk5IAdiDi\ntrkCHT4ubcvKSfs7xHd+FO1xJjneNhSJtxNu3RDTMph93T5cMFkooCguFDS3iTOY3YSnB2mIyneg\nUt6oUtUfA9BI1qrgqPvVnsxt8OQZZHUo8fQDkXvgGsrrDBeqGIO3un7DY7/adlMdejpewY/cexTf\nPHU33ChdMM6Ayi5avhgxC/2fJKdS6QbyO0QhxNE0WA/dvOhgCVZdaLI4EXBF3ASz8TBODAqmzKUh\n1D1yTPEVBbWD9IN3qxqqx2jprnqA3UcO5o7dV1C0aNlfqBuYWiYn9b6dx/CNRSpsunClD0oXORVF\nHHt1vQ37thAnda6QgumKB0nx4LoisdtfgyvUGS1HxSOnyMFF5nSpR5PpLmJTFA5NVRusFU/wsJmt\ngIcaD/EPjZ4CAHxq8hA+/HbqWPTE5lbUxQ9ttZ7A2cU+uQ8mrtHxtUGUt9ExU53koLsTJVwNEWzD\n82FoAvpKxGuStRPWHIwnqQisO1TEWIISwY9c2QqWFD/AuQj4MP24P3rqB+X5K0FpWyGLXJpwkLxE\nY3VLOmLTdH0qow5cMfl19BeQXW+0/PQLogqFKBbDoqn1iW48mO5AvvJtvF7MM02csghy2qbXbqC2\nQvoufiI0yjjq4rUJJhs+qKxRaBPsBxqUr/V56x5nsqlzUBIgqN/S3JhClUyYGLObeoCqgX3ScVwk\n/AIicHkc0oNp7D+o/BgsMrICPPMGg8aVf4MQjX++FlcCvPbGmMKBeUNnCjzf0TOGs0KS4lYsKgJa\nkEvLWtaylt02dlMj9LwZwecv7YWz10NsgJJu1atJeKKtmaVxrNwtKkXLDKydZkFtJoLICr1vVZIY\nvJPgimKihvw5iirduAe3QLDD5SyJP6Xu3oD3An1e3uKg/TGCSOw4Q3GP6HFpONCVBkXr0iX6bnhN\nw/b7qfHGXC0DUyRit4yuYluS1BR/pYtU7v9g9a2oOHTsj27/Gn7jsffRCascWpZm9MzedayJ0v9K\nxYBaoP1FjmRRW6FIc/NqGtygsWyfWMSFSRrLoZ00juVKErmSgJ7OJfD35yhBGY3W8YlL99N1cBU8\n7xAkZNd0MKGZ3tFbwOYlkhjIzqfQJ+QW/POay6WxrYfO60xlACkhzVCsGKjVKRL0PIYdQrJgIJST\nyaqxrg1cmqKVANodMKE1bxdDUKIUoWkhUY49F0NYQGxWikMsJsDqjdjigYNn8MzSCI11uQ2pk0KZ\nc6uH3kFa6k6v92B5SkBV7Q5dT695SX6724ObJFnx2z1HUfLoeQ4mRcF5Eze/USHZHM/77wf7i0Zl\nJafSxEWX/T2vKeN3b9D4QlfsJl31IGQSPBYAKAHlQyugbx7ksjfDMLypfXdTFH9NJWzV0yS/PjgG\nNSAlQHTGBvxiSD30xn5dzvGpzSPif/9rzVT+te3mNriwFTjrEbCUhepVcm48zNEzQkv3QiUCSyHH\nyDyG9GOC9WAA1QmxdJvVUPwkObrcHg4IZgMPuzAWyPGYg/Rw120NoYPEpjEYh6eJRgwcEk93ahp2\njBGbJaS46BgkbD2rtOH8aXKMqQsKvLcSG2RqrguFLhrXO577CADgngOXMFeifX8JByS2bdZC4KLb\nUK4Qk0yYtmQFSBIrZHMzDn1dZPzLDINvJVz4woUBqBX6MUQ1Op9sIS6vpdXlQBEyAKWMCm4JdBzL\nuAAAIABJREFU3vaKBnuYICF9MYQ3vvU0AOCpubHGD0D3EFIbuCgAlKsKrmQFT99lKJyh12ysItUl\n1ZUQsgM0ofzXb38f9k0QzHRlpROd/XTdihUD1jpRcTqGN5FdoPxEOEGTc7W/Bl6hzyPrDJaAapSO\nOioJOt/HrmyFdk5MXIM2XHok0HGcYdamiSM5r6C4g54JPafBWGNQrodub2v76lWC7X6756jEdk1w\nif/aaF6C+8wWE2hywP77FU+RfO0bNX2+tluRHoBqgib1WQIc9lKAW24wFyWPnim/+CfYZzQozeuC\nSWdtck2qQCqsoeXiBeAfjzOoSjOcozDeJLVrBeCmIA4fLCgKTnlR5n9XxTdmqH5kAOdwK1oLcmlZ\ny1rWstvEbi7LRfOgZCxETkUg6a8KsBoTjSyWQ8Aw0R4ikxFYbWIpmOOIzotEowkUSe8J8VkF1T6x\nvFsMwQ2JaE/AGWYpAU9UR4YWQ7AOiRAuMBNvG13GpUUS1vIsFRCRbs/wBlbXCQoxM4b8yr6xBaxW\nKVJuGyCxr8VKG2xRHXop14W6KGv90Z3P428K99Eh6xqMOEXOR3rm8NWTJPwVSdegbKf3a7MJLBbo\nmEZnDaM7aOXiiM4N7nwUiijV79m3hpVZiqKNmIVuwRvPdsTg1Cj6sfosbI0Ry+S40Y9in+AHT0Yx\nWyMZgHsOkWD/ynIalojUWNiFsYNWGX3JIi6fpmrc/oPLWCrT+FjIk23qJnrXsCdFq5xLxW6csSiK\ndj2GcIbu5+5OGsfzs8OwRNs5s9+FkaLIPaw7sDS6b+GQg9JWsaQ3VZTE6szsaizznSjALJ8dxVHe\nX4f34OuHhw4AOEWrXPsuF4qvCBi4BNRerqENHoyofVhCBYcptgkxr6mMX27Lrr+u1/b6DEbIvlFD\niuuhDo8zGa1XA7IDfru6hGLeMBGqw20aS1CEK+r3NGUN6OZGXHrwBiMnzCATxQoQ6HnaiHRVMCms\nEGY6vDNt112LW8lubsciS4EyZ8DVAXHvkJjhqKfpPx0nOcpZWo5bKaDW5eu9MNmoIr7swomK8mMH\ncpnNVQ61Lh6qESEDWwiBlcVEsL0EiJL48KqGw28lbZHnHt8BnhAUqo4anBIdfz2XhLJKa31vXwmW\n0E2xMip+bJg0TMouvdetF/CltX0AgJNnxsDEOD7JD4NF6EFLZ8pwXBr30ZUhkjQEsLVzHeNxwoUf\n0yZQukg4t5NwcfnKMF2jnVSSrwxU4QiGz6GOBXxlTUw4OQNdoghq6YVeGNsJHhrq28STG1RAlIqY\n2NtJdMquHSU8+PDdtE2E9p0fW8RSkRzE5kIbShVilpSNOt5+L+mxfOPydjCRb+jtyuPKKjGF/uPB\nr+BJUeJ/eqYf0QRNUKalw3F8FT7hNMI2TIWum7apwbTpntRtBTxKP7RodxExAdFUignJZHL7TWhz\nAoaLcHAxgbs6BxwFeJ35896nBdvq5xWYvIE36Tfoh2kwV0INQYzZ5Grj/yyIkYv7pXjIC3hEDzh8\nFVxuG2UuCsIxX0stDGq4yE5fzG1qYOHvz4dfgpOIxwNNNQLyAd8Jj1fApaNP+N2NrhlTA35xpWSu\nHrhu4A2VSj3QsajObfQ+FRBtugWtBbm0rGUta9ltYi8pQmeMpQD8NYDdoDjopwFcAvBpACMAZgC8\nj3O++V0PVuHoOepi/t0eOp6iGT1U9hCfoxlz5Z0mFCHalT7HUBmk2bjWpUBUkGPtoAI7QzNv5AUV\n4ZwolunhGLiLEoo5kXT7hQMP4x/miQmiqy6uLFGird7l4tSDlFD6nvedwFPzpGBYW46Dh0UCKB+C\nURQJovUojBWxKhjh+PNLb6DvDlIfzX+a24/7e6cAANYuDZdXiX2h6y7sTZG4DBvQBYd6V+cKzolo\nvS9awOefuYNOLmkDXZQAHezNYeES8eA3s4KHbTOZBM5ZUQkd7dk+jyubBL/YPTY8AblcWO+X175/\neEOqUSqGC6+NxvLps4cAAGN9WSkqxmwFEFHx0pVOvK2XmoG8Z9tprFsEN1WdEJZEGf7nVg5hbxsx\nj/6PO7+C33runQCA9vYy4qIg6+iZLXIsobJguXQ6SF6k58Bs53BE5LS5nkBkRjTMiHIpuhVaaDQ9\n0YuNWCTRW4JZC4EpLz9Ef6We7VfD9MepDuGEpWGnkKEAIx10gBQEoyLSrfOG7jnBLA0+ubTANj5X\nu+TpTWJWQSjEhzYKXPmOTBTba2ig+5z0G/HRgebmGtXA95TAvq9dXQDNImQKa6wcfK59iAUZMI22\ney5vJD8VBplMpu/6MA+HKiQBpmwHoW+d8i/VLWkvFXL5EwBf45z/MGMsBCAK4D8A+Cbn/GOMsY8C\n+CiA3/huO3ENho0dGkJLHPkd9F50UUWtSzBVPIbUpcYD5i/BqxONJZVmOGA5gkI2DrvQ8+LB7LKk\nUmJhhjD5T/D78b6xEwCA3ZEF/FaNHE3pWAdC9xNtb7GaQkI4Hd7DoIsuQWZdRy0qKk7LGoa+R2jJ\nlBKwRJefuQrBIyNtOfmQnrswCBYT/RgXokBMTBCLURhbCd6IaRaKS+SkY0N13HOQcOzVWgLTy+Qk\ns6UY7ruDYKFjX6YOSM6+MrpThJU/c36LfBrPL/Riax/RCbvjZdgCc18rxVEqEqSxuJSR3YOihgWe\nEBOhwPurto73jJwFADysb0d2hs5t+855PJWlpEW+FsGm6AXLGMe7D9O1LTmGbDZ9NtwHRbRvcj2G\nzSzBOLrAyu1CGO4YQWLhy1GUxkTxx5qK+D7KGeTzMcl+8cKehFb0kgYfou28Z1kqc2aiNcyuJKT0\n8Mu0V+TZfjWMO/Sc/fzJH8ezd/53AEDFcxBTGtfB4jd2Pb6TVjiTcJgaZIOIhyuqOBJ+saE0Nbjw\nAli1j5UHm10o4Ego1nXHNq+pBAXIEfsOverpN1RvDDrzaABmqQSKj3R4AYgGcnx+RajBgCAZSg38\nDTaE9t+3waVM8QdO/Az6nPPXjetWsheFXBhjbQDeCOC/AwDn3OKc5wG8F8Dfis3+FsD3/2sNsmUt\n+9ew1rPdstvNXkqEPgpgHcD/ZIztA3AMwK8C6OacL4ttVgB0v5QDMg9wEhyDO4n1sMB64QmYY7Av\nh+VxYl94BpcNJjoH8shOEaSgLujQxPv1do9UFAHoyyEYom0a0qKUPlpDXKXI0OWK1EnxdI7cOkWO\nVTOMQ/3Ep+7tKeDpNdLYrlsaFKEtsm33PGY2KGKtZaNQE3TMU5eIp943tIFjV+k1izkICQ10q51B\nEYU9RpeFTJQi05lyBj2jFI1eLnXBEJotdUeTpe1mNYTjondp4j4q+PE4w+oLdH1YwpOa5W5NxfQ6\nXR9rLUrQDUhjxpyn1Ur7GY61d4sVD4CxTjp+KkRjKtoGPnWe4Jf7x6YwHaJreEdmFl+4Sr1a3z92\nHC/k6TzPLPTjWJbGt5JtkyqRE8PrOMdJ4TE/l0JU9AxVjlIC1+vykOylpG2+PQwm7mVt0EZtWTBo\nLAWRDRGtbXekSqbVxmGsUwwyEM/DHKTH976uK3ig5wL+X6Ez8zLsFX22Xy2LfSEJ5U6/DL4RpQUL\nZChqpee/yps56d+pv+i1ZjBXbhOCJxtEUN/PBoOmiZ8e4LCbwUYYAn7RAyqIQd11uYIAR1V8zw4U\nHAW55yE0tNlVxq+Df1ywG0oj6Gi0m1MZa2o3F2Z0zIJnwfZXKw/e2gwX4KU5dA3AQQAf5JwfZYz9\nCWgJKo1zzhm7AbcJAGPs5wD8HABoyTQ8DWCdddQFhrz3yBROP09L+sX1FCCW151bs8gVCQvPXWgH\nF1K6lqpArdAj2711Hb0xcg5nY71YKxK+m07TD3t+LY0/vfh2AECkvwy8QDfEnrCQaqdtCpsxbI/T\n5PL4+gRqQqvBrmvIpKn4x/UUdCVp+7lKCJ4QwhoWTaLnljMIiQ5A9WwEvb3kLFdYEtYiQRT9fesY\nihMMqysuHr1K7JPBRF5i1+V6SFZrRjULL8wQy6U2K3qKpmygXehdxG1EouR0e9uKuLJA8ENioIia\n2ShmcgYJZlnuVYAK3e7B0ZysQlWL9F56xwYSMZr8Fqtt6I8RJbPqhrCni3zbFmMFV0J0HKfWeHS8\nmgZvnnIFjxR2ykIpO+OiJthBGBSMiEUVJYcmx+jWIvjzdE+2fe8VnDxNsA0Pe6iM0o9IWw3he9/y\nAgDg4YfugCAW4dx6D6JhOv+T+QHM5DLI1Y/jZdor9mwbiL7cY79ilv7HY3jk/6SJ+82RHFz4uLkn\nhaU8eLKBtAJIqmIQ+gg6bC/gFP3XQa2XoEO9tuoz2MuzJOhs1I+0UVgUpDcCzUJbJtegMPu6z4KT\nRZBeGYIn93cjqqIauH1BSqKNBlVRQcOJ23BhC1cfVVQ8Y9K1TX/q2C2Lnfv2UlguCwAWOOdHxf8/\nB/oRrDLGegFA/F270Zc553/JOT/MOT+sxmKvxJhb1rJXyl6xZ1tH+KYMuGUt+272ohE653yFMTbP\nGNvGOb8E4C0Azot/PwngY+LvF1/0aIza0IXPRlC6g6Kr1bU2iCACqurB6aD317JJWSqv2Azaish6\nV4BQXiwR57tx8g6K8LTFMBwxfVb85NhYTbZscy4kEb2LkpI7Mlk5o+ciJu6LTQIAPjV1CN1JSjom\njToWszQzbxZi6EjT+7yiITFLA54Ni4YQRRXaBoWO9W2W7GOa3p5DSUicTM51y+jWLelI9tD+jj87\ngfR2GlfhShp8jMZV2IxBE9BN2wR9HtFtLG3Q+SZiJjQB53QaZay20eqkmI2hp59WAmsbSWCT2CLQ\nPXSP0H4qVghMFFBF1sV10DJQe0m/xY6pUspgIrYmVzCTZi826jQph+IW1jdp5dAzkENuja4FPKBt\nL61QapaOI32UTH7s2C66Z50e0EsrgfrlJDThB9eqCfSKRh+dkQrWa3ScZbMLDz1JUFDIBew2Ouf6\nehwQSpHjbRu4d2Aa66GXxxF+RZ/tV9G4beHDD/0EAOD8j3wcLhdwxjX8az/mVQOMDg+NqM7F9Tx0\nl7OmsnnfdOZJPRePMxiKzyxRGxF1IF4MtqMDaxQIyX1yRcoN6AF1RJW5jaYWgJQM0APFTArj1+nT\n0Lldvwqp84aaIjFegjzzhj5LXEiQ1LmNX/7CTwEAxu1nrzvGrWYvleXyQQCfFCyAaQA/Bboen2GM\n/QyAWQDve7GdcI2j3uUgOamhtEgOqHtLFqucHKd6MYYY+QJYCcAUhUVcBexxIZw9bSBEsiGIZD1U\n5+jCpy9ymO30EBQPkcPgJR1MMC7UuoJShZzuNGtHZ4zglPf0ncbvzBD7pb+tgJhOTuHcci8cIRrG\nQh62pilIW1tPwuxoxhqNNQazQ1RZ1lTceTexVparSepBCsBaiSLUR8esmSpcAbMM7lvG6hMEf4RU\nwBZQVHgmjPa7yDEvLpNz7egsISSw6li4wR6YiK9hMErbfiZ3GLsz5IC99CqeMUbo9bkkrDM0oWwe\nsqWmvPFGYvuUV5MYEz1Mp2a6oYTpB/qMPorLi+SsM+kKsmuUe9AMByHR6ak/XkBWo21GxtYwt0qQ\nirpg4FlOsBF85k+YSe12lQOeqEi9t3san79IxVnLaymErtK9Cgd+p2avI+mUeqKOhEH36tjXd8LZ\nVkXR/Cb+F+wVebZfbdv+B0Ib/gfq6FT9bkCqdFLBSkgbDd0SmzMggKEHqz/p8wbMEqQNemBNGi9B\nbRg/WAozVzp1k2uSCRNkuQShkuBxglouQWdtBKiPauCY/nFizJEFVE1iY2LTaoCqqKPBAkooqhTi\n0pkiOxPNOx62/THl2G5NOa5me0kOnXN+EsDhG3z0lld2OC1r2c211rPdstvJbnLHIgAMUGscmdOC\nwzqmSP6wG+bI7xalwCUVrJsibW/FQGiS+NSMA05E7MoDwqKnqFb3YAuIXl0R6/jBGsICtqi5CXii\nwcS7dz2PdYvggkez2zAtStgPDM3LBOVP73wGj2cpcVm1Q1iuigx3SYcjeorGp+jy1Ts4HNGQIdJe\nw7NXiCnDqxqUqii37q7DLNO4QnELiQid22ohgdgRipILpQju6KVo4KitIlcWqoWdBM9UzBDMVdEA\nRHdkdPP1xR2ye5IScjFfoRXP17Y/hO8z6Tw37qzJrkqZriKSIrr1Vwp6zEK+RvtQIw64gKo4Z4gK\nDZrcVAY92wgWKVQi+PzhvwQAvPOpX4YrCqJmprobHeU9wD0rtGlEeFPrdTCxi4qQJqd6kRY1AI8v\nb4Et5I+NFQ2KQE/MTg8hUUS0ZesyFp4gZo1dVpEXkrza/jycS21Sh+f1aM48Rehv/spHcO7dnwBA\nEIJ9g/6ZOho9Rl3OYIhVjwH3hvxw36LMlcU615b4e4EEqSIhkmYZXMlo8bTrioyCyoy6Ysuo3AWT\n0XcQ8okxp4ln7gYifb+QqHmMgeKjwLsxP2nMOQzmN9VwERXvv+uhD2Ni4SheK3ZTHbpaY8icUNF+\nuorZdwrNltU2JDoIinCupqEL7ZVavwuIpTl0DlN0FYp3lxH5HC37N/YytJ+hm+cYDOFN8SDRx0i1\nVbBxSdAd6wyeQTf4VH4AB1LkOL/+7f1onyCcp+qEsC1BBTpfWtyDqtABr9RCiIiJQeuowc4LvPww\nYc6MAYf6REPpxT7pDPWUCb3TldtUzIi8FpaAYtwLCZi7iVGSSlbxpKjm1HIaLFEROybGVzN0aGnC\nm9JGFZdzNBGtrjacWaS9hrUywVn/ZX0n8uKYq1MdjSrTxRS6t5ED8B16Z6qMtrDAth0V5QJ9b60c\nR12wZt5+70l89RQVOe2bmMfXy1RtC8YRTxEkVllKoG+cnP7aZjfq3cKTi3yIHrfkBKrGHTmBbi4l\noOfED2rQgrpJz4HSY8JM0PGnZruhiLaAd9wxieOPi2u1tQR9SwnMaGZbvB5tx3+ewdl30PM3cc2v\n29clMTmXGiaAJxkvQdjEd546grRGRTJG6h6TOi0pxZLfDWqMe9fsT2qP36BoSAUHAjAPAtWpvgVh\nGR9WoTMIQC8B8S098F1/AlPQgFyMAH4eVXRZQJRQQjhhib4E//dVvJaeqtdvSNOylrWsZbeZ3VzI\nhVFSbOY9UXgiWtw6vCJV/pwEh16gWbPtgoqSz0WuMOhCV8WbTSG7n77bcZIjv1VIW+Yhl+mJq/R5\nfjSC0CBF/7alScaL6Wr40hxFmtHhIrJCK6VihjCfJ7iiuB5HbEp0G7p/DbnTlFCM7dhEPkcR+l3D\nMwCAJy9O4NhFglm0TQ1MdB1q6yyhXBMNOxhHqoMSgC5n2NVBicun0mlYOVqt1KM2Mj0UrdfSIUBI\nDJw/S8U84MDQNlpBHD03ju4BSmIyhUvud9doGasFOp9PTR6SDbPhMaKJABgZXJdNMy6uU82Me7oN\n5f20v9JmFExE1N2JEmaEPMDRlSHsGKeVSHu4gj99iJLJbtJFxaH7wCMuNp6m4ieVAbZIroZjdLyR\njhwyYVrZHF8ckDIKWtRB50Fi4WxPreGJJ0he2Fsx4FeyR0eKKHO6VrPFNLxhWlF8aNej+H+OvV02\nwX49m7u6hp/9xK8CAB7/0O83FRm5AWaLbyqD7DsKXM8pd8GaSvl905nXJGgS5HrrAchDMlQCEXWM\nNdKLwS5F/rGD/UKDCovB7wXL+avXdFQyrikbMHljW5U1ksMqmOTs29yFLiAXDSp+9hO/DADoXX0a\nryVrRegta1nLWnab2E2N0D0dqPZwaBUGs5NmxsnLfVJgy066cIRolJWuQ50WWtkDNpwcDTU+q0AR\nkbaRd6CXaE6q311C5AmKTG2xj4hho5ijJOIv3vkY/uy57wEAXF1vR0a0gCtXDewdoSRdzoxi4SJF\nrHqVodZNkUZtsgPx7YRdO54CRCiSeHqaKlwTZ8KoDAmKJQNig5TE3NuxhMeeI/41Uja6eihCX32q\nD7k30/7UsgJHUPqGu3LQBZ+3ZuiYXSb8v2OUIteQ6mJ5k1YzzFKwJoSvursKWHEo4fmR0Yfxl4v3\nAwA05iEpSvufOr4DHV1UVbtWjGNrG9EwTYGPJw7kUJoSjUZchu69tBJYLiZRz9F96BkrwVApl3Cl\n2AE3Que8Y9sCZnN0/GouCi8sxNYUwJgRFEWT/l6Nx7G0h849HHJg+7ROS0V3VAiPLYwgIbj5+Tka\nEwBUFhJ44Ai11Hv41G7ocYr6P3b0exGeCTf1JX09W+8fPgMA+Mn3/CA+Nf4lAJQgbeh9exIXrjdF\n556M3v0raXHWlOSsi1VQQrHl+0Eaogt2nT45QFG7bKpxTUs4GhOaqlB9u1Zh8dpkbNM+QLi5v+Lw\n8wQJxpEXuZoQPPm+Cy4raXWmyhXMv5l+O3r/4LUVmft2c3uKqhx2xoU3Ykk1s9CZKEzhOKPzGqwU\nXVRtPQqzj5xH4lwIfmMTvcLBxRq8NKDB2BAPwckEiuMikSIaTGRCNpw2cmifmTkkGyb/2t5HcKlK\nsMDY8Dp+//HvBQBEOqu4705SU3t+YRjqWZognG1VmAJ2CFaBe6Jox04C8Rl6MCqDnuSIP3Zpq/xl\n6HNhzDNyenyLiclnRgAA4W1FcCF3u/TIIPreSsnaohnG3mGaaK7kyLFv71nFsuiixHUPW/op+bgt\nuYZiil7/0czb8JZu4sF/+spBtAk2TXhVhTNAg6muxfCNFdJn4aKJc2E9Bf/3nt65geUsHefusatQ\numkclqfho31fBQD8yuQHoLYL9kstivqMKDLauQ5dTG7z8+1wanSnmS0gs5SDmGiSkY7WsCLgoa6u\nAiazxGU3V2NwMjRu1mbJphZsoozHrlAjDT1RhzJJk/XAkRVstkXAIq+l9NW/ognH5PxMBE99ja7R\nEaMY4Fkz2fwizBqNMDwEHWbDufrwR5i5CCm+xkoDZvF4s35KEF7xtwmW7buBphVBx+477msLhbwA\nJz2YfDUDxzGukcgNmgvIZ87/v3+dpHPnHBdE5ZX5MwmQxM9rz1ohTcta1rKW3SZ2c5OiCsAiDhTF\ngyeWQFaay+jNauOILovZ2ACMJYqKk7MuzDRtv7HfQ2SZZvXEoodqB72vVQEuEq12G0Wd6xc74KVp\n2h0e2cRGjuh8v3fiAalqaM/FoPdRFG8uxvFkdjsAoHsoh+xWujx3jczg2MM7xbi4vGhOSgiGjddg\nrYt2dREPG2cpgYouS55baFcB3iRFvU7GgStgiVolJPm01SEHV86TVgBXOeo9QijMpvM90nYVuUFR\neq84yNbofL5yYRd4XSSuKir+RkgPeAZHbIxWC+aADecCrRDQ5kp+fPwSjbuw1wIX0U/pWAf4CEXI\ny9UkxhJEm9waW8PHV6nexuVMrlbu753C+CgtURetNE7lB+g4g0DuURqLKxibZpyhJDjz7x4+i5Uk\nwUbfuLADAz2UlK0lQ3AsOh/uKMicpeOsDup4zy4BuVzdjtoA3duF1TS0pTC4+d3VAl9v5k5dxX/5\nzZ8GAHz6D/4AIbEE05v0wRWU0IA9/OjVj/QSiguTNyiEfiRuBvqSKoH3FXDUA1G3LOG/JnL3LSrb\nxN04tlTAZfQdjMh1cBn9B9UU9QAi40MvCYVJOMU/ZwBQGIMusAIbLn7lNz4MAIhfvvVL/L+T3VSH\nrmku2tvLKL/QAWdMlOd32FL5MBa2UHiUoJDKiIPYDA2PK0x2rVFsJmGWlbsYFJH4DuUJhqAv0B/W\nY8K4SKyIqdVhRCYIQ67mI2Bz5FTcNhfDouR9djEiO/lkz3cgMk7bPz05Dt4jCoc6qrJASBXH4x5g\nDBP+W12PySIbltcbfS9fSEExhDxA2MUH7/kGAODLy3sxPU24PYu4ULKik1NexdbdhHOfmKLy+U/P\nH0a2RA79zcOX0ROhY3qcYWmKJpHIUEk2XlFVDwc7iW/+lKWjpNO1UAo6Rg/S+/phOt9OT8WG6PS0\nqSSQPE4wR+HJfvR98AoA4HD0Kn6j/RwA4B3lH5CFQFfKHfjsk0fomFUFTjed/9ahVSTeRFh8Vui+\naAsRKG0E1fzz3C5YjrjHpor5WeKn6zkNTh9tk+ooY/0w4ejcUfDVKZpYPVfBYD9NNIvnu6GOl5t1\nAloGAIh/lopi3r7l3+PoL/0hACqcCWqY+KwPnRF8EjSXN/jcNpr7ewZ560ENGB9aCfYxVRlvapRx\nrWaMDk867iCXHGiwchIB2ERFoFEF5w09Gk5NLADAUHwJAgV12QCDyWKrKBTJbDn8Zx/C4Gdem7h5\n0FqQS8ta1rKW3SZ2UyN0x1WwWYyCpzwpvsQ4UF4nKKDQbYHtIfjDMByE+ylKW98XQSIuxLkutsOJ\niXL/KmClG3l5v1IwlhQd4+eSMEVkzVyGnjjxnw/0LmJ5OCnHdV8nRaCVnSHsaSft70eO70J5TbRb\nM1xAROP3Dl7FY08RR1oRcAofqsl9sYgDLuACxQG0Ms2ZmTesYOUsJf1CVw38ZfQ+AEBtLYo9u+YA\nAFPrHbBXKUHKNUpCAkBUJHbnF9uhFOi9x44dwl3vJfghrDnYuZv2kQlXkBOKiLObaXz1OI0VIQ+d\nguWybqZRMOn6R3WKcypWCMWSkBroLqLQQ4nY+IFVHNskHvxcLYOLCUrarpdjkp10/NQ49IIoCR+v\nSdGktQeHUBZ9Yd2IWJ3oHJ8U7dJ+ffJ9KF6g42gAHKF572kcyhpdh2rYAe+m5yA8bSB1mBgya9Pt\nmDfpu0wBFMXDd5AtbxmAgd95Gvs7PgQAOPb+P4IqNc69pmhd4Q2+NtCI3gEAnMtomSo76bXBOFx/\nVci4VDOsctbET78RrBKEU2w0ovUgdOKbikbFZ7DkILhtUEFRD5yjf2SFMbQxOiuXc2z/zC8BALb8\n1ms/OgduskNXqgoix6Oo9nkI7yOYwzmahtsplmjxOmpZ0SjAcJAT3XaMNQ2mJYRaMh6sNkFLXGGI\nCynb3BssJE6Sk3IM+puoAsWd5CR4yMPSGYI25mOdeMN+anwcVlwciJLE68NsO06KxspMSwZ7AAAg\nAElEQVT9o1ksTRKMoeY1xLfTeI+tDqBnF0EhyxfIQQ925DG3RM5FXwih906aFObX0rBFwc3aZgL6\nMFEljZCNwizh6XqnKeUG3tt1Er+18l4AgNdn4dwkYdGRjJgwGIfeT/vw8glcKRJEkatGcKSXHPq3\nrkygO0OOW2EcoRQ5w1ikjkyEJjR3gGEoSedzeYPO0eMMbJGuW1FzEd5OBU6FagQlQTlcVhOYiNK5\nl9bi8sceWVRh3EN6NCHNRWeUxjiVGYNWEzmRhFjydlbxo8/8Ozqmx8AG6Ny4xwDRNMPTAS66LjFX\nkXo85gjD6jI9E5EVFUz0Tq31ujBnE/DqLQz9u9n4rxE2fIh/GMc+8EcAqGem7+x0pkBRfAfr0w0Z\nCl6waKixP9/5u7wxAXi8QYVsdvQNNo0C3sRWoW092Qu15HlNxU4NZ9x8/KBqYmN8TFIR1QCuH4SS\nFLHHXZ/+JWz5tdcuXn4ja0EuLWtZy1p2m9jN5aFrxGrhGkf9NEVa3r4yNDFb17JRhNdElLWUQJIC\nTVR7OZxekf1kDaijsN1DeENsX9Fgi+DeX97XBjxoeVFaPlZGSIiA2c+nMT1K0e1mJSLVCS1HRaFI\nKwFl1gDvpGM6cRf5FUrqxTqrKEwRROQnQk1HQyRBME+tTcOs6EavVFVE1oQe9E4PsShFyzs6VvGc\n0GbfO7CIL10mWORBez8+9sCnAAC/c+F7UZ2j4zhJ2se+sQWcX6KkcefdK/ih/hMAgP8xdTfOb9Lq\nI3IsitqbKBKvVMO4c5hWH89OjSISokg3FTGvawFWXo8BSaF06agoi4TnTxx5Gv/ft++la5iy8M01\nEsQaG1vFXE60sTuyidyiKADSPZgdFDN5mtRbAktSotS7EoeTFu29ZjXUtokVxPkwKjvpNY9z6AJ6\nUizI1Zy9lIDTTvekNmIhdpm20UoKossM6vUN5lt2Axv/9Wdxb/bXAABf+8XfRUah61jnjoyifUaM\nByCjiFWw1xDyIpZJY5/BiPpGUbQKICOK5vwin6CpLLgqgIzsAcjIPWgVj8vkZxAyorGIowaUFP2o\nHQD2f+KDdB1+5/aAWYJ2Ux16JG5i3/2TOD47BEsVWHEh3FgncMCO052MrDIphwsOKKKaki0b0Es+\nhq7Cifg6oEBtSCgiCqU+lrTgCdVbsxAGE8UvtX4HWeG4rZqOyQWSZIXGwUVxSvfBValEeFf3DP75\nEmm/3N0/g7k2crR+j9BHju+SRS1aWQEfJsfkMKA6LiaiqobRYWJlvKvjtOwIpDCOI0MzAACPK/gP\nz/8gnfJ6GJ6YUA71k37KpWwX2hIEUeRKMfzhk9Qv9d69kzBdOuflfSkok9Rg4s67LuHZ41SIE+kr\n477uaQDAEyvjmJ6iiQFiycvqCt5x9ykAwNee2ycrcB9e2g6tLDrTJBhmRPXq3eNXMe+RQy9txGCs\n0PHNIUtOfmzUhLZIE0NbG00ykc4ClgUjBwxInKLP7TgQFbmP+mQS7gC9DkUtOfmk92QltbL2VIdk\nPrlDJozzYbDXQgeCW8T6P0bO7P3Tv47f/difAQD2hRo9SH2n6IJLvZOEwmRDCBVoUiH0cfNgByQV\nQLCw09/eYJ6cDHzHHWSn2GhMCgZrUBJdzuU+YgEqost5M2uH+T1NRbcuBpy26Ju/8u8/iIHP3n6O\n3LcW5NKylrWsZbeJMc5vHjMgvrWH7/nET2LjuW5YKZp3Q5uq1P5wDQ50CEbDhYiUAQDjyJyhGbg8\nxBBZFbre+13oBcEosRg0CgIRXaHP1+9xpAZ49HJINqZwDS5bsPF+E20BXRdVyAOYSzHwGM3q8UxV\nMih87ROANMQB4Ht6LqNDJ/jlL86/AWZR6Lg7DCnRO3Q8k8ValSLXbCmGg33EA396chx7R+n1YqkN\n2YWGdgkTZfl+Sp97DLvGqAw/CJmslBLYXGqT/793L/VIdbiCo+dJbwYuk5rk4TYT1grhU4Zoi2eu\nxMBVXwTDwwfvehQA8PXVnZhaFsnhOQM9h0glcmE5IznzD9x/Ek8ujAEA6nUNfIZWP16YIzRA+z8g\nzrfXKOChh4izbmU8aKJ5BXMBq9PHZ3hzqCGufby9iorQaWc5HenzdA2KWwCnt47l/+u/oX514VWR\nXEyyDD/CXptNjtQJunfaX1fx2S1fBgCUPMKvVDAogeg3yI7xC46ABuxhcS5lPaq8GX4JwijXwiXW\nNX7Ih3wUNKAYDwGlRMZQ8RorB990psgx+hzzf3PlnaKcH3AvT3/3i3GL2lH+TRR57kWf7Zvq0MND\ng7zv1z8EeI2qTiRtsBwtjVSTSR0WrvAGJdFj4IKSyEwVxpovrdnAaL1wQz5XJz+L8t1VhC6Q4+IM\ncuKAR82qAcJorXbaSf9YFpsVchi1ShjKusBx6wxaVTzISQ5P9CnlGYJ4uK0gKRoWV6phHB4mxsmx\n2SEpK6RpLiwhZcsrmqQqhhQH7WFyeqc3+iSkkC9HUK/Q8VmF4IzxHUuYy6bl/qp5GuuOsSUsCwli\nlzPsF9orc6UMZqdE8+ZQw0n/7dQRCSe5p2kiUPcWJMOBP5VG7SDNjj+w/RQePLef3uesUWFbCDeq\nTccK8jxL63HZgBoeEBugCS2k0eSUNOpShGvy77ehNCLuWZGhNiCaGxdUuKIgi3lA+2m6JpXvL8K+\nkBT3jcHsF0yYsIvIRQMz/+MPUVuebzn0f4Et/9o9AIDf/4W/AgDcY5TkZzb3EGb0LFa5LR0ngKbO\nSEHYxnf5QUcPNOCXG70XNCOgO6My1tT42kXDd7UplJPy4OGEEGn7uf9GWHnvHz4j9W1eq/ZSHXoL\ncmlZy1rWstvEbmpSlHnUhs6JcglnGFcN6KKxgnkhJcv2rZG6VBs8fXUAiiY6jGsc3TtJCW3uTC+8\nuJjXVY7QimhIcZG2LWbDEoYpTTjQU5Row0ysSUogNkuXYVFtR88QybZWc1Ggh0J+21LghYSexbSB\nsUMEH8R0+vzE+VE4rpDnDDnoClNU865tZ3Fyg7jkm9UIQiGKQEtWHD/YfRwA8LmVQ3hqnpa8Yd1B\n3Q7cEltoTmToOLPPDcjrU4t7SAwRDegn+p7Bx+skDVyzdNn/dGmjDWobRbE97QV8aYkUFu8fmMKF\nAiVFN1Yo4t3sjzbkZ0dddKfpHF7YGMKeIUrKnro8CC7ug1pSEZugIp/BVB7nZ0iD5sjOK4gJusm3\n50ZRr9P5lNdFhru3ICP0zTtshBfonplbTclDx3AVbIFWVm7cxeZ2EcddTMr4TLEARSRrWUmlZ6oV\nnvyLzZeN/eO/p+fp5//TCB59F0kGdKsh+DG3wdQGmwRUXg8Qo6SZ8w2xfSO49NDgpPsRusoaSc5Q\n4DVBKL4ypIY693uRMiiyj6mGVZfIAm/4ykew4z/N0Lm8xppTvBL2khw6Y+zDAH4W5E7OAPgpAFEA\nnwYwAmAGwPs455vfbT9c57C7bYSWdIQWBJzgAu5RghHsURvxEzQkJxaGNUi3+/7tk/jWKRLNSl7Q\nMasS5ZBHPQwOU0HL4loKqkn7NFP0GBnrDG/+354DAHz1K3fAjtK+Y9sKqM4IiCIK1NvpgekcyDcq\n2xyGUFg0mLbCcAXsoejA5XPE7tC76SGKdVWgCrgibtQREZrh/3RhP2E9AMZ71jH/GFVcKttqWLCI\niXJPZhqzm3T+rqfAFh18vIUoQoKGpwiRMsUCYvfSZLYx2Y6ooCH++ez9WLpK10Rrs1A5TfvGeAP7\n35Zaw6MnSQdlMZuSxUfq9xHzBqtJICEgpJqGjQI5YMfUJfukbyCHkEoT6EwxJCWFL74wDGOEIKeu\ncAlfm9pB9zNv4IGDZwAAj01Tw+0391/G554/TMcuatB20zjePHgFJ7J0XdfPdsHrpJM3YhY4EWvg\nXo3DFtRKN6QitiDwdw+wGqmHl2yv1HN9O5q7SgVkW39xDb88+AEAwKUPDeDP3ktVvvcYpQD7JST7\ncQZZLQpYk9PXA07f/64awMpjAdEs2WgcjddBmMdgGh4T4nS/9KWfwvY/oiBr6/xzr6keoK+0vWhM\nwxjrB/ArAA5zzneDJtUPAPgogG9yzicAfFP8v2Ute01Y67lu2e1oL5oUFQ/+swD2ASgC+AKAPwXw\ncQBv4pwvM8Z6AXyLc77tu+3LGO/ngx/73+EuROF1UATGHQVMyJ6qJUUWh3AGJA9Q9JidSyF5WSRj\nujncWGDWLzSicflemc6pPEwyvADgJF1k+gkiyC2kJDtm593TWCpTtF63NZRESX7mDMPGQZrrFUuB\n2kPYjTcfQ3Kb6KZzlSLrOw9P4uQiRZc7e1bgibX/9GYGtoBQ2mI1rM5S5Ky1WdjWR+X+cb0uIZpn\nVkaRFRBIoqMiE6TWeSG7O2T6tRKIxUxkYjSmbDmGumDfcM6QbqMka6Ecge0nYjkwNkjR/fTlHhir\ngjcutG4UU0F4Q3R/avfAFcEsmVVR6Re9XWsM3YeJ5TIQz+OZMxR1KzEbimDI8GUDbpr2qW7oMtJO\npGisCuMwLRqTY6twNwQjKOFgYpCuyZXVDox2071fKSZQFeqWxvkIPLG52ePIHrGxqyrSUw5OPvYn\nKG++NJbLK/lcA7dPUvTFjOm0Cs6//yAqP0Srq7/a93c4JO6LBy8Al6ioc1r1VbmLqGCduOCo+zx3\nsW1UUWGwBmDgR/wuuJS4PW2p+JkTPwEAiH8xifQ/HgMAcPv2ryh7qUnRF4VcOOeLjLHfBzAHoAbg\nYc75w4yxbs75sthsBUD3i+7LUWCvRxAqK7AM+lH3j69jaY3Wy0ouLJktisWwMUsOM7yhILIucPFt\nHvRN8WAYHJgg51XTYjDW6Hx91IQ5DN3P0YNRGNXA+4Q2ecZExyhBBKfOD0vZVVbSZDNqs72x1NPK\nDJaonBzet4xcVYh7p+hBOr/eLaGSmXxGOqzBdF7i7BU7jIHdRJlSGMf+JC0RX8gP4cwm4c+5yQyY\nYHdUygb2DBJ2fXZEaK2X///2zjxGjvvK759fVfV9Tc89wxlySA5JiaREUTZ1er22fDuJjVyLLGDA\nAYIEAYJkEwRYrBEgSP5LgGyQRRAE6yRIgHiReGF7Y6828a7s9SFbEmlKpCTeHB4zw7l7eq6+u6t+\n+eO9qZGBDSzHYo80U1+AYE93Vb1fVf/61avv773v2/m6ttbzPHPuPgADqTQbTRnTwewaP5iSYiK7\nnCC9pBkHWctdXzJeEitu6LC3r6VbNwx9VNYsFtby+Pey+j6hpnwr55Dy5PXN8gA9I/KDNv+nyPop\n5dY7hviCnP/EM7PcviJrCFXtgGQ9yRoCePajV3m5Kr4y31PjwbpsE5QTrGaFQz81uMihCbmB/mH9\nHEabTmdyTepaKNbJwPKTLp3z7z7B5b2c1/sJ286z8LXXKHxN3vsX3tO0f/0MAPPPJzCPy7z43OFr\n/LXiRQBOxho/d5yCVqduw7eW80rh/fH6Wf73PZVJfqvA6E/kN+T94DJjwdWdsbyXJ7ZH8G4olyLw\nReAwMApkjDFfeuc2VsL8v/D6GmP+njHmojHmol+pvAdDjhDhV8evOq/1GOHcbtN8qOONEOHd4N0s\nin4SuGetXQEwxnwLeA5YMsaMvOPRdPkv2tla+1XgqwCZ/nE7cN5h7fNV8q/Kots8AyTnJUrcLvwB\n8HvbpG9JZNrJWlyVcDvwkqGpyrel5zvYe3Ic68DWI5qXfF3u9NlZy8Lzmtfu+cR10TSRaJOLyw/w\nyLFF5soaPWZadAKJDNs9AeNHhKJY2BgO5QQa4x7Bq9obdEJzq4eaTBRl3SzttVjSAqL7pV5REQRO\nji5yfVmCvWP9JQ4lZDH3SxOv892qRNS/W/4kAwW56c3N9HHrJSkKyj8l9MPHH7nNz0rS7GLhzWH+\nTKVxvXU3zOu/Xxtn7GkJMDt9DuVxzRZpeeRVS6ZV8GguaH6+7hfb8ljelKi80/ZIraqWRwzYpsRq\nDoWELAQ3fY+Z65IpY59q42mRkdswtPolip7bKJA7JKqN1SmlsibLlFRF8/p/OoV5QiL7p0ZmeGNZ\naKuaa2n9VFZCzx8ucGVQnsJOTO7k2zdbHulFXRTtQHXcYn85scVfaV7Dz8/tvOndtwGj7XTwvi/0\nx8Hv77x/BbjCkwA4ySTOkBSo2WRCpBMBU5PIPVhaIWhsR/GWMXYi8QjvHu/Goc8Azxhj0sij6SeA\ni0AV+DLwr/T/b/+iAwUxqI0YvGsZ4pvKnc1KyhmIfkvhglIOQ3GqB/Q3YmH+s+Ikei/E6L0hX/zm\nZBJ7VH7smZ9mQVPgas+JU9wqpXAa2w4dYhfF0W6daLHqyfGOFVcoxeWmUK0lwsKm+JJD46I4rEzB\nUBtWXr6RoFmU115BHj/nF4u0BsSbbFaTONv8c7pBvbnzaPkbkyKmlXMbvFERx/zv73ycpBbddFou\nB3NyY5hzeqmP6g1Dx3p9czjsWBSMNHBKcsNzDlfpaJu6Vt1j+WWhcE5/5iZZvXHdnB5msyIO21v3\ncFS2NignwmscvClON79iUSl22jnwtuTYB5+c4+qSXJPaSiaUxk0dqlLTm2LhDmyqZ231uXzyqGjN\nf3f9FAAbV/roPSU3qMpSP31H5Hxjjs+6ZtY4dQeelhuB14iR1qbbd5f6iSeU838rRysv17nV6+PW\nnF/2Gfw9m9cRfjGCRoNgena3h7Hn8W449PPGmG8AbwAd4BISlWSBPzTG/B1gGviNhznQCBHeS0Tz\nOsJeRHdL/yfG7PA//4fQdkjPyL2kVbR0+oUqSczGUUkU3HdQkltHg3Cx0q0baodUebFlwlWAvjcc\nSs9q9JaS/+O3UjSPyIEKxSrtVyTLpDEQCJUA2EQAWjTkrHs7EfqJTZpT8nifKBtaZ7SxRODAokS1\n24/4QTwIx+HUHKxKDCSHqjSWJOr87FNvUm4JzTGY2AoXQp/tv8e37wp1cmZ4noQrY7+6OkxNo/tq\nWRY8c/1VEhqtl+YKOKr14rgWOyfbBAMt3EXZzx9uMaKNlxdLBdKXZZvKZIeeK3L915+U6NdbjlGY\nknNYfaZNckaO0XfNZ31SC3ieXqdSlnOYOLjC/GtyDsHROoFSS969JIl1bVRwtBMuLOdG5IvtdNxw\n29ZSOtSpKUyshyqNTtUl2C48m4vRGNnJxDn3lOjUeCbgwo81372/TbLQZPq3f5/Gnbmo9D/CnkNU\n+h8hQoQI+wxdLf3HAi0Hp+VQG5eoy6u4DP5AwuX6AKHCYt8zC6z8UCLAvsuG5JpEbGvHPA58T25U\nc58JMDWJHtcehczUdmMFLScfDPDmNW+26eAMaz51zYTa2WaogZ2RKDq2afAfE/69fTVPTKP12qMN\ncimJZGs3e+j0yM7p+2Jn8IUFqi2xU7rTS8+45LuvlXLE1+Se+b2XztIZk6eFsaE18glZB7i8PgYX\nhX+ufbbEp/tkMajux7hwSfK80yMypmSsQ+muPGXkxzfZXJVxp27HqR3Q+rhND+0jwODwGkvax9QA\njX5dAF13qTwneeHbE8AcarPaJ+eQvxoP1wkW/2qL2G2J7P3rBWKHZb/pm8N86jOXAfjzqRMkrss2\nmQVL+QXh5+P3knQm5DxjWmFamcuHi+CM+KH+fDrRwh+S82zc6CGQYJ1mvx+mVhoLt8tSEVtvxhl4\nQvLWtxoJ/PNFTC2KTyLsb3TVoccSHcaPrjCc2eSN8+Ks/IRl9cz2Fha/V5xluZYiNyMOuPS5Jn5N\nhpq/FlbTk5iPkdTK9a1zdZwFdTxaTGQstAeFzsE3oXP1kxZzSBxT/FI2LP03PmGWycpx+OTR6wC8\neOVxtmaEfnEt5NTxVNryXqWZwFfqILniUlsXp/vor02z8PqEnic0faFqHthi2Mj6qZEZ6i9I/veb\nNw+S1bz16c0i6VlxZHZETmFlthjKAW8u5EBVH90muFU9t3RAWlmH9eowwZBcw0TZoXNCzvnQ0CoZ\nT25Qb186DEDxbUNtWOVoj7+DKsk0aFu5rsmSoTahlFTZ4eKSNAY5NrLMyvdkkdePQ/GHyXBc5bi8\nrt+UY9jRDm1dzMxNuWw+Iq/np/t28v4NeGX5vv2RJs66XDevZqi9rhIHNdh8VotTXu8htWqjBhcR\n9j2ikCZChAgR9gi6GqEHazGq3xzmZ0/1bfdawPhghyQqDZouZkuGFH+1h+WnlSJxApJT27SMxWoJ\ncSdtMVodmrmUCrXRtxtcWMfBbsl+fsrS7NspYf/iibcA+Gb5KbJ35HiVIz5FHWt7OcWftKXtXPJO\ngrouzHWGWnxsTFYPX9yUxcxaM0ZfVqLf9UEfp6HKi45PZVzG0unxwwaLzmqciioL3kwNsliWSD++\n7PHKLck9tw0Xd1CrL2/I5z0LBrehEfokpBaVEhqxpE8IzVOtJVj/sH6txuJsaOn/qS1SqvZ4b7Gf\nYF1bACbFRjvnoZpixFddEqfleAnPx9f3KxM+zoJE3MVzy5TeFjpnazxF+znZKHsjTn14u3mJE+pQ\n+9ta9A4wrimTx1sk3ha6yasZsg+2n8gamFmxY+suLW3pl7icpKmUnDWG1rzyMkM+7ayDPgBFiLBv\n0VWH7qdh7Yw6qfpOfridkx9vYZowl7h4vU75tLxvptKhDG592OJrA0M73ID72sHG7iju1bUyv93T\nAZV7zb8dp3JOHIm/nOCPrmvThoRPJ63URspnVfO8EyWXpgqHtB6t8bQ2rXhnhoptyn4NE2fxtjjd\nWBty98X+m7lD5B8Rx7g1XQgzdeKnN8KGzfO3BrDbDTMONTg6KgVHUzdHcFqaDaINOKzjitwBcp3a\nGfm809+mrlouqVQLLksmSu3xenjs5loSXxtmOxYGzki9zNKSNsgueCSljor0IqwmNSf99DKVs5Kh\nYldTIU+9tFIgt51QMp+hfUacruMTZgo1Rnc48kyPXPv+dJ3SRSmwqh50SJ6UY5sLeZqqkunXXfIL\n2jvUejgqpbD5eBO3rDeow1Xsms4PDN7RCiaxo/ETIcJ+RES5RIgQIcIeQVcjdCfmkzuwSaMZIzYl\nj/xeDbJzEsW1sg6lDykFkE+zzVHEqobEhi4AXjdUDqoQfrJDUzmSxqBPXLMhOiMSLWavJqk9JpHh\n5uMtvAcS0fnDLQb/RKLvlbOGpJbWm7aHvaQCUTF44qxUOU5vFFlX8avzb0/iZHYWWkF6fWZmdEHx\nWMCaMDG4Wy7xMTm3+EiVZk5sfmRkhh/clHJ/0zG4dY1Msx1WqxJdx/saDP2pjHf1lCpNHm2FEWru\n+BobcRlreipO/qOab36/jyOfFuGvu7eGQVv3JWfjcFqi4eBWloRmncTTsjhqggSbk3K9C7cMsS0Z\n0/LlIfwxWcCNr7hh1kr2cgpP6Z9O0nDogFzD5bujofhWfNWhfUSO31LaaCmeA6VGElNJWo9oVD1g\niW1p5el0nJZ+r9tPcgA0XMYfF1mDmbdHyC7IGKvjPr25KnPuflbCjhCh2xy677C1kSI5lcTo77id\ngeVzqsnR3uF0O2kXm1ans25oFHf44u19G+tJvKxSED1t/tLzPwPgW5dEPyJ/P6A2qt4j7ZNVp9te\nT1A6ozRHzLJelpL4Yt8WLS1oqo91uHRLMjfcDY91VzJXem47VJ4XJ5VXtcHqtSJOR46Xn3Iw2g23\nOkbYyWiwUGH5htj5UXKSRFpuCsGDBPGTUuZeWcpSS+qN7nKWTemHEa4NZIp1goI41NqVIo7SL63H\naqxtyY3AqTvM/1gUDvNProVNKPxkjHZJbkqphmF6RrJFYlk5l/bxeqg70/lsHcff7gvq0FHdl85E\nA7sp46sPWFJK0bSzMH1X0yP7g50+r+kAd0mVIpVDd8dqnB2TG871lSGac+LobbGNHda+scuJHUdu\noHNIznl8YD2UFHbahsqkXMNzp+7yxvRB2p1fTswlQoS9hohyiRAhQoQ9gq5G6G7VUHwlQfnMTnOC\nwfOGjjaniG9ZKmsSUcYqlr4r2nAhB+mSUgdlh+XnNHLPN/HuyvZtEnyrKq3NHO2NuXrakD8sVIRv\nDZ2stnqL70SMhRuGZlGiyGoyga856UcmF7k7JUJUbsOEUgG1j1Y4UFQdcBVe34r10OgTm53tJwbA\nHq1Sf1NsBo+vExwX+YC4F9CrWTHzhTQTeTneraUsp0eEUrg8m6Gd14hZG3rEr+TJ3ZNjbx4lpEVa\nTpKO9lZNlZ0wz7vn6wU6h3dy793azmtPqRujfVjtwSZfOC2ZP9++8CRGFzNt22G7HaRxYLvTWHbW\nYIIgvD7b8gm0DEFBNho9UA5b423nmGd/muXCCalBKB5cw6p8QbGvwpo29yDnk9Jxtc9tEaj0Qenm\nSKjI6R2tEDyQBeypcj/MJ8MerBEi7Fd0N8slBWuPBcQ23ZCXXT6X4Og35HWjPx7qo2wcg8TrylG7\nUHpMJVybEC/J62AzE1aW+sNN0jeEc+75demqU7o4RO2t7URESCqdEvPBU+e29kSH5IIXHrsj7AIr\nlUy4X3u8idWeoqwlifXLTWLqtlT8fOwjV/nxK6ImmHngUDmsXm8pzbbW4uZKNtSYeXL8QcjJuxWH\ne+elQMdJ2VBi12kbDj0l1MT9i0KhGN/Q1Hahrd4OqYWdr89RRcTirYD5T2hTj8kYcWFzqB30wybQ\n7mSVmCsOOJMUyuXpoWl+d1j6r5bOZDmvOimxLUNCj1Ed2+lG1Ox1aeXlePUDPkPDWh27lQ6VHxeW\ne/jNZ14D4JUVaYQ9mykSm5HvaaPWF3Y66jtYYy2QNYHc8Bb1dcm+CeYzYQOSxrCPUX7ef5Dhheek\nX+lstYe1bEHSdyJE2MeIQpoIESJE2CPoaoRuOpLf7TShkxKaI1YxVMbl9dZBh+pxiRhT9+KUHpf9\ngrgVRUMgPe+Gpf3JVUNtRN/PNWkWNHNlTQpO0kuGyoR8XrxiaGj3+NpYQP6wRJTp13pJlnVxMWfC\nBb2TA0tc13FXb/eQOSbbf+XR7/KdkuSw3+lItPjyT0+Fbe8qR/xwMddUXFLL2oY0ZwoAAA3WSURB\nVMm8FaMua6xcuDPBpx6Ro9/sOcDZk8KjXL50lNiPJEqtHw24d0kaPnj6ZOG0oKPn7m26tLfpHQOB\nRrHVYY/Ymuav9wQ0JrXfYsPFZiS6bi+nsAOak68LoXcrffze2iQAvfEq9qB8HjufZv0xWXzM3Yph\ntEdq/UgTR3P8c2+kWEppEUCwk5UyOr7KT5alUOpYQVZQ/+bY67x1Qp44Xv362TBj6c7sIP0XtMDr\ncx6dgow1lm9hdCH09IEF3np7Qg7uG66UhRJbWuohXnZDGi9ChP2Krjp060KzGGAsxDc0RW3JUB3R\nDJaTDdIZ8V6dZIxOQZ3xmw7W2UkLTGmfTKcNSXWYybfy+OPKOc8Ib1I5FGAH5XjlMwkINLPFs7TO\nC3cx8lqD1VPiJSsn2hwYl/S7N2bH6M0Lzz3yoRnuLEq3lX994zME6mC2HWRytEFtSyV1AxNWZ2Zm\nnZB776RtSLkETZdbG5IV8uxjt7leEpoltegw8dclVfL6y0dw2ioZrA691WMxmjHpHqlwoFe4kOnl\nXrwZoXA2P9QgfU31U043QCtCiVmefVQqXC+8eoJOU776TV/FzZZzTObE6b547TGsOsfNRzu4FXW0\nBwNi2iybjQQHx6QI6sG5Is6i6reM1si8LNk886aXRF4LjvSOd37+EOdGpUirOh6EDWALFxOsn5DX\nQcMLOfl2JR4Wh5UbaTLTMpbqYw0O56XXKMBWPolJRmmLEfY3IsolQoQIEfYIuiufayw2EeCV3Z2s\nkWEbUii5fJ3qbXl0P/qOjvGbk6L0B5C9b9g4qzRCy+HE70vmiLu2xe2/LxTFdp56/2UoPSEH73/T\nUj6pVEQyoFWQaHDl8WQ4lviyx0JV86k7sJySqHetv048obRDssncioyx2Ceqi53AweiCXCLdpqHR\nbXXcw2iU7fgQVMSQk2kzlJYin3IzTe2KLNxmyzbsI+oXA7yqPrmMasZJIiCmvU1b5RSLurAZrCSJ\n62Jh8kqSxoA+iQQmtI8DF+5PyPYpi6OSAL4+TUwcW+LFa1oRFRjoyL0+M1iFC0IDVY+18C5rzv5M\nwP2YZLA4GzECzbIxD9Jh/1daDh8ek7Zjjtkpy7+4IIvA7lAdX/Pd3WYSr6ZjvZ0Km1pgIJaV10cL\nJX54TGwaC6/dEaXInp4q6UQrfAqIEGG/orsOPTC4VQfrEnYpou3wt5/9CQDXK8OcV43vcj0dap8k\n1g1WnyW2Dgc4mzLsgYvgloR2WPr0OCnV/9g8IQ5g7VE33G/pmR151eRAnbQ6pk5qp/OQNZBYlR16\nr/ssPymvDz+6yt3XpMpnpVXADmgWyTaFvZwg0NTCRs0Ln3uML82uAWzcJ35fbi4tLwh1vT88NMs9\n5NjP/92L/PHFswAURzdInJQB1xZ7wmsVOyYpjik3YHNJziFZdkIdlq2jO47Tth0yWk3ZKlharlJB\nIxVqc7Lv4AX5fDrbh1UnbrY8SO/QF/6H5OYTm8pSOy4Uip9M0Nsv7zfyMZragNvWXJo9+r3113ll\nSrJbUkql1VYyJJblgrcHfYyuQ7SzhoQkD7Fxuo27qV/KaCMsJuqPV8Ixpa8nQw34jVKRDz11mztu\npJ8bYX8jolwiRIgQYY+guxG6IwU9qZJDbEsiulbB8t9+9hwA7roHedV1eamfwrrSIk93QknavjcN\nW4clYjN+gE1I1JncCKgekKguptFdZ7KOMy20SWLNJfcRURhcnuojkKd+sk+U2FySgpbkg+2scZh7\nwZK/LXamFgYxeqW8MrQzuii7IRF3u6+Do52TzGATRzVFekbrYaeejVoqHJ8T92m9LBH6S+NFyEtU\n/eKrT3L8pDS7uP1gkHhKonu3JON67iNXeUPpio7vcHxSipDul8bppJXaaRo6We2RmvDx9ZQ6Ew2M\nRuCtm3nMuOT+lz6t1+FyCq8m13v90QAnKdFutZQmviQnHxytk7oqC85eXTooAZTnekjNyTbtrCW9\nJMcp38+S0oybdl4lGAbbxDdkW+vslOoXb7aZ/huq0bMQo92jRUuzKTqa+/5H338GZ2S7ZsHl+CnJ\n02/6HlcWR6h3YkSIsJ/R/RZ0AbRzFquWg3RAKI4+0iSp7c68hg31rVMLXkiLVEclHQ+g9FcabByR\n4p74JiQ16cGqE6l3Uju6L4MB9WXhgjOzLnHlS8p9PWG6m5+0xDT7Jrbp0tLCxfTrqZCXNlaaRgPU\nDoqjmTiyzPRNSaE7MbpEWrsB3VgZon4/F56nmxMH3V/cokoqvCZW+efHjj7g6hsT8nbWp6Wcu6fs\n1Ks/OhVSVdm+Gq6jKZun10ioc7U/GiR2QqiJTLLFZkIlZhcT2JRmkRxsMD4g/EY2LlTIrbkJ/Lh8\nnp5zadZkvyDvkzkjF3Z9pid8pts63qGi0rsm1aHZt63HY9iQQlDciQrukp7/pIzp9NAib5ckPdJt\nEtJq60djYGQsuXtQGZcvvDBlWX5etgkSAZ6uG3hrDjen5Zqbisexk3PMR+JcEfY5IsolQoQIEfYI\nultYFEjJvZ+09NzQKHfYpalyH7lDG9hViVzrgyaMxL0qtI/Io3bq7VTYG7QRj0NhuxOOoX5AF8Vi\n+ri+7uHrYiWxALckEW91LMDZ1v1wLd66G46v2S/bp5YcAn0q2Hq0Tf6q7JteCqgNyr7pGbl8SwM5\nUnOy8cTTZS4uCy3SupXHDmtGTmBIviXntvIY2JMSjRo3CMvfHy/McfeQVD/Va3GMyhAklDaqD1iM\nZqfU7ue50avpQdZw6IDkhC+fbJAIZHwrs0UYF/vZawkqJ1Qq90GSwUOyoNmfkCyha8Oj9PRKFL3e\nlwF9Ooj3NVhTSio959LS5tFevoVzV8bVyVoSpZ3YoD4hdoZzNZxPyfGXL0uu/dt3J8O8erdu6Mja\nLF4daMg1LH+0SfK2nNvyr3XI3tZm3J95EOrrOHEwet3SByqc65vmij4ZRYiwX9FdPfQWZGYN1jU0\n1Ik3JxuwJkSv/+NeWkptBHEo3BSnv/GxOoF2B2oWLZn5bQlVj54pccDzH/PD7ImWZlkEcbvTDm7R\nC1vANYY7NHuVh2+4tHv1UT3hk5hV0jmA1KqMpfeGw9JT242knZDG6ZmS/UqZHB1txvy9l87SGRXH\nUjy1yvodFV8xUPi4aMxMpqrhNXnz7hhntRvSXKOH6qp4cVN3cPrV6et9ym3C8LBQJf2Hq7x5S7Jj\nJo8sUq5pE2bfoaWiVWR9vISM8cQXbnGzJCmZlU6WK4tCVR0fkPSYRw4t0JuQoqGfLhwLs32Gj23y\n4MFw+J0ESsvYjkOgsrZ2PU7wuNwgWovp8KazdLc/1F4pTMuQ1p9p0tGbafJBnKZmDHk1l/xN1X0f\ndWkel0rVXK5BoyTUzuJGDjcv1zZx0yPQlnonBxc5m57m607k0CPsb0SUS4QIESLsERhru1eMYYxZ\nAapAqWtGd9C/S3Z30/Z+s3vIWjuwC3YxxmwBN3fDNvvve95N2+/rud1Vhw5gjLlorf1wV43uot3d\ntL3f7O4movm1P2y/3+d2RLlEiBAhwh5B5NAjRIgQYY9gNxz6V3fB5m7a3U3b+83ubiKaX/vD9vt6\nbnedQ48QIUKECA8HEeUSIUKECHsEXXPoxpjPGmNuGmOmjDG/85BtjRtjfmCMuWaMuWqM+S19v9cY\n85Ix5rb+X/xFx/r/tO8aYy4ZY17sll1jTI8x5hvGmBvGmOvGmGe7eL7/RK/zFWPM/zDGJLtl+/2A\nbs3t/Tiv1c6uzO0P4rzuikM3xrjAfwA+B5wEftMYc/IhmuwA/9RaexJ4BvgHau93gO9ba48B39e/\nHwZ+C8KWpHTJ7u8B37XWPgKcUfsP3a4x5gDwj4APW2tPAy7wt7ph+/2ALs/t/TivYRfm9gd2Xltr\nH/o/4FngT9/x91eAr3TDttr7NvAppPBjRN8bAW4+BFtjyBf9AvCivvdQ7QIF4B66JvKO97txvgeA\nWaAXkZJ4Efh0N2y/H/7t5tze6/Naj7src/uDOq+7RblsX5xtPND3HjqMMRPAWeA8MGStXdCPFoGh\nh2Dy3wG/TagcA12wexhYAf6rPhL/Z2NMpgt2sdbOAf8GmAEWgA1r7Z91w/b7BLsyt/fJvIZdmtsf\n1Hm9pxdFjTFZ4JvAP7bWbr7zMyu32Pc0xccY85eBZWvt6/+vbR6GXSSCeBL4j9bas4i8ws89Cj4k\nuyiH+EXkhzcKZIwxX+qG7f2KfTSvYZfm9gd1XnfLoc8B4+/4e0zfe2gwxsSQSf8H1tpv6dtLxpgR\n/XwEWH6PzT4PfMEYcx/4n8ALxpivdcHuA+CBtfa8/v0N5EfwsO0CfBK4Z61dsda2gW8Bz3XJ9vsB\nXZ3b+2xew+7N7Q/kvO6WQ/8ZcMwYc9gYE0cWF77zsIwZYwzwX4Dr1tp/+46PvgN8WV9/GeEg3zNY\na79irR2z1k4g5/jn1tovdcHuIjBrjDmhb30CuPaw7SpmgGeMMWm97p9AFq26Yfv9gK7N7f02r9X2\nbs3tD+a87hZZD3weuAXcAf7ZQ7b1EeRR6C3gsv77PNCHLOzcBr4H9D7EMXyMncWjh24XeAK4qOf8\nv4Bit84X+JfADeAK8N+BRDev9W7/69bc3o/zWu3sytz+IM7rqFI0QoQIEfYI9vSiaIQIESLsJ0QO\nPUKECBH2CCKHHiFChAh7BJFDjxAhQoQ9gsihR4gQIcIeQeTQI0SIEGGPIHLoESJEiLBHEDn0CBEi\nRNgj+L+7omDDDxCT/gAAAABJRU5ErkJggg==\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -864,18 +811,18 @@ { "cell_type": "code", "execution_count": 24, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -906,21 +853,19 @@ { "cell_type": "code", "execution_count": 25, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([ (1.0, [0.08865821621194064, 0.3784631548839458, 0.3904972254761878], [-0.1326194120629367, 0.6232164386612264, 0.7707226233389667], 1192346.6320091304, 0),\n", - " (1.0, [0.08865821621194064, 0.3784631548839458, 0.3904972254761878], [-0.6644604177986176, -0.6182443857504494, 0.41984072297352965], 356616.8122252148, 0),\n", - " (1.0, [-0.0524358478826145, -0.2989344511695743, -0.17188682459930016], [0.26140031911472983, 0.8973965547376798, 0.35545646246996265], 836460.5302888667, 0),\n", + "array([((0.04198465, 0.36778516, -0.54532495), (-0.87811811, -0.39548134, -0.26926397), 571922.4194387 , 1., 0, 0),\n", + " ((0.04198465, 0.36778516, -0.54532495), (-0.27391993, 0.65832903, -0.70112107), 1051291.75191703, 1., 0, 0),\n", + " ((0.23330238, 0.11245273, -0.49945337), ( 0.1509347 , -0.85503549, 0.49611796), 299854.82560331, 1., 0, 0),\n", " ...,\n", - " (1.0, [-0.1061743912824093, 0.2687838889464804, 0.3209783107825243], [0.04074864852534854, 0.6722488179526406, -0.7392029994559244], 4419569.703536596, 0),\n", - " (1.0, [-0.1061743912824093, 0.2687838889464804, 0.3209783107825243], [0.2921501228867853, 0.9089796683155593, 0.2973285527596903], 2716068.3317314633, 0),\n", - " (1.0, [0.24742871049665383, 0.2887788071034633, 0.12388141872813332], [0.9088435703078486, -0.040848021273558396, -0.4151322727373983], 1005076.8690394862, 0)], \n", - " dtype=[('wgt', '" + "Text(0, 0.5, 'Probability/eV')" ] }, "execution_count": 27, @@ -995,12 +936,14 @@ }, { "data": { - "image/png": "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\nAAAASUVORK5CYII=\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -1030,9 +973,7 @@ { "cell_type": "code", "execution_count": 28, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1046,18 +987,20 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], "source": [ - "plt.quiver(sp.source['xyz'][:,0], sp.source['xyz'][:,1],\n", - " sp.source['uvw'][:,0], sp.source['uvw'][:,1],\n", + "plt.quiver(sp.source['r']['x'], sp.source['r']['y'],\n", + " sp.source['u']['x'], sp.source['u']['y'],\n", " np.log(sp.source['E']), cmap='jet', scale=20.0)\n", "plt.colorbar()\n", "plt.xlim((-0.5,0.5))\n", @@ -1081,9 +1024,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.0" + "version": "3.6.7" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/examples/jupyter/search.ipynb b/examples/jupyter/search.ipynb index 5c754049a..0299f319a 100644 --- a/examples/jupyter/search.ipynb +++ b/examples/jupyter/search.ipynb @@ -14,9 +14,7 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Initialize third-party libraries and the OpenMC Python API\n", @@ -43,9 +41,7 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# Create the model. `ppm_Boron` will be the parametric variable.\n", @@ -139,24 +135,160 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + " warn(msg, IDWarning)\n" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ - "Iteration: 1; Guess of 1.00e+03 produced a keff of 1.08721 +/- 0.00158\n", - "Iteration: 2; Guess of 2.50e+03 produced a keff of 0.95263 +/- 0.00147\n", - "Iteration: 3; Guess of 1.75e+03 produced a keff of 1.01466 +/- 0.00163\n", - "Iteration: 4; Guess of 2.12e+03 produced a keff of 0.98475 +/- 0.00167\n", - "Iteration: 5; Guess of 1.94e+03 produced a keff of 0.99954 +/- 0.00154\n", - "Iteration: 6; Guess of 1.84e+03 produced a keff of 1.00428 +/- 0.00162\n", - "Iteration: 7; Guess of 1.89e+03 produced a keff of 1.00633 +/- 0.00166\n", - "Iteration: 8; Guess of 1.91e+03 produced a keff of 1.00388 +/- 0.00166\n", - "Iteration: 9; Guess of 1.93e+03 produced a keff of 0.99813 +/- 0.00142\n", - "Critical Boron Concentration: 1926 ppm\n" + "Iteration: 1; Guess of 1.00e+03 produced a keff of 1.08853 +/- 0.00158\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + " warn(msg, IDWarning)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration: 2; Guess of 2.50e+03 produced a keff of 0.95372 +/- 0.00148\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + " warn(msg, IDWarning)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration: 3; Guess of 1.75e+03 produced a keff of 1.01328 +/- 0.00169\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + " warn(msg, IDWarning)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration: 4; Guess of 2.12e+03 produced a keff of 0.98150 +/- 0.00158\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + " warn(msg, IDWarning)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration: 5; Guess of 1.94e+03 produced a keff of 0.99886 +/- 0.00146\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + " warn(msg, IDWarning)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration: 6; Guess of 1.84e+03 produced a keff of 1.00759 +/- 0.00162\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + " warn(msg, IDWarning)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration: 7; Guess of 1.89e+03 produced a keff of 1.00063 +/- 0.00166\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + " warn(msg, IDWarning)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration: 8; Guess of 1.91e+03 produced a keff of 0.99970 +/- 0.00150\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", + " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", + "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + " warn(msg, IDWarning)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration: 9; Guess of 1.90e+03 produced a keff of 0.99935 +/- 0.00164\n", + "Critical Boron Concentration: 1902 ppm\n" ] } ], @@ -178,19 +310,19 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, + "execution_count": 5, + "metadata": {}, "outputs": [ { "data": { - "image/png": "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\nb2ZmVnJO9mZmZiXnZG9mZlZyTvZmZmYl52RvZmZWck72ZmZmJedkb2ZmVnJO9mZmZiVX2B30Wtlt\nC5Yzfc4SVqxZz6j2NqZOPIjJh/spu2Zm1pqc7KvctmA502YvYv2GTQAsX7OeabMXATjhm5lZS3I3\nfpXpc5ZsTvQV6zdsYvqcJU2KyMzMbPs42VdZsWb9NpWbmZkNdE72VUa1t21TuZmZ2UDnZF9l6sSD\naBs2ZIuytmFDmDrxoCZFZGZmtn08QK9KZRCeR+ObmVlZONnXMPnw0U7uZmZWGu7GNzMzKzknezMz\ns5IrLNlLmilplaRH69RL0lWSlkpaKOmIXN3lkhZLejwto6LiNDMzK7siz+yvByZ1U38ycEB6TQG+\nDiDp7cD/AA4F3gocCZxQYJxmZmalVliyj4h5wIvdLHIqMCsy9wPtkvYGAtgJ2BF4DTAMeK6oOM3M\nzMqumdfsRwPLcvNdwOiI+AVwL7AyveZExONNiM/MzKwUmpnsa12HD0lvAt4CjCH7QnCipONrbkCa\nIqlTUufq1asLDNXMzKx1NTPZdwH75ObHACuA9wL3R8S6iFgH3AkcU2sDETEjIjoiomPkyJGFB2xm\nZtaKmpnsbwfOTqPyjwHWRsRK4NfACZKGShpGNjjP3fhmZma9VNgd9CTdCEwARkjqAi4hG2xHRFwL\n3AGcAiwFXgLOS6veApwILCIbrPejiPh+UXGamZmVXWHJPiLO7KE+gPNrlG8C/rqouMzMzAYb30HP\nzMys5JzszczMSs7J3szMrOSc7M3MzErOyd7MzKzknOzNzMxKzsnezMys5JzszczMSs7J3szMrOSc\n7M3MzErOyd7MzKzknOzNzMxKzsnezMys5JzszczMSs7J3szMrOSc7M3MzErOyd7MzKzknOzNzMxK\nrrBkL2mmpFWSHq1TL0lXSVoqaaGkI3J1+0q6S9Ljkh6TNLaoOM3MzMquyDP764FJ3dSfDByQXlOA\nr+fqZgHTI+ItwFHAqoJiNDMzK72hRW04Iub1cEZ+KjArIgK4X1K7pL2B3YGhEXF32s66omI0MzMb\nDJp5zX40sCw335XKDgTWSJotaYGk6ZKGNCVCMzOzEmhmsleNsiDrbTgOuBA4EngDcG7NDUhTJHVK\n6ly9enVRcZqZmbW0Zib7LmCf3PwYYEUqXxART0fERuA24Iga6xMRMyKiIyI6Ro4cWXjAZmZmraiZ\nyf524Ow0Kv8YYG1ErAQeBHaXVMneJwKPNStIMzOzVlfYAD1JNwITgBGSuoBLgGEAEXEtcAdwCrAU\neAk4L9VtknQhcI8kAfOB64qK08zMrOyKHI1/Zg/1AZxfp+5u4NAi4jIzMxtsfAc9MzOzknOyNzMz\nKzknezMzs5JzsjczMys5J3szM7OSc7I3MzMrOSd7MzOzknOyNzMzKzknezMzs5JzsjczMys5J3sz\nM7OSc7I3MzMrOSd7MzOzknOyNzMzKzknezMzs5JzsjczMys5J3szM7OSc7I3MzMrOSd7MzOzkiss\n2UuaKWmVpEfr1EvSVZKWSloo6Yiq+uGSlku6uqgYzczMBoMiz+yvByZ1U38ycEB6TQG+XlX/ReC+\nQiIzMzMbRApL9hExD3ixm0VOBWZF5n6gXdLeAJLeBuwF3FVUfGZmZoNFM6/ZjwaW5ea7gNGSdgC+\nCkxtSlRmZmYl08xkrxplAXwcuCMiltWo33ID0hRJnZI6V69e3ecBmpmZlcHQJu67C9gnNz8GWAEc\nCxwn6ePALsCOktZFxEXVG4iIGcAMgI6Ojig+ZDMzs9bTzGR/O3CBpJuAo4G1EbESOKuygKRzgY5a\nid7MzMwa01Cyl7QX8GVgVEScLGkccGxEfKObdW4EJgAjJHUBlwDDACLiWuAO4BRgKfAScN52tMPM\nzMzqUETPvd+S7gS+CVwcEYdJGgosiIhDig6wUR0dHdHZ2dnsMMzMzPqNpPkR0dHTco0O0BsRETcD\nrwBExEZg03bEZ2ZmZv2k0WT/B0l7ko2WR9IxwNrCojIzM7M+0+gAvc+QDah7o6SfASOB9xUWlZmZ\nmfWZhpJ9RDwk6QTgILLfxy+JiA2FRmZmZmZ9otHR+GdXFR0hiYiYVUBMZmZm1oca7cY/Mje9E/Au\n4CHAyd7MzGyAa7Qb/xP5eUm7Af9RSERmZmbWp3p7b/yXyB5Na2ZmZgNco9fsv0/62R3ZF4RxwM1F\nBWVmZmZ9p9Fr9lfkpjcCv4qIrgLiMTMzsz7W6DX7+4oOxMzMzIrRbbKX9Hte7b7fogqIiBheSFRm\nZmbWZ7pN9hGxa38FYmZmZsXYpufZS3od2e/sAYiIX/d5RGZmZtanGvrpnaT3SHoSeAa4D3gWuLPA\nuMzMzKyPNPo7+y8CxwBPRMT+ZHfQ+1lhUZmZmVmfaTTZb4iIF4AdJO0QEfcC4wuMy8zMzPpIo9fs\n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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -198,7 +330,7 @@ "plt.figure(figsize=(8, 4.5))\n", "plt.title('Eigenvalue versus Boron Concentration')\n", "# Create a scatter plot using the mean value of keff\n", - "plt.scatter(guesses, [keffs[i][0] for i in range(len(keffs))])\n", + "plt.scatter(guesses, [keffs[i].nominal_value for i in range(len(keffs))])\n", "plt.xlabel('Boron Concentration [ppm]')\n", "plt.ylabel('Eigenvalue')\n", "plt.show()" @@ -230,7 +362,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.0" + "version": "3.6.7" } }, "nbformat": 4, From 039d5c0b63f0be83050b39bd5c4abd90acac1a07 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Apr 2019 15:09:10 -0500 Subject: [PATCH 156/165] Adding check for a valid delayed group filter when scoring. --- src/tallies/tally_scoring.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index 7e235fa45..c2e5fb208 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -257,7 +257,9 @@ score_fission_eout(const Particle* p, int i_tally, int i_score, int score_bin) #pragma omp atomic tally.results_(filter_index, i_score, RESULT_VALUE) += score; - } else if (score_bin == SCORE_DELAYED_NU_FISSION && g != 0) { + } else if (score_bin == SCORE_DELAYED_NU_FISSION && + g != 0 && + tally.delayedgroup_filter_ > 0) { // Get the index of the delayed group filter auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; From 11acaacb4f628eb1a06b672a9962f3a1cd1b2b36 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 2 Apr 2019 15:39:03 -0500 Subject: [PATCH 157/165] Changing check for valid delayed group filter. --- src/tallies/tally_scoring.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index c2e5fb208..80c7444ce 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -258,15 +258,15 @@ score_fission_eout(const Particle* p, int i_tally, int i_score, int score_bin) tally.results_(filter_index, i_score, RESULT_VALUE) += score; } else if (score_bin == SCORE_DELAYED_NU_FISSION && - g != 0 && - tally.delayedgroup_filter_ > 0) { - - // Get the index of the delayed group filter - auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; + g != 0) { // If the delayed group filter is present, tally to corresponding delayed // group bin if it exists - if (i_dg_filt >= 0) { + if (tally.delayedgroup_filter_ >= 0) { + + // Get the index of the delayed group filter + auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; + const DelayedGroupFilter& dg_filt {*dynamic_cast( model::tally_filters[i_dg_filt].get())}; From 7351773b2957c0f415b5dc8ae8f6bd5a3a00bfdd Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 3 Apr 2019 10:48:06 -0500 Subject: [PATCH 158/165] Addressing comments from @paulromano. --- include/openmc/geometry.h | 2 +- src/geometry.cpp | 2 +- src/lattice.cpp | 20 +++++++++++--------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/openmc/geometry.h b/include/openmc/geometry.h index 43b595bc1..39f500b84 100644 --- a/include/openmc/geometry.h +++ b/include/openmc/geometry.h @@ -39,7 +39,7 @@ struct BoundaryInfo { //! Check two distances by coincidence tolerance //============================================================================== -bool coincident(const double& d1, const double& d2); +bool coincident(double d1, double d2); //============================================================================== //! Check for overlapping cells at a particle's position. diff --git a/src/geometry.cpp b/src/geometry.cpp index f4c24bcd5..225a4970f 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -32,7 +32,7 @@ std::vector overlap_check_count; // Non-member functions //============================================================================== -bool coincident(const double& d1, const double& d2) { +bool coincident(double d1, double d2) { return std::abs(d1 - d2) < FP_COINCIDENT; } diff --git a/src/lattice.cpp b/src/lattice.cpp index de077bbe6..87ec3c83f 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -6,6 +6,7 @@ #include "openmc/cell.h" #include "openmc/error.h" +#include "openmc/geometry.h" #include "openmc/geometry_aux.h" #include "openmc/hdf5_interface.h" #include "openmc/string_utils.h" @@ -291,7 +292,7 @@ RectLattice::get_indices(Position r, Direction u) const double ix_ {(r.x - lower_left_.x) / pitch_.x}; long ix_close {std::lround(ix_)}; int ix; - if (std::abs(ix_ - ix_close) < FP_COINCIDENT) { + if (coincident(ix_, ix_close)) { ix = (u.x > 0) ? ix_close : ix_close - 1; } else { ix = std::floor(ix_); @@ -301,7 +302,7 @@ RectLattice::get_indices(Position r, Direction u) const double iy_ {(r.y - lower_left_.y) / pitch_.y}; long iy_close {std::lround(iy_)}; int iy; - if (std::abs(iy_ - iy_close) < FP_COINCIDENT) { + if (coincident(iy_, iy_close)) { iy = (u.y > 0) ? iy_close : iy_close - 1; } else { iy = std::floor(iy_); @@ -312,7 +313,7 @@ RectLattice::get_indices(Position r, Direction u) const if (is_3d_) { double iz_ {(r.z - lower_left_.z) / pitch_.z}; long iz_close {std::lround(iz_)}; - if (std::abs(iz_ - iz_close) < FP_COINCIDENT) { + if (coincident(iz_, iz_close)) { iz = (u.z > 0) ? iz_close : iz_close - 1; } else { iz = std::floor(iz_); @@ -711,18 +712,19 @@ std::array HexLattice::get_indices(Position r, Direction u) const { // result variables - int ix{}, ia{}, iz{}; + int ix = 0; + int ia = 0; + int iz = 0; // Offset the xyz by the lattice center. Position r_o {r.x - center_.x, r.y - center_.y, r.z}; if (is_3d_) {r_o.z -= center_.z;} - // Index the z direction. Same as the technique used in - // RectLattice::get_indices. + // Index the z direction, accounting for coincidence if (is_3d_) { double iz_ {r_o.z / pitch_[1] + 0.5 * n_axial_}; long iz_close {std::lround(iz_)}; - if (std::abs(iz_ - iz_close) < FP_COINCIDENT) { + if (coincident(iz_, iz_close)) { iz = (u.z > 0) ? iz_close : iz_close - 1; } else { iz = std::floor(iz_); @@ -769,14 +771,14 @@ HexLattice::get_indices(Position r, Direction u) const // calculate distance double d = r_t.x*r_t.x + r_t.y*r_t.y; // check for coincidence - bool on_boundary = std::abs(d - d_min) < FP_COINCIDENT; + bool on_boundary = coincident(d, d_min); if (d < d_min || on_boundary) { // normalize r_t and find dot product r_t /= std::sqrt(d); double dp = u.x * r_t.x + u.y * r_t.y; // do not update values if particle is on a // boundary and not moving into this cell - if (on_boundary && dp > dp_min) { continue; } + if (on_boundary && dp > dp_min) continue; // update values d_min = d; ix_chg = j; From 33c1f64100ceb752545e161eb54cb5b0c5632f6c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 3 Apr 2019 11:05:58 -0500 Subject: [PATCH 159/165] Updating lattice_hex_coincident test to use Python API. --- .../lattice_hex_coincident/geometry.xml | 34 ---- .../lattice_hex_coincident/inputs_true.dat | 81 ++++++++++ .../lattice_hex_coincident/materials.xml | 31 ---- .../lattice_hex_coincident/settings.xml | 16 -- .../lattice_hex_coincident/test.py | 148 +++++++++++++++++- 5 files changed, 227 insertions(+), 83 deletions(-) delete mode 100644 tests/regression_tests/lattice_hex_coincident/geometry.xml create mode 100644 tests/regression_tests/lattice_hex_coincident/inputs_true.dat delete mode 100644 tests/regression_tests/lattice_hex_coincident/materials.xml delete mode 100644 tests/regression_tests/lattice_hex_coincident/settings.xml diff --git a/tests/regression_tests/lattice_hex_coincident/geometry.xml b/tests/regression_tests/lattice_hex_coincident/geometry.xml deleted file mode 100644 index aa2d09189..000000000 --- a/tests/regression_tests/lattice_hex_coincident/geometry.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - 1.4 - 3 -
0.0 0.0
- - 2 -2 2 - 1 -2 2 - 2 -
- - - - - - - - - - - - -
diff --git a/tests/regression_tests/lattice_hex_coincident/inputs_true.dat b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat new file mode 100644 index 000000000..8d73f6374 --- /dev/null +++ b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat @@ -0,0 +1,81 @@ + + + + + + + + + + + + 1.4 + 11 +
0.0 0.0
+ + 10 +10 10 + 9 +10 10 + 10 +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + -0.9899494936611666 -0.9899494936611666 0.0 0.9899494936611666 0.9899494936611666 10.0 + + + + false + + 22 + diff --git a/tests/regression_tests/lattice_hex_coincident/materials.xml b/tests/regression_tests/lattice_hex_coincident/materials.xml deleted file mode 100644 index 164aa27fe..000000000 --- a/tests/regression_tests/lattice_hex_coincident/materials.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/regression_tests/lattice_hex_coincident/settings.xml b/tests/regression_tests/lattice_hex_coincident/settings.xml deleted file mode 100644 index 0d72a853b..000000000 --- a/tests/regression_tests/lattice_hex_coincident/settings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - eigenvalue - 1000 - 10 - 5 - - - -0.9899494936611666 -0.9899494936611666 0.0 0.9899494936611666 0.9899494936611666 10.0 - - - - false - - 22 - diff --git a/tests/regression_tests/lattice_hex_coincident/test.py b/tests/regression_tests/lattice_hex_coincident/test.py index 06ee724f9..65786e2ec 100644 --- a/tests/regression_tests/lattice_hex_coincident/test.py +++ b/tests/regression_tests/lattice_hex_coincident/test.py @@ -1,6 +1,150 @@ -from tests.testing_harness import TestHarness +import numpy as np +import openmc +from tests.testing_harness import PyAPITestHarness + + +class HexLatticeCoincidentTestHarness(PyAPITestHarness): + def _build_inputs(self): + materials = openmc.Materials() + + fuel_mat = openmc.Material() + fuel_mat.add_nuclide('U235', 4.9817E-03, 'ao') + materials.append(fuel_mat) + + matrix = openmc.Material() + matrix.set_density('atom/b-cm', 8.7742E-02) + matrix.add_element('C', 1.0, 'ao') + matrix.add_s_alpha_beta('c_Graphite') + materials.append(matrix) + + lead = openmc.Material(name="Lead") + lead.set_density('g/cm3', 10.32) + lead.add_nuclide('Pb204', 0.014, 'ao') + lead.add_nuclide('Pb206', 0.241, 'ao') + lead.add_nuclide('Pb207', 0.221, 'ao') + lead.add_nuclide('Pb208', 0.524, 'ao') + materials.append(lead) + + coolant = openmc.Material() + coolant.set_density('atom/b-cm', 5.4464E-04) + coolant.add_nuclide('He4', 1.0, 'ao') + materials.append(coolant) + + zirc = openmc.Material(name="Zirc4") + zirc.add_nuclide('Zr90', 2.217E-02, 'ao') + zirc.add_nuclide('Zr91', 4.781E-03, 'ao') + zirc.add_nuclide('Zr92', 7.228E-03, 'ao') + zirc.add_nuclide('Zr94', 7.169E-03, 'ao') + zirc.add_nuclide('Zr96', 1.131E-03, 'ao') + materials.append(zirc) + + materials.export_to_xml() + + ### Geometry ### + pin_rad = 0.7 # cm + assembly_pitch = 1.4 # cm + + cool_rad = 0.293 # cm + zirc_clad_thickness = 0.057 # cm + zirc_ir = cool_rad # cm + zirc_or = cool_rad + zirc_clad_thickness # cm + lead_thickness = 0.002 # cm + lead_ir = zirc_or # cm + lead_or = zirc_or + lead_thickness # cm + + cyl = openmc.ZCylinder(x0=0., y0=0., r=pin_rad) + fuel_btm = openmc.ZPlane(z0=0.0, boundary_type = 'reflective') + fuel_top = openmc.ZPlane(z0=10.0, boundary_type = 'reflective') + region = -cyl & +fuel_btm & -fuel_top + + container = openmc.Cell(region=region) + container.fill = fuel_mat + + fuel_outside = openmc.Cell() + fuel_outside.region = +cyl + fuel_outside.fill = matrix + + fuel_ch_univ = openmc.Universe(cells=[container, fuel_outside]) + + # Coolant Channel + cool_outer = openmc.ZCylinder(x0=0.0, y0=0.0, r=cool_rad) + zirc_outer = openmc.ZCylinder(x0=0.0, y0=0.0, r=zirc_or) + lead_outer = openmc.ZCylinder(x0=0.0, y0=0.0, r=lead_or) + + coolant_ch = openmc.Cell(name="coolant") + coolant_ch.region = -cool_outer & +fuel_btm & -fuel_top + coolant_ch.fill = coolant + + zirc_shell = openmc.Cell(name="zirconium_shell") + zirc_shell.region = +cool_outer & -zirc_outer & +fuel_btm & -fuel_top + zirc_shell.fill = zirc + + lead_shell = openmc.Cell(name="lead_shell") + lead_shell.region = +zirc_outer & -lead_outer & +fuel_btm & -fuel_top + lead_shell.fill = lead + + coolant_matrix = openmc.Cell(name="matrix coolant surround") + coolant_matrix.region = +lead_outer & +fuel_btm & -fuel_top + coolant_matrix.fill = matrix + + coolant_channel = [coolant_ch, zirc_shell, lead_shell, coolant_matrix] + + coolant_univ = openmc.Universe(name="coolant universe") + coolant_univ.add_cells(coolant_channel) + + half_width = assembly_pitch # cm + edge_length = (2./np.sqrt(3.0)) * half_width + + inf_mat = openmc.Cell() + inf_mat.fill = matrix + + inf_mat_univ = openmc.Universe(cells=[inf_mat,]) + + # a hex surface for the core to go inside of + hexprism = openmc.model.get_hexagonal_prism(edge_length=edge_length, + origin=(0.0, 0.0), + boundary_type = 'reflective', + orientation='x') + + pincell_only_lattice = openmc.HexLattice(name="regular fuel assembly") + pincell_only_lattice.center = (0., 0.) + pincell_only_lattice.pitch = (assembly_pitch,) + pincell_only_lattice.outer = inf_mat_univ + + # setup hex rings + ring0 = [fuel_ch_univ] + ring1 = [coolant_univ] * 6 + pincell_only_lattice.universes = [ring1, ring0] + + pincell_only_cell = openmc.Cell(name="container cell") + pincell_only_cell.region = hexprism & +fuel_btm & -fuel_top + pincell_only_cell.fill = pincell_only_lattice + + root_univ = openmc.Universe(name="root universe", cells=[pincell_only_cell,]) + + geom = openmc.Geometry(root_univ) + geom.export_to_xml() + + ### Settings ### + + settings = openmc.Settings() + settings.run_mode = 'eigenvalue' + + source = openmc.Source() + corner_dist = np.sqrt(2) * pin_rad + ll = [-corner_dist, -corner_dist, 0.0] + ur = [corner_dist, corner_dist, 10.0] + source.space = openmc.stats.Box(ll, ur) + source.strength = 1.0 + settings.source = source + settings.output = {'summary' : False} + settings.batches = 10 + settings.inactive = 5 + settings.particles = 1000 + settings.seed = 22 + settings.export_to_xml() def test_lattice_hex_coincident_surf(): - harness = TestHarness('statepoint.10.h5') + harness = HexLatticeCoincidentTestHarness('statepoint.10.h5') harness.main() From 81388cf5b9196dab286cfddb811c8a6bc4f287ce Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 3 Apr 2019 11:23:56 -0500 Subject: [PATCH 160/165] Updates based on comments from @paulromano. --- examples/jupyter/search.ipynb | 24 +++---------------- .../python/pincell_depletion/run_depletion.py | 1 - scripts/openmc-plot-mesh-tally | 2 -- src/tallies/tally_scoring.cpp | 3 +-- 4 files changed, 4 insertions(+), 26 deletions(-) diff --git a/examples/jupyter/search.ipynb b/examples/jupyter/search.ipynb index 0299f319a..6031c4c4d 100644 --- a/examples/jupyter/search.ipynb +++ b/examples/jupyter/search.ipynb @@ -70,8 +70,8 @@ " materials = openmc.Materials([fuel, zircaloy, water])\n", " \n", " # Create cylinders for the fuel and clad\n", - " fuel_outer_radius = openmc.ZCylinder(R=0.39218)\n", - " clad_outer_radius = openmc.ZCylinder(R=0.45720)\n", + " fuel_outer_radius = openmc.ZCylinder(r=0.39218)\n", + " clad_outer_radius = openmc.ZCylinder(r=0.45720)\n", "\n", " # Create boundary planes to surround the geometry\n", " min_x = openmc.XPlane(x0=-0.63, boundary_type='reflective')\n", @@ -141,8 +141,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] @@ -158,8 +156,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] @@ -175,8 +171,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] @@ -192,8 +186,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] @@ -209,8 +201,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] @@ -226,8 +216,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] @@ -243,8 +231,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] @@ -260,8 +246,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] @@ -277,8 +261,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n", "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] @@ -310,7 +292,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { diff --git a/examples/python/pincell_depletion/run_depletion.py b/examples/python/pincell_depletion/run_depletion.py index c4319eb96..c1ad9d20a 100644 --- a/examples/python/pincell_depletion/run_depletion.py +++ b/examples/python/pincell_depletion/run_depletion.py @@ -16,7 +16,6 @@ particles = 1000 time_step = 1*24*60*60 # s final_time = 5*24*60*60 # s time_steps = np.full(final_time // time_step, time_step) -print(time_steps) chain_file = './chain_simple.xml' power = 174 # W/cm, for 2D simulations only (use W for 3D) diff --git a/scripts/openmc-plot-mesh-tally b/scripts/openmc-plot-mesh-tally index 7c42b7281..183fe35c5 100755 --- a/scripts/openmc-plot-mesh-tally +++ b/scripts/openmc-plot-mesh-tally @@ -230,8 +230,6 @@ class MeshPlotter(tk.Frame): v_ind = 2 axial_ind = 3 - (h_ind + v_ind) - print(h_ind, v_ind) - print(dims) dims = (dims[h_ind], dims[v_ind]) mesh_dim = len(self.mesh.dimension) diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index 80c7444ce..8d51aa7f2 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -257,8 +257,7 @@ score_fission_eout(const Particle* p, int i_tally, int i_score, int score_bin) #pragma omp atomic tally.results_(filter_index, i_score, RESULT_VALUE) += score; - } else if (score_bin == SCORE_DELAYED_NU_FISSION && - g != 0) { + } else if (score_bin == SCORE_DELAYED_NU_FISSION && g != 0) { // If the delayed group filter is present, tally to corresponding delayed // group bin if it exists From 63dd99c089ed922628600f3dafdac729a608d3e0 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 3 Apr 2019 13:51:35 -0500 Subject: [PATCH 161/165] Addressing @smharper's comments. --- include/openmc/geometry.h | 4 +++- src/geometry.cpp | 6 +----- src/lattice.cpp | 28 ++++++++++++---------------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/include/openmc/geometry.h b/include/openmc/geometry.h index 39f500b84..8e6e8a82e 100644 --- a/include/openmc/geometry.h +++ b/include/openmc/geometry.h @@ -39,7 +39,9 @@ struct BoundaryInfo { //! Check two distances by coincidence tolerance //============================================================================== -bool coincident(double d1, double d2); +inline bool coincident(double d1, double d2) { + return std::abs(d1 - d2) < FP_COINCIDENT; +} //============================================================================== //! Check for overlapping cells at a particle's position. diff --git a/src/geometry.cpp b/src/geometry.cpp index 225a4970f..d70e1ed0b 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -32,10 +32,6 @@ std::vector overlap_check_count; // Non-member functions //============================================================================== -bool coincident(double d1, double d2) { - return std::abs(d1 - d2) < FP_COINCIDENT; -} - bool check_cell_overlap(Particle* p) { int n_coord = p->n_coord_; @@ -400,7 +396,7 @@ BoundaryInfo distance_to_boundary(Particle* p) // a higher level then we need to make sure that the higher level boundary // is selected. This logic must consider floating point precision. double& d = info.distance; - if (d_surf < d_lat && !coincident(d_surf, d_lat)) { + if (d_surf < d_lat - FP_COINCIDENT) { if (d == INFINITY || (d - d_surf)/d >= FP_REL_PRECISION) { d = d_surf; diff --git a/src/lattice.cpp b/src/lattice.cpp index 87ec3c83f..dc1b1d8fe 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -711,16 +711,23 @@ const std::array HexLattice::get_indices(Position r, Direction u) const { - // result variables - int ix = 0; - int ia = 0; - int iz = 0; - // Offset the xyz by the lattice center. Position r_o {r.x - center_.x, r.y - center_.y, r.z}; if (is_3d_) {r_o.z -= center_.z;} + // Convert coordinates into skewed bases. The (x, alpha) basis is used to + // find the index of the global coordinates to within 4 cells. + double alpha = r_o.y - r_o.x / std::sqrt(3.0); + int ix = std::floor(r_o.x / (0.5*std::sqrt(3.0) * pitch_[0])); + int ia = std::floor(alpha / pitch_[0]); + + // Add offset to indices (the center cell is (i_x, i_alpha) = (0, 0) but + // the array is offset so that the indices never go below 0). + ix += n_rings_-1; + ia += n_rings_-1; + // Index the z direction, accounting for coincidence + int iz{}; if (is_3d_) { double iz_ {r_o.z / pitch_[1] + 0.5 * n_axial_}; long iz_close {std::lround(iz_)}; @@ -731,17 +738,6 @@ HexLattice::get_indices(Position r, Direction u) const } } - // Convert coordinates into skewed bases. The (x, alpha) basis is used to - // find the index of the global coordinates to within 4 cells. - double alpha = r_o.y - r_o.x / std::sqrt(3.0); - ix = std::floor(r_o.x / (0.5*std::sqrt(3.0) * pitch_[0])); - ia = std::floor(alpha / pitch_[0]); - - // Add offset to indices (the center cell is (i_x, i_alpha) = (0, 0) but - // the array is offset so that the indices never go below 0). - ix += n_rings_-1; - ia += n_rings_-1; - // Calculate the (squared) distance between the particle and the centers of // the four possible cells. Regular hexagonal tiles form a Voronoi // tessellation so the xyz should be in the hexagonal cell that it is closest From b05d8b4e2fba62fdfb1a6cdb0f89358896a5493d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 3 Apr 2019 14:54:13 -0500 Subject: [PATCH 162/165] Removing another warning messgage in jupyter notebook. --- examples/jupyter/post-processing.ipynb | 350 +++---------------------- 1 file changed, 37 insertions(+), 313 deletions(-) diff --git a/examples/jupyter/post-processing.ipynb b/examples/jupyter/post-processing.ipynb index c8792fa6d..1223f67f3 100644 --- a/examples/jupyter/post-processing.ipynb +++ b/examples/jupyter/post-processing.ipynb @@ -92,20 +92,11 @@ "cell_type": "code", "execution_count": 4, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/shriwise/.pyenv/versions/3.6.7/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/surface.py:1300: FutureWarning: \"ZCylinder(...) accepts an argument named 'r', not 'R'. Future versions of OpenMC will not accept the capitalized version.\n", - " warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning)\n" - ] - } - ], + "outputs": [], "source": [ "# Create cylinders for the fuel and clad\n", - "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, R=0.39218)\n", - "clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, R=0.45720)\n", + "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.39218)\n", + "clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.45720)\n", "\n", "# Create boundary planes to surround the geometry\n", "min_x = openmc.XPlane(x0=-0.63, boundary_type='reflective')\n", @@ -212,7 +203,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -245,7 +236,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -271,7 +262,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -281,12 +272,12 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEVyEhLpgJFNv8T///98iBL0AAAAAWJLR0QDEQxM8gAAAAd0SU1FB+MEAg0jGz+ZgBkAAAKlSURBVGje7ZrBscIwDETxwSWkn5TAgXCgBPqhBA6kyj/fDhCIJa2zZAwz0pmHpZWdSazd7Tw8PDw8PDw8vinCMBzW03HIsRLvhnv0HL7qD+IwjzXKzaNaxeEt9kz21RWEBV5XQbfka3pQWL4qgdLyNQkUcbwFT/FP4zjWt+D+++OY4laZQJgtnqNOwe5l9XkGmIIL/PEHUAGTeuc5P15wBbu34ucSIAXkX77h4xUtIBSXnxIAOhCLy98TANNfLj8lYBYQCuLPWmAWEBe9f90DUPdKy08JWB0U1HsoaAgQxPSnAgwBopz+VABQvoDnAnqTP0r8zealzfPcQqqAQSs/C6AKGLX0pwKs8uX0cwGaAHr6uYC9wSt46qDCB4RXBDTkMwWMhnxZQF3+s8pf1AZY5VsCWuVnAUQ+YPxB43X5koAiH035soCa/AaeBOw34m359AaQPCK/1oAAyJ8aIPBI+7QGRkD+3IBt+A6QPzeg34SH2pcauN+Kt9uXGljkse0jb6BP8AD+vwGKPLZ95A0UofbnDbAFj20/eQN+gD8h/LgRD25/8QCA2088AD/Oo8dPOoDo8ZMOoPPNeej4pwdAgUcfX9IDzHnnf5lnz88XnH/nSf4M8cIL7I+/P3yCP0G88P7W+v2z9ft36+8P9vuJ/X5r/f3Jfj83//5vff/R+v6Hvb9i78/Y+7vW94/N71/Z+2P2/pq9P2fv7+n5ATu/YOcn7PyGnR+x8yt6ftYN3PzOENCcH7LzS3Z+Ss9vO62DV5uPmgAXSz5+fs7O72n/QBQLwPwLrH+C9W/Q/hHWv8L6Z2j/ThZgvX+I9S/R/inWv8X6x2j/Guufo/17rH+Q9S/S/knWv0n7R2n/Kuufpf27tH+Y9i/vWP+0h4eHh4eHh8cW8QcxLJDBvLKoigAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOS0wNC0wMlQxMzozNToyNy0wNTowMIPRP68AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTktMDQtMDJUMTM6MzU6MjctMDU6MDDyjIcTAAAAAElFTkSuQmCC\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEVyEhLpgJFNv8T///98iBL0AAAAAWJLR0QDEQxM8gAAAAd0SU1FB+MEAw4yF98MNh4AAAKlSURBVGje7ZrBscIwDETxwSWkn5TAgXCgBPqhBA6kyj/fDhCIJa2zZAwz0pmHpZWdSazd7Tw8PDw8PDw8vinCMBzW03HIsRLvhnv0HL7qD+IwjzXKzaNaxeEt9kz21RWEBV5XQbfka3pQWL4qgdLyNQkUcbwFT/FP4zjWt+D+++OY4laZQJgtnqNOwe5l9XkGmIIL/PEHUAGTeuc5P15wBbu34ucSIAXkX77h4xUtIBSXnxIAOhCLy98TANNfLj8lYBYQCuLPWmAWEBe9f90DUPdKy08JWB0U1HsoaAgQxPSnAgwBopz+VABQvoDnAnqTP0r8zealzfPcQqqAQSs/C6AKGLX0pwKs8uX0cwGaAHr6uYC9wSt46qDCB4RXBDTkMwWMhnxZQF3+s8pf1AZY5VsCWuVnAUQ+YPxB43X5koAiH035soCa/AaeBOw34m359AaQPCK/1oAAyJ8aIPBI+7QGRkD+3IBt+A6QPzeg34SH2pcauN+Kt9uXGljkse0jb6BP8AD+vwGKPLZ95A0UofbnDbAFj20/eQN+gD8h/LgRD25/8QCA2088AD/Oo8dPOoDo8ZMOoPPNeej4pwdAgUcfX9IDzHnnf5lnz88XnH/nSf4M8cIL7I+/P3yCP0G88P7W+v2z9ft36+8P9vuJ/X5r/f3Jfj83//5vff/R+v6Hvb9i78/Y+7vW94/N71/Z+2P2/pq9P2fv7+n5ATu/YOcn7PyGnR+x8yt6ftYN3PzOENCcH7LzS3Z+Ss9vO62DV5uPmgAXSz5+fs7O72n/QBQLwPwLrH+C9W/Q/hHWv8L6Z2j/ThZgvX+I9S/R/inWv8X6x2j/Guufo/17rH+Q9S/S/knWv0n7R2n/Kuufpf27tH+Y9i/vWP+0h4eHh4eHh8cW8QcxLJDBvLKoigAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOS0wNC0wM1QxNDo1MDoyMy0wNTowMKoZjXIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTktMDQtMDNUMTQ6NTA6MjMtMDU6MDDbRDXOAAAAAElFTkSuQmCC\n", "text/plain": [ "" ] @@ -313,7 +304,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -323,7 +314,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -345,7 +336,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -362,7 +353,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": { "scrolled": true }, @@ -399,8 +390,8 @@ " Copyright | 2011-2019 MIT and OpenMC contributors\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.10.0\n", - " Git SHA1 | fe3d85d0d086321c09d777bfb09cdede7e27289b\n", - " Date/Time | 2019-04-02 13:35:28\n", + " Git SHA1 | cc09ba4a5bf2edd95624e386b72803d83ddc9f4f\n", + " Date/Time | 2019-04-03 14:50:23\n", " OpenMP Threads | 2\n", "\n", " Reading settings XML file...\n", @@ -496,59 +487,7 @@ " 72/1 1.05470 1.04178 +/- 0.00185\n", " 73/1 1.03892 1.04173 +/- 0.00182\n", " 74/1 0.98570 1.04086 +/- 0.00199\n", - " 75/1 1.02591 1.04063 +/- 0.00198\n", - " 76/1 1.02944 1.04046 +/- 0.00195\n", - " 77/1 1.04456 1.04052 +/- 0.00192\n", - " 78/1 1.04877 1.04064 +/- 0.00190\n", - " 79/1 1.02922 1.04047 +/- 0.00188\n", - " 80/1 1.03456 1.04039 +/- 0.00185\n", - " 81/1 1.02594 1.04019 +/- 0.00184\n", - " 82/1 1.05772 1.04043 +/- 0.00183\n", - " 83/1 1.03401 1.04034 +/- 0.00181\n", - " 84/1 1.02023 1.04007 +/- 0.00180\n", - " 85/1 1.05036 1.04021 +/- 0.00178\n", - " 86/1 1.04087 1.04022 +/- 0.00176\n", - " 87/1 1.02683 1.04004 +/- 0.00175\n", - " 88/1 1.01558 1.03973 +/- 0.00175\n", - " 89/1 1.05942 1.03998 +/- 0.00175\n", - " 90/1 1.04540 1.04005 +/- 0.00173\n", - " 91/1 1.00511 1.03961 +/- 0.00176\n", - " 92/1 1.04518 1.03968 +/- 0.00174\n", - " 93/1 1.04876 1.03979 +/- 0.00172\n", - " 94/1 1.04409 1.03984 +/- 0.00170\n", - " 95/1 1.08677 1.04039 +/- 0.00177\n", - " 96/1 1.05201 1.04053 +/- 0.00175\n", - " 97/1 1.00706 1.04014 +/- 0.00178\n", - " 98/1 1.01253 1.03983 +/- 0.00178\n", - " 99/1 1.04419 1.03988 +/- 0.00176\n", - " 100/1 1.05087 1.04000 +/- 0.00175\n", - " Creating state point statepoint.100.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 2.4783e-01 seconds\n", - " Reading cross sections = 2.3853e-01 seconds\n", - " Total time in simulation = 1.2926e+02 seconds\n", - " Time in transport only = 1.2922e+02 seconds\n", - " Time in inactive batches = 2.0238e+00 seconds\n", - " Time in active batches = 1.2724e+02 seconds\n", - " Time synchronizing fission bank = 1.9768e-02 seconds\n", - " Sampling source sites = 1.6800e-02 seconds\n", - " SEND/RECV source sites = 2.8950e-03 seconds\n", - " Time accumulating tallies = 3.2764e-03 seconds\n", - " Total time for finalization = 2.5501e-02 seconds\n", - " Total time elapsed = 1.2954e+02 seconds\n", - " Calculation Rate (inactive) = 24706.2 particles/second\n", - " Calculation Rate (active) = 3536.71 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.04002 +/- 0.00179\n", - " k-effective (Track-length) = 1.04000 +/- 0.00175\n", - " k-effective (Absorption) = 1.04116 +/- 0.00173\n", - " Combined k-effective = 1.04058 +/- 0.00138\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" + " 75/1 1.02591 1.04063 +/- 0.00198\n" ] } ], @@ -573,7 +512,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": { "scrolled": true }, @@ -592,24 +531,9 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tally\n", - "\tID =\t1\n", - "\tName =\tflux\n", - "\tFilters =\tMeshFilter\n", - "\tNuclides =\ttotal \n", - "\tScores =\t['flux', 'fission']\n", - "\tEstimator =\ttracklength\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "tally = sp.get_tally(scores=['flux'])\n", "print(tally)" @@ -624,32 +548,9 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[0.40791951, 0. ]],\n", - "\n", - " [[0.40985691, 0. ]],\n", - "\n", - " [[0.40996961, 0. ]],\n", - "\n", - " ...,\n", - "\n", - " [[0.41165858, 0. ]],\n", - "\n", - " [[0.40864517, 0. ]],\n", - "\n", - " [[0.4103825 , 0. ]]])" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "tally.sum" ] @@ -663,52 +564,9 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(10000, 1, 2)\n" - ] - }, - { - "data": { - "text/plain": [ - "(array([[[0.00453244, 0. ]],\n", - " \n", - " [[0.00455397, 0. ]],\n", - " \n", - " [[0.00455522, 0. ]],\n", - " \n", - " ...,\n", - " \n", - " [[0.00457398, 0. ]],\n", - " \n", - " [[0.0045405 , 0. ]],\n", - " \n", - " [[0.00455981, 0. ]]]),\n", - " array([[[1.95627478e-05, 0.00000000e+00]],\n", - " \n", - " [[1.83614292e-05, 0.00000000e+00]],\n", - " \n", - " [[1.64302659e-05, 0.00000000e+00]],\n", - " \n", - " ...,\n", - " \n", - " [[1.72592008e-05, 0.00000000e+00]],\n", - " \n", - " [[1.67649181e-05, 0.00000000e+00]],\n", - " \n", - " [[1.73154805e-05, 0.00000000e+00]]]))" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "print(tally.mean.shape)\n", "(tally.mean, tally.std_dev)" @@ -723,24 +581,9 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tally\n", - "\tID =\t2\n", - "\tName =\tflux\n", - "\tFilters =\tMeshFilter\n", - "\tNuclides =\ttotal \n", - "\tScores =\t['flux']\n", - "\tEstimator =\ttracklength\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "flux = tally.get_slice(scores=['flux'])\n", "fission = tally.get_slice(scores=['fission'])\n", @@ -756,7 +599,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -768,32 +611,9 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "fig = plt.subplot(121)\n", "fig.imshow(flux.mean)\n", @@ -810,22 +630,9 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Determine relative error\n", "relative_error = np.zeros_like(flux.std_dev)\n", @@ -852,27 +659,9 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([((0.04198465, 0.36778516, -0.54532495), (-0.87811811, -0.39548134, -0.26926397), 571922.4194387 , 1., 0, 0),\n", - " ((0.04198465, 0.36778516, -0.54532495), (-0.27391993, 0.65832903, -0.70112107), 1051291.75191703, 1., 0, 0),\n", - " ((0.23330238, 0.11245273, -0.49945337), ( 0.1509347 , -0.85503549, 0.49611796), 299854.82560331, 1., 0, 0),\n", - " ...,\n", - " ((0.0699198 , -0.02937169, 0.26199297), (-0.52319058, 0.76040935, 0.38477167), 3092157.86592333, 1., 0, 0),\n", - " ((0.14744428, 0.26653355, -0.60973896), ( 0.75846552, -0.63529803, -0.14534944), 2583881.32654478, 1., 0, 0),\n", - " ((0.14744428, 0.26653355, -0.60973896), ( 0.62586295, 0.30081458, 0.71958749), 2875076.1470368 , 1., 0, 0)],\n", - " dtype=[('r', [('x', '" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Create log-spaced energy bins from 1 keV to 10 MeV\n", "energy_bins = np.logspace(3,7)\n", @@ -972,32 +719,9 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(-0.5, 0.5)" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "plt.quiver(sp.source['r']['x'], sp.source['r']['y'],\n", " sp.source['u']['x'], sp.source['u']['y'],\n", From d0a0d34b89cc59329d60bf26b657768a7ccd64e3 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 3 Apr 2019 19:50:12 -0400 Subject: [PATCH 163/165] Address #1210 comments --- include/openmc/cell.h | 37 +---------------- src/cell.cpp | 96 ++++++++++++++++++++++++++++++++----------- src/geometry_aux.cpp | 5 +-- 3 files changed, 76 insertions(+), 62 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 2cd0bd3fa..cc4429b44 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -210,44 +210,9 @@ public: explicit UniversePartitioner(const Universe& univ); //! Return the list of cells that could contain the given coordinates. - const std::vector& get_cells(Position r, Direction u) const - {return get_cells(r, u, 0, surfs_.size()-1, (surfs_.size()-1)/2);} + const std::vector& get_cells(Position r, Direction u) const; private: - //! Perform a binary search for the given coordinates. - // - //! \param left The lower search bound of the `surfs_` vector - //! \param right The upper search bound of the `surfs_` vector - //! \param middle The index of the `Surface` to test against - const std::vector& - get_cells(Position r, Direction u, int left, int right, int middle) const - { - // Check the sense of the coordinates for the current surface. - auto i_surf = surfs_[middle]; - const auto& surf = *model::surfaces[i_surf]; - if (surf.sense(r, u)) { - // The coordinates lie in the positive halfspace. Recurse if there are - // more surfaces to check. Otherwise, return the cells on the positive - // side of this surface. - int right_leaf = right - (right - middle) / 2; - if (right_leaf != middle) { - return get_cells(r, u, middle+1, right, right_leaf); - } else { - return partitions_[middle+1]; - } - } else { - // The coordinates lie in the negative halfspace. Recurse if there are - // more surfaces to check. Otherwise, return the cells on the negative - // side of this surface. - int left_leaf = left + (middle - left) / 2; - if (left_leaf != middle) { - return get_cells(r, u, left, middle-1, left_leaf); - } else { - return partitions_[middle]; - } - } - } - //! A sorted vector of indices to surfaces that partition the universe std::vector surfs_; diff --git a/src/cell.cpp b/src/cell.cpp index 5e803c4cd..8e2dfc5a7 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -659,10 +659,10 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) } } - // Define a functor for comparing z-planes by their location, and use it to + // Define a lambda for comparing z-planes by their location, and use it to // sort the surfs_ member. - struct { - bool operator()(int32_t i_surf, int32_t j_surf) const + std::sort(surfs_.begin(), surfs_.end(), + [](int32_t i_surf, int32_t j_surf) -> bool { const auto* surf = model::surfaces[i_surf].get(); const auto* zplane = dynamic_cast(surf); @@ -672,25 +672,24 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) double zj = zplane->z0_; return zi < zj; } - } compare_surfs; - std::sort(surfs_.begin(), surfs_.end(), compare_surfs); + ); // Populate the partition lists. partitions_.resize(surfs_.size() + 1); for (auto i_cell : univ.cells_) { // Find the tokens for bounding z-planes. - int32_t min_token = 0, max_token = 0; + int32_t lower_token = 0, upper_token = 0; double min_z, max_z; for (auto token : model::cells[i_cell]->rpn_) { if (token < OP_UNION) { const auto* surf = model::surfaces[std::abs(token) - 1].get(); if (const auto* zplane = dynamic_cast(surf)) { - if (min_token == 0 || zplane->z0_ < min_z) { - min_token = token; + if (lower_token == 0 || zplane->z0_ < min_z) { + lower_token = token; min_z = zplane->z0_; } - if (max_token == 0 || zplane->z0_ > max_z) { - max_token = token; + if (upper_token == 0 || zplane->z0_ > max_z) { + upper_token = token; max_z = zplane->z0_; } } @@ -698,27 +697,78 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) } // If there are no bounding z-planes, add this cell to all partitions. - if (min_token == 0) { + if (lower_token == 0) { for (auto& p : partitions_) p.push_back(i_cell); continue; } - // Iterate over partitions, and add this cell to each appropriate one. - // Since surfs_ is sorted, we know this cell belongs to every partition - // between min_token and max_token. - bool in_partition = min_token < 0; - for (auto i = 0; i < surfs_.size(); ++i) { - if (in_partition) { - partitions_[i].push_back(i_cell); - if (max_token == -(surfs_[i] + 1)) { - in_partition = false; + // Find the first partition this cell lies in. If the lower_token indicates + // a negative halfspace, then the cell is unbounded in the lower direction + // and it lies in the first partition onward. Otherwise, it is bounded by + // the positive halfspace given by the lower_token. + int first_partition = 0; + if (lower_token > 0) { + for (int i = 0; i < surfs_.size(); ++i) { + if (lower_token == surfs_[i] + 1) { + first_partition = i + 1; break; } - } else { - in_partition = min_token == surfs_[i] + 1; } } - if (in_partition) partitions_.back().push_back(i_cell); + + // Find the last partition this cell lies in. The logic is analogous to the + // logic for first_partition. + int last_partition = surfs_.size(); + if (upper_token < 0) { + for (int i = first_partition; i < surfs_.size(); ++i) { + if (upper_token == -(surfs_[i] + 1)) { + last_partition = i; + break; + } + } + } + + // Add the cell to all relevant partitions. + for (int i = first_partition; i < last_partition + 1; ++i) { + partitions_[i].push_back(i_cell); + } + } +} + +const std::vector& +UniversePartitioner::get_cells(Position r, Direction u) const +{ + // Perform a binary search for the partition containing the given coordinates. + int left = 0; + int middle = (surfs_.size() - 1) / 2; + int right = surfs_.size() - 1; + while (true) { + // Check the sense of the coordinates for the current surface. + const auto& surf = *model::surfaces[surfs_[middle]]; + if (surf.sense(r, u)) { + // The coordinates lie in the positive halfspace. Recurse if there are + // more surfaces to check. Otherwise, return the cells on the positive + // side of this surface. + int right_leaf = right - (right - middle) / 2; + if (right_leaf != middle) { + left = middle + 1; + middle = right_leaf; + } else { + return partitions_[middle+1]; + } + + } else { + // The coordinates lie in the negative halfspace. Recurse if there are + // more surfaces to check. Otherwise, return the cells on the negative + // side of this surface. + int left_leaf = left + (middle - left) / 2; + if (left_leaf != middle) { + right = middle-1; + middle = left_leaf; + } else { + return partitions_[middle]; + } + } } } diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 38d3a8a0e..f02ee42b1 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -139,14 +139,13 @@ partition_universes() } // Partition the universe if there are more than 5 z-planes. (Fewer than - // five is likely no worth it.) + // 5 is likely not worth it.) int n_zplanes = 0; for (auto i_surf : surf_inds) { if (dynamic_cast(model::surfaces[i_surf].get())) { ++n_zplanes; if (n_zplanes > 5) { - univ->partitioner_ = std::make_unique( - UniversePartitioner(*univ)); + univ->partitioner_ = std::make_unique(*univ); break; } } From c814b6f81edf33a19181cf9d0285ba344ddd527c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 3 Apr 2019 21:42:40 -0500 Subject: [PATCH 164/165] Moving iz back. Expliciting initializing iz. --- src/lattice.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index dc1b1d8fe..b16fecc6e 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -715,6 +715,18 @@ HexLattice::get_indices(Position r, Direction u) const Position r_o {r.x - center_.x, r.y - center_.y, r.z}; if (is_3d_) {r_o.z -= center_.z;} + // Index the z direction, accounting for coincidence + int iz = 0; + if (is_3d_) { + double iz_ {r_o.z / pitch_[1] + 0.5 * n_axial_}; + long iz_close {std::lround(iz_)}; + if (coincident(iz_, iz_close)) { + iz = (u.z > 0) ? iz_close : iz_close - 1; + } else { + iz = std::floor(iz_); + } + } + // Convert coordinates into skewed bases. The (x, alpha) basis is used to // find the index of the global coordinates to within 4 cells. double alpha = r_o.y - r_o.x / std::sqrt(3.0); @@ -726,18 +738,6 @@ HexLattice::get_indices(Position r, Direction u) const ix += n_rings_-1; ia += n_rings_-1; - // Index the z direction, accounting for coincidence - int iz{}; - if (is_3d_) { - double iz_ {r_o.z / pitch_[1] + 0.5 * n_axial_}; - long iz_close {std::lround(iz_)}; - if (coincident(iz_, iz_close)) { - iz = (u.z > 0) ? iz_close : iz_close - 1; - } else { - iz = std::floor(iz_); - } - } - // Calculate the (squared) distance between the particle and the centers of // the four possible cells. Regular hexagonal tiles form a Voronoi // tessellation so the xyz should be in the hexagonal cell that it is closest From a4c15928cfa19b3ee556b4f6446571b3024ad511 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 4 Apr 2019 11:04:52 -0400 Subject: [PATCH 165/165] Use ordered set in UniversePartitioner constructor --- src/cell.cpp | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 8e2dfc5a7..7c22164b3 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "openmc/capi.h" @@ -641,28 +642,10 @@ void DAGCell::to_hdf5(hid_t group_id) const { return; } UniversePartitioner::UniversePartitioner(const Universe& univ) { - // Find all of the z-planes in this universe. Add them to the surfs_ member. - // Use surf_set for O(1) searches that ensure surfs_ entries are not repeated. - std::unordered_set surf_set; - for (auto i_cell : univ.cells_) { - for (auto token : model::cells[i_cell]->rpn_) { - if (token < OP_UNION) { - auto i_surf = std::abs(token) - 1; - const auto* surf = model::surfaces[i_surf].get(); - if (const auto* zplane = dynamic_cast(surf)) { - if (surf_set.find(i_surf) == surf_set.end()) { - surf_set.insert(i_surf); - surfs_.push_back(i_surf); - } - } - } - } - } - - // Define a lambda for comparing z-planes by their location, and use it to - // sort the surfs_ member. - std::sort(surfs_.begin(), surfs_.end(), - [](int32_t i_surf, int32_t j_surf) -> bool + // Define an ordered set of surface indices that point to z-planes. Use a + // functor to to order the set by the z0_ values of the corresponding planes. + struct compare_surfs { + bool operator()(const int32_t& i_surf, const int32_t& j_surf) const { const auto* surf = model::surfaces[i_surf].get(); const auto* zplane = dynamic_cast(surf); @@ -672,7 +655,24 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) double zj = zplane->z0_; return zi < zj; } - ); + }; + std::set surf_set; + + // Find all of the z-planes in this universe. A set is used here for the + // O(log(n)) insertions that will ensure entries are not repeated. + for (auto i_cell : univ.cells_) { + for (auto token : model::cells[i_cell]->rpn_) { + if (token < OP_UNION) { + auto i_surf = std::abs(token) - 1; + const auto* surf = model::surfaces[i_surf].get(); + if (const auto* zplane = dynamic_cast(surf)) + surf_set.insert(i_surf); + } + } + } + + // Populate the surfs_ vector from the ordered set. + surfs_.insert(surfs_.begin(), surf_set.begin(), surf_set.end()); // Populate the partition lists. partitions_.resize(surfs_.size() + 1); @@ -729,7 +729,7 @@ UniversePartitioner::UniversePartitioner(const Universe& univ) } // Add the cell to all relevant partitions. - for (int i = first_partition; i < last_partition + 1; ++i) { + for (int i = first_partition; i <= last_partition; ++i) { partitions_[i].push_back(i_cell); } }