<commit_before>// Material.cpp
#include "Material.h"

#include "CycException.h"
#include "Timer.h"
#include "Logger.h"

#include <cmath>
#include <vector>
#include <list>

using namespace std;
using namespace boost;

list<Material*> Material::materials_;

bool Material::decay_wanted_ = false;

int Material::decay_interval_ = 1;

bool Material::type_is_recorded_ = false;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::Material() {
  last_update_time_ = TI->time();
  CLOG(LEV_INFO4) << "Material ID=" << ID_ << " was created.";
  materials_.push_back(this);
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::~Material() {
  materials_.remove(this);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::Material(CompMapPtr comp) {
  IsoVector vec = IsoVector(comp);
  last_update_time_ = TI->time();
  iso_vector_ = vec;
  CLOG(LEV_INFO4) << "Material ID=" << ID_ << " was created.";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::Material(IsoVector vec) {
  last_update_time_ = TI->time();
  iso_vector_ = vec;
  CLOG(LEV_INFO4) << "Material ID=" << ID_ << " was created.";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::Material(const Material& other) {
  iso_vector_ = other.iso_vector_;
  last_update_time_ = other.last_update_time_;
  quantity_ = other.quantity_;
  CLOG(LEV_INFO4) << "Material ID=" << ID_ << " was created.";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::absorb(mat_rsrc_ptr matToAdd) { 
  // @gidden figure out how to handle this with the database - mjg
  // Get the given Material's composition.
  double amt = matToAdd->quantity();
  iso_vector_.mix(matToAdd->isoVector(),quantity_/amt); // @MJG_FLAG this looks like it copies isoVector()... should this return a pointer?
  quantity_ += amt;
  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " absorbed material ID="
                   << matToAdd->ID() << ".";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mat_rsrc_ptr Material::extract(double mass) {
  if(quantity_ < mass){
    string err = "The mass ";
    err += mass;
    err += " cannot be extracted from Material with ID ";
    err += ID_; 
    throw CycNegativeValueException(err);
  }
  // remove our mass
  quantity_ -= mass;
  // make a new material, set its mass
  mat_rsrc_ptr new_mat = mat_rsrc_ptr(new Material(iso_vector_));
  new_mat->setQuantity(mass);
  // we just split a resource, so keep track of the original for book keeping
  new_mat->setOriginalID( this->originalID() );

  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had " << mass
                   << " kg extracted from it. New mass=" << quantity() << " kg.";
  
  return new_mat;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mat_rsrc_ptr Material::extract(const CompMapPtr comp_to_rem, double kg_to_rem) {
 
  CompMapPtr new_comp = CompMapPtr(this->unnormalizeComp(MASS));
  assert(!new_comp->normalized());
  CompMapPtr remove_comp = comp_to_rem;
  remove_comp->massify();
  assert(remove_comp->normalized());
  double remainder_kg, new_kg, kg_to_rem_i;
  remainder_kg = this->quantity();
  int iso;

  for (CompMap::iterator it = remove_comp->begin(); 
       it != remove_comp->end(); it++) {
    // reduce isotope, if it exists in new_comp
    kg_to_rem_i = it->second * kg_to_rem;
    iso = it->first;
    if ( this->mass(iso) >= kg_to_rem_i ) {
      (*new_comp)[iso] = this->mass(iso) - kg_to_rem_i;
      new_kg += kg_to_rem_i;
      remainder_kg -= kg_to_rem_i;
    } else {
    stringstream ss("");
    ss << "The Material " << this->ID() 
      << " has insufficient material to extract the isotope : "
      << iso ;
    throw CycNegativeValueException(ss.str());
    }
  }

  // make new material
  mat_rsrc_ptr new_mat = mat_rsrc_ptr(new Material(comp_to_rem));
  new_mat->setQuantity(new_kg, KG);
  new_mat->setOriginalID( this->originalID() ); // book keeping
  
  // adjust old material
  this->iso_vector_ = IsoVector(new_comp); 
  this->setQuantity(remainder_kg, KG);

  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had composition extracted.";

  return new_mat;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
void Material::print() {
  CLOG(LEV_INFO4) << "Material ID=" << ID_
                   << ", quantity=" << quantity() << ", units=" << units();

  CLOG(LEV_INFO5) << "Composition {";<commit_msg>utilizes the cyclus::eps_rsrc() value to avoid exceptions being thrown because of floating point errors in material amounts.<commit_after>// Material.cpp
#include "Material.h"

#include "CycException.h"
#include "CycLimits.h"
#include "Timer.h"
#include "Logger.h"

#include <cmath>
#include <vector>
#include <list>

using namespace std;
using namespace boost;

list<Material*> Material::materials_;

bool Material::decay_wanted_ = false;

int Material::decay_interval_ = 1;

bool Material::type_is_recorded_ = false;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::Material() {
  last_update_time_ = TI->time();
  CLOG(LEV_INFO4) << "Material ID=" << ID_ << " was created.";
  materials_.push_back(this);
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::~Material() {
  materials_.remove(this);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::Material(CompMapPtr comp) {
  IsoVector vec = IsoVector(comp);
  last_update_time_ = TI->time();
  iso_vector_ = vec;
  CLOG(LEV_INFO4) << "Material ID=" << ID_ << " was created.";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::Material(IsoVector vec) {
  last_update_time_ = TI->time();
  iso_vector_ = vec;
  CLOG(LEV_INFO4) << "Material ID=" << ID_ << " was created.";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
Material::Material(const Material& other) {
  iso_vector_ = other.iso_vector_;
  last_update_time_ = other.last_update_time_;
  quantity_ = other.quantity_;
  CLOG(LEV_INFO4) << "Material ID=" << ID_ << " was created.";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::absorb(mat_rsrc_ptr matToAdd) { 
  // @gidden figure out how to handle this with the database - mjg
  // Get the given Material's composition.
  double amt = matToAdd->quantity();
  iso_vector_.mix(matToAdd->isoVector(),quantity_/amt); // @MJG_FLAG this looks like it copies isoVector()... should this return a pointer?
  quantity_ += amt;
  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " absorbed material ID="
                   << matToAdd->ID() << ".";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mat_rsrc_ptr Material::extract(double mass) {
  if(quantity_ < mass){
    string err = "The mass ";
    err += mass;
    err += " cannot be extracted from Material with ID ";
    err += ID_; 
    throw CycNegativeValueException(err);
  }
  // remove our mass
  quantity_ -= mass;
  // make a new material, set its mass
  mat_rsrc_ptr new_mat = mat_rsrc_ptr(new Material(iso_vector_));
  new_mat->setQuantity(mass);
  // we just split a resource, so keep track of the original for book keeping
  new_mat->setOriginalID( this->originalID() );

  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had " << mass
                   << " kg extracted from it. New mass=" << quantity() << " kg.";
  
  return new_mat;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mat_rsrc_ptr Material::extract(const CompMapPtr comp_to_rem, double kg_to_rem) {
 
  CompMapPtr new_comp = CompMapPtr(this->unnormalizeComp(MASS));
  assert(!new_comp->normalized());
  CompMapPtr remove_comp = comp_to_rem;
  remove_comp->massify();
  assert(remove_comp->normalized());
  double remainder_kg, new_kg, kg_to_rem_i;
  remainder_kg = this->quantity();
  double remainder_kg_i;
  int iso;

  for (CompMap::iterator it = remove_comp->begin(); 
       it != remove_comp->end(); it++) {
    // reduce isotope, if it exists in new_comp
    kg_to_rem_i = it->second * kg_to_rem;
    if ( kg_to_rem_i <= cyclus::eps_rsrc() ) { kg_to_rem_i = 0; };
    iso = it->first;
    remainder_kg_i = this->mass(iso) - kg_to_rem_i;
    if ( remainder_kg_i >= -cyclus::eps_rsrc() ) {
      if ( remainder_kg_i <= cyclus::eps_rsrc() ) { remainder_kg_i = 0; };
      (*new_comp)[iso] = remainder_kg_i;
      new_kg += kg_to_rem_i;
      remainder_kg -= kg_to_rem_i;
    } else {
      stringstream ss("");
      ss << "The Material " << this->ID() 
         << " has insufficient material to extract the isotope : "
         << iso ;
      throw CycNegativeValueException(ss.str());
    }
  }

  // make new material
  mat_rsrc_ptr new_mat = mat_rsrc_ptr(new Material(comp_to_rem));
  new_mat->setQuantity(new_kg, KG);
  new_mat->setOriginalID( this->originalID() ); // book keeping
  
  // adjust old material
  this->iso_vector_ = IsoVector(new_comp); 
  this->setQuantity(remainder_kg, KG);

  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had composition extracted.";

  return new_mat;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    
void Material::print() {
  CLOG(LEV_INFO4) << "Material ID=" << ID_
                   << ", quantity=" << quantity() << ", units=" << units();

  CLOG(LEV_INFO5) << "Composition {";
{'fraction_non_alphanumeric': 0.202197118872422, 'fraction_numerical': 0.0022800290185511453, 'mean_word_length': 2.0193992490613266, 'pattern_counts': {'":': 0, '<': 167, '<?xml version=': 0, '>': 64, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 108, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6178369', 'n_tokens_mistral': 3618, 'n_tokens_neox': 3519, 'n_words': 662}