Logo Search packages:      
Sourcecode: kalzium version File versions  Download package

nuclearCalculator.cpp

/***************************************************************************
 *   Copyright (C) 2009       by Kashyap R Puranik, kashthealien@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "nuclearCalculator.h"
#include <math.h>
#include "prefs.h"
using namespace KUnitConversion;

00025 nuclearCalculator::nuclearCalculator(QWidget * parent)
        : QFrame(parent)
{
    ui.setupUi(this);

    /**************************************************************************/
    //                       Nuclear Calculator set up                        //
    /**************************************************************************/
    KalziumDataObject *kdo = KalziumDataObject::instance();

    // add all element names to the comboBox in the user interface
    foreach(Element * e, kdo -> ElementList) {
        ui.element -> addItem(e -> dataAsString(ChemicalDataObject::name));
    }
///FIXME
    /* The last three elemenents will be removed because information is not available
       and causes the program to crash when selected. */
    int count = ui.element -> count();
    ui.element -> removeItem(count - 1);
    ui.element -> removeItem(count - 2);
    ui.element -> removeItem(count - 3);

    // initialise data
    init();
    // Connect signals with slots
    connect(ui.element, SIGNAL(activated(int)),
            this, SLOT(elementChanged(int)));
    connect(ui.isotope, SIGNAL(activated(int)),
            this, SLOT(isotopeChanged(int)));
    connect(ui.halfLife, SIGNAL(valueChanged(double)),
            this, SLOT(halfLifeChanged()));
    connect(ui.halfLife_unit , SIGNAL(activated(int)),
            this, SLOT(halfLifeChanged()));
    connect(ui.initAmt, SIGNAL(valueChanged(double)),
            this, SLOT(initAmtChanged()));
    connect(ui.initAmt_unit, SIGNAL(activated(int)),
            this, SLOT(initAmtChanged()));
    connect(ui.initAmtType, SIGNAL(activated(int)),
            this, SLOT(initAmtChanged()));
    connect(ui.finalAmt, SIGNAL(valueChanged(double)),
            this, SLOT(finalAmtChanged()));
    connect(ui.finalAmt_unit, SIGNAL(activated(int)),
            this, SLOT(finalAmtChanged()));
    connect(ui.finalAmtType, SIGNAL(activated(int)),
            this, SLOT(finalAmtChanged()));
    connect(ui.time, SIGNAL(valueChanged(double)),
            this, SLOT(timeChanged()));
    connect(ui.time_unit, SIGNAL(activated(int)),
            this, SLOT(timeChanged()));
    connect(ui.slider, SIGNAL(valueChanged(int)),
            this, SLOT(sliderMoved(int)));
    connect(ui.mode, SIGNAL(activated(int)),
            this, SLOT(setMode(int)));
      connect(ui.reset, SIGNAL(clicked()),
                  this, SLOT(init()));
      
    /**************************************************************************/
    // Nuclear Calculator setup complete
    /**************************************************************************/
    
    if(Prefs::mass()) {
      ui.initAmtType->hide();
      ui.finalAmtType->hide();      
    }
}

nuclearCalculator:: ~nuclearCalculator()
{

}

// The function that initialises data
void nuclearCalculator::init()
{
      const int ISOTOPE_NUM = 22;
    // Add all isotope names of Uranium ( by default )to the isotope comboBox
    QList<Isotope*> list = KalziumDataObject::instance() -> isotopes(92);
    QString isotope;
    
    ui.isotope->clear();
    foreach(Isotope * i , list) {
        isotope.setNum(i -> mass());
        ui.isotope  -> addItem(isotope);
    }
    
      // initialise the data, initially selected values ( Uranium, 92, 238)
    ui.element    -> setCurrentIndex(91);
    ui.isotope    -> setCurrentIndex(ISOTOPE_NUM);
    ui.halfLife   -> setValue(list.at(ISOTOPE_NUM) -> halflife());
    ui.initAmt    -> setValue(6.0);
    ui.finalAmt   -> setValue(3.0);
    ui.time         -> setValue(list.at(ISOTOPE_NUM) -> halflife());
    
    ui.halfLife_unit    ->setCurrentIndex(0);
    ui.initAmtType            ->setCurrentIndex(0);
    ui.finalAmtType           ->setCurrentIndex(0);
    ui.initAmt_unit           ->setCurrentIndex(0);
    ui.finalAmt_unit    ->setCurrentIndex(0);
    ui.time_unit        ->setCurrentIndex(0);
    
    QString tempStr;
    tempStr.setNum(list.at(ISOTOPE_NUM) -> mass());
    ui.mass -> setText(tempStr);

    // Setup of the UI done
    // Initialise values
    m_initAmount  = Value(6.0, "g") ;
    m_finalAmount = Value(3.0, "g");
    m_mass = list.at(ISOTOPE_NUM) -> mass();
    m_time = Value((list.at(ISOTOPE_NUM) -> halflife()), "years");
    m_halfLife = Value(list.at(ISOTOPE_NUM) -> halflife(), "years");

    m_element = * KalziumDataObject::instance() -> element(92);
    m_isotope = * list.at(ISOTOPE_NUM);

      setMode(2);
    // Initialisation of values done
}
// This function is executed when the element is changed
void nuclearCalculator::elementChanged(int index)
{
    // set the newly chosen element
    m_element = * KalziumDataObject::instance() -> element(index + 1);

    // Add all isotope names of Uranium ( by default ) to the isotope comboBox
    QList<Isotope*> list = KalziumDataObject::instance() -> isotopes(index + 1);
    QString isotope;                        // A temporary string
    ui.isotope  -> clear();               // Clear the contents of the combo box

    // update the combobox with isotopes of the new element
    foreach(Isotope * i , list) {
        isotope.setNum(i -> mass());
        ui.isotope  -> addItem(isotope);
    }

    // Set the halfLife to that of the first isotope of the element.
    ui.halfLife  -> setValue(list. at(0) -> halflife());
    // Recalculate and update
    calculate();
}

// This function is executed when the isotope is changed
void  nuclearCalculator::isotopeChanged(int index)
{
    // update the nuclear Calculator
    int elementNumber = ui.element  -> currentIndex() + 1;
    QList<Isotope*> list = KalziumDataObject::instance() -> isotopes(elementNumber);
    m_isotope = * list.at(index);

    // get the halfLife of the new isotope
    double halfLife = list.at(index) -> halflife();
    m_mass = list.at(index) -> mass();

    // A string used for searching the right unit
    QString halfLifeUnit = list.at(index) -> halflifeUnit();
    halfLifeUnit = (halfLifeUnit == "y") ? "years" : "seconds";

    QString tempStr;                // A temporary string
    tempStr.setNum(m_mass);
    ui.mass -> setText(tempStr);
    // Update the UI with the halfLife value
    ui.halfLife -> setValue(halfLife);
    int x = ui.halfLife_unit -> findText(halfLifeUnit);
    if (x >= 0)
        ui.halfLife_unit -> setCurrentIndex(x);
    m_halfLife = Value(halfLife , halfLifeUnit);
    // Recalculate and update
    calculate();
}

// This function is executed when the halfLife is changed
void  nuclearCalculator::halfLifeChanged()
{
    // update the halfLife value
    m_halfLife = Value(ui.halfLife -> value(), ui.halfLife_unit -> currentText());
    // recalculate the required
    calculate();
}

void  nuclearCalculator::initAmtChanged()
{

    // If quantity is specified in terms of mass, quantity <- ( mass , unit)
    if (ui.initAmtType -> currentIndex() == 0) {
      ui.initAmt_unit->show();
        m_initAmount = Value(ui.initAmt -> value(), ui.initAmt_unit -> currentText());
      }        

    // If quantity is specified in terms of moles quantity <- ( moles * atomicMass, unit )
    else {
      ui.initAmt_unit->hide();
        m_initAmount = Value(((ui.initAmt -> value()) * m_mass), \
                             ui.initAmt_unit -> currentText());
      }

    calculate();
}

void  nuclearCalculator::finalAmtChanged()
{
    // If quantity is specified in terms of mass, quantity <- ( mass , unit)
    if (ui.finalAmtType -> currentIndex() == 0) {
      ui.finalAmt_unit ->show();
        m_finalAmount = Value(ui.finalAmt -> value(), \
                              ui.finalAmt_unit -> currentText());
      }
    // If quantity is specified in terms of moles quantity <- ( moles * atomicMass, unit )
    else {
      ui.finalAmt_unit->hide();
        m_finalAmount = Value(((ui.finalAmt -> value()) * m_mass), \
                              ui.finalAmt_unit -> currentText());
      }

    calculate();
}

void  nuclearCalculator::sliderMoved(int numHlives)
{
    double num = numHlives / 10.0;
    m_time = Value(num * m_halfLife.number() , m_halfLife.unit());

    ui.time -> setValue(m_time.number());
    ui.time_unit -> setCurrentIndex(ui.halfLife_unit -> currentIndex());
    ui.numHalfLives -> setText(m_time.toString());
}

void  nuclearCalculator::timeChanged()
{
    m_time = Value(ui.time -> value(), ui.time_unit -> currentText());
      
    calculate();

}

void nuclearCalculator::setMode(int mode)
{
      m_mode = mode;
      
      ui.initAmt->setReadOnly(false);
      ui.finalAmt->setReadOnly(false);
      ui.time->setReadOnly(false);
      
      // set the quantity that should be calculated to readOnly
      switch (mode)
      {
            case INIT_AMT:
                  ui.initAmt->setReadOnly(true);
                  ui.time_in_halfLives->show();             
                  break;
            case FINAL_AMT:
                  ui.finalAmt->setReadOnly(true);
                  ui.time_in_halfLives->show();             
                  break;
            case TIME:
                  ui.time->setReadOnly(true);
                  ui.time_in_halfLives->hide();
                  break;
      }
      
      calculate();
}
void  nuclearCalculator::calculate()
{
      error(RESET_NUKE_MESSAGE);
    // Validate the values involved in calculation
    if (m_halfLife.number() == 0.0)
    {
      error (HALFLIFE_ZERO);
        return;
    }

      switch (m_mode)
      {
          case 0:       // calculate initial amount before given time
            if (ui.finalAmt  -> value() == 0.0 )
            {         
                error ( FINAL_AMT_ZERO);
              return;
          }
          calculateInitAmount();
            break;
      case 1:         // Calulate final Amount after given time
              if (ui.initAmt->value() == 0.0)
                  {
                        error ( INIT_AMT_ZERO );
                  return;
            }
              calculateFinalAmount();
            break;
      case 2:     // final amount greater than initial
          if (m_finalAmount.number() > m_initAmount.convertTo\
                (m_finalAmount.unit()).number())
          {
                error ( FINAL_AMT_GREATER );
                return;
            }
            // one of the amounts is 0.0
            if (ui.finalAmt -> value() == 0.0 )
            {
                  error ( FINAL_AMT_ZERO );
                return;
            }
            else if (ui.initAmt->value() == 0.0)
            {
                  error (INIT_AMT_ZERO);
                  return;
            }
              calculateTime();
              break;
    }
}

void nuclearCalculator::calculateInitAmount()
{
      error(RESET_NUKE_MESSAGE);
      
    // If no time has elapsed, initial and final amounts are the same
    if (m_time.number() == 0.0) {
            m_initAmount = m_finalAmount.convertTo(m_initAmount.unit());
            ui.initAmt->setValue (m_initAmount.number());
        return;
    }
    // Calculate the number of halfLives that have elapsed
    double ratio = m_time.convertTo(m_halfLife.unit()).number() / m_halfLife.number();
    // find out the initial amount
    m_initAmount = Value(m_initAmount.number() * pow(2.0 , ratio), m_initAmount.unit());
    // Convert into the required units
    m_initAmount = m_initAmount.convertTo( ui.initAmt_unit->currentText());
    ui.initAmt -> setValue(m_initAmount.number());
}

void nuclearCalculator::calculateFinalAmount()
{
    // If no time has elapsed, initial and final amounts are the same
    if (m_time.number() == 0.0) {
          m_finalAmount = m_initAmount.convertTo( m_finalAmount.unit());
            ui.finalAmt->setValue (m_finalAmount.number());
        return;
    }
    // Calculate the number of halfLives that have elapsed
    double ratio = m_time.convertTo(m_halfLife.unit()).number() \
                    / m_halfLife.number();
    // Calculate the final amount
    m_finalAmount = Value(m_finalAmount.number() / pow(2.0, ratio), m_initAmount.unit());
    // Convert into the required units
    m_finalAmount = m_finalAmount.convertTo( ui.finalAmt_unit->currentText());
    ui.finalAmt -> setValue(m_finalAmount.number());
}

void nuclearCalculator::calculateTime()
{
    // If initial and final masses are the same ( both units and value )
    // the time is also 0
    if (m_initAmount.number() == m_finalAmount.number() && \
            m_initAmount.unit() == m_finalAmount.unit()) {
        m_time = Value(0.0, m_time.unit());
        ui.time -> setValue(0.0);
        return;
    }

    // calculate the ratio of final to initial masses
    double ratio = m_initAmount.convertTo(m_finalAmount.unit()).number()
                                     / m_finalAmount.number();
                    
    // The number of halfLives ( log 2 ( x ) = log x / log 2 )
    double numHalfLives = log(ratio) / log(2.0);
    double time_value = numHalfLives  * m_halfLife.number();
    // Calculate the total time taken
      Value time = Value(time_value, m_halfLife.unit());
    m_time = time.convertTo( ui.time_unit->currentText());
    ui.time -> setValue(m_time.number());
    
    return;
}

void nuclearCalculator::error (int mode)
{
      switch (mode) { // Depending on the mode, set the error messages.
            case RESET_NUKE_MESSAGE:
                  ui.error->setText("");
                  break;
            case INIT_AMT_ZERO:
                  ui.error->setText(i18n("Initial amount cannot be zero."));
                  break;
            case FINAL_AMT_ZERO:
                  ui.error->setText(i18n("Final amount cannot be zero."));
                  break;
            case HALFLIFE_ZERO:
                  ui.error->setText(i18n("Time is zero, please enter a valid value."));
                  break;
            case FINAL_AMT_GREATER:
                  ui.error->setText(i18n("The final amount is greater than the initial amount."));
                  break;
      }
}

#include "nuclearCalculator.moc"



Generated by  Doxygen 1.6.0   Back to index