File indexing completed on 2022-11-29 12:50:41

0001 /*
0002     SPDX-FileCopyrightText: 2009 Kashyap R Puranik <kashthealien@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "gasCalculator.h"
0008 
0009 #include <KLocalizedString>
0010 
0011 #include "kalziumunitcombobox.h"
0012 #include "kalziumutils.h"
0013 #include "prefs.h"
0014 
0015 using namespace KUnitConversion;
0016 
0017 gasCalculator::gasCalculator(QWidget *parent)
0018     : QWidget(parent)
0019 {
0020     ui.setupUi(this);
0021 
0022     setupUnitComboboxes();
0023 
0024     init();
0025 
0026     connect(ui.temp, SIGNAL(valueChanged(double)), this, SLOT(tempChanged()));
0027     connect(ui.temp_unit, SIGNAL(activated(int)), this, SLOT(tempChanged()));
0028     connect(ui.volume, SIGNAL(valueChanged(double)), this, SLOT(volChanged()));
0029     connect(ui.volume_unit, SIGNAL(activated(int)), this, SLOT(volChanged()));
0030     connect(ui.pressure, SIGNAL(valueChanged(double)), this, SLOT(pressureChanged()));
0031     connect(ui.pressure_unit, SIGNAL(activated(int)), this, SLOT(pressureChanged()));
0032     connect(ui.mass, SIGNAL(valueChanged(double)), this, SLOT(massChanged()));
0033     connect(ui.mass_unit, SIGNAL(activated(int)), this, SLOT(massChanged()));
0034     connect(ui.moles, SIGNAL(valueChanged(double)), this, SLOT(molesChanged(double)));
0035     connect(ui.molarMass, SIGNAL(valueChanged(double)), this, SLOT(molarMassChanged(double)));
0036     connect(ui.a, SIGNAL(valueChanged(double)), this, SLOT(Vand_aChanged()));
0037     connect(ui.b, SIGNAL(valueChanged(double)), this, SLOT(Vand_bChanged()));
0038     connect(ui.b_unit, SIGNAL(activated(int)), this, SLOT(Vand_bChanged()));
0039     connect(ui.mode, SIGNAL(activated(int)), this, SLOT(setMode(int)));
0040     connect(ui.reset, &QAbstractButton::clicked, this, &gasCalculator::init);
0041 }
0042 
0043 gasCalculator::~gasCalculator() = default;
0044 
0045 void gasCalculator::init()
0046 {
0047     error(RESET_GAS_MESSAGE);
0048 
0049     ui.molarMass->setValue(2.008);
0050     ui.temp->setValue(273.0);
0051     ui.volume->setValue(22.400);
0052     ui.pressure->setValue(1.0);
0053     ui.a->setValue(0.0);
0054     ui.b->setValue(0.0);
0055     ui.mass->setValue(2.016);
0056     ui.moles->setValue(1.0);
0057 
0058     ui.mass_unit->setCurrentIndex(0);
0059     ui.pressure_unit->setCurrentIndex(0);
0060     ui.temp_unit->setCurrentIndex(0);
0061     ui.volume_unit->setCurrentIndex(0);
0062     ui.b_unit->setCurrentIndex(0);
0063 
0064     m_temp = Value(273.0, KUnitConversion::Kelvin);
0065     m_molarMass = 2.016;
0066     m_pressure = Value(1.0, KUnitConversion::Atmosphere);
0067     m_mass = Value(2.016, KUnitConversion::Gram);
0068     m_moles = 1.0;
0069     m_Vand_a = 0.0;
0070     m_Vand_b = Value(0.0, KUnitConversion::Liter);
0071     m_vol = Value(22.4, KUnitConversion::Liter);
0072 
0073     if (Prefs::ideal()) {
0074         ui.non_ideal->hide();
0075     }
0076 
0077     setMode(VOLUME);
0078 }
0079 
0080 void gasCalculator::setupUnitComboboxes()
0081 {
0082     QList<int> units;
0083     units << Gram << Milligram << Kilogram << Ton;
0084     KalziumUtils::populateUnitCombobox(ui.mass_unit, units);
0085 
0086     units.clear();
0087     units << Atmosphere << Pascal << Bar << Millibar << Torr;
0088     KalziumUtils::populateUnitCombobox(ui.pressure_unit, units);
0089 
0090     units.clear();
0091     units << Kelvin << Celsius << Fahrenheit;
0092     KalziumUtils::populateUnitCombobox(ui.temp_unit, units);
0093 
0094     units.clear();
0095     units << Liter << Milliliter << CubicMeter << KUnitConversion::GallonUS;
0096     KalziumUtils::populateUnitCombobox(ui.volume_unit, units);
0097 
0098     units.clear();
0099     units << Liter << Milliliter << CubicMeter << KUnitConversion::GallonUS;
0100     KalziumUtils::populateUnitCombobox(ui.b_unit, units);
0101 }
0102 
0103 int gasCalculator::getCurrentUnitId(QComboBox *comboBox)
0104 {
0105     return comboBox->itemData(comboBox->currentIndex()).toInt();
0106 }
0107 
0108 void gasCalculator::calculatePressure()
0109 {
0110     double volume = m_vol.convertTo(KUnitConversion::Liter).number();
0111     double temp = m_temp.convertTo(KUnitConversion::Kelvin).number();
0112     double b = m_Vand_b.convertTo(KUnitConversion::Liter).number();
0113 
0114     double pressure = m_moles * R * temp / (volume - m_moles * b) - m_moles * m_moles * m_Vand_a / volume / volume;
0115 
0116     m_pressure = Value(pressure, KUnitConversion::Atmosphere);
0117     m_pressure = m_pressure.convertTo(KUnitConversion::UnitId(getCurrentUnitId(ui.pressure_unit)));
0118     ui.pressure->setValue(m_pressure.number());
0119 }
0120 
0121 void gasCalculator::calculateMolarMass()
0122 {
0123     double mass = m_mass.convertTo(KUnitConversion::Gram).number();
0124     double volume = m_vol.convertTo(KUnitConversion::Liter).number();
0125     double pressure = m_pressure.convertTo(KUnitConversion::Atmosphere).number();
0126     double temp = m_temp.convertTo(KUnitConversion::Kelvin).number();
0127     double b = m_Vand_b.convertTo(KUnitConversion::Liter).number();
0128 
0129     m_molarMass = mass * R * temp / (pressure + m_moles * m_moles * m_Vand_a / volume / volume) / (volume - m_moles * b);
0130     ui.molarMass->setValue(m_molarMass);
0131 }
0132 
0133 void gasCalculator::calculateVol()
0134 {
0135     double pressure = m_pressure.convertTo(KUnitConversion::Atmosphere).number();
0136     double temp = m_temp.convertTo(KUnitConversion::Kelvin).number();
0137     double b = m_Vand_b.convertTo(KUnitConversion::Liter).number();
0138 
0139     double volume = m_moles * R * temp / pressure + (m_moles * b);
0140     m_vol = Value(volume, KUnitConversion::Liter);
0141     m_vol = m_vol.convertTo(KUnitConversion::UnitId(getCurrentUnitId(ui.volume_unit)));
0142     ui.volume->setValue(m_vol.number());
0143 }
0144 
0145 void gasCalculator::calculateTemp()
0146 {
0147     double volume = m_vol.convertTo(KUnitConversion::Liter).number();
0148     double pressure = m_pressure.convertTo(KUnitConversion::Atmosphere).number();
0149     double b = m_Vand_b.convertTo(KUnitConversion::Liter).number();
0150 
0151     double temp = (pressure + (m_moles * m_moles * m_Vand_a / volume / volume)) * (volume - m_moles * b) / m_moles / R;
0152     m_temp = Value(temp, KUnitConversion::Kelvin);
0153     m_temp = m_temp.convertTo(KUnitConversion::UnitId(getCurrentUnitId(ui.temp_unit)));
0154     ui.temp->setValue(m_temp.number());
0155 }
0156 
0157 void gasCalculator::calculateMoles()
0158 {
0159     double volume = m_vol.convertTo(KUnitConversion::Liter).number();
0160     double pressure = m_pressure.convertTo(KUnitConversion::Atmosphere).number();
0161     double temp = m_temp.convertTo(KUnitConversion::Kelvin).number();
0162     double b = m_Vand_b.convertTo(KUnitConversion::Liter).number();
0163 
0164     m_moles = (pressure + m_moles * m_moles * m_Vand_a / volume / volume) * (volume - m_moles * b) / R / temp;
0165     ui.moles->setValue(m_moles);
0166 }
0167 
0168 void gasCalculator::calculateMass()
0169 {
0170     double volume = m_vol.convertTo(KUnitConversion::Liter).number();
0171     double pressure = m_pressure.convertTo(KUnitConversion::Atmosphere).number();
0172     double temp = m_temp.convertTo(KUnitConversion::Kelvin).number();
0173     double b = m_Vand_b.convertTo(KUnitConversion::Liter).number();
0174 
0175     double mass = (pressure + m_moles * m_moles * m_Vand_a / volume / volume) * (volume - m_moles * b) * m_molarMass / R / temp;
0176     m_mass = Value(mass, KUnitConversion::Gram);
0177     m_mass = m_mass.convertTo(KUnitConversion::UnitId(getCurrentUnitId(ui.mass_unit)));
0178     ui.mass->setValue(m_mass.number());
0179 }
0180 
0181 void gasCalculator::volChanged()
0182 {
0183     m_vol = Value(ui.volume->value(), KUnitConversion::UnitId(getCurrentUnitId(ui.volume_unit)));
0184     calculate();
0185 }
0186 
0187 void gasCalculator::tempChanged()
0188 {
0189     m_temp = Value(ui.temp->value(), KUnitConversion::UnitId(getCurrentUnitId(ui.temp_unit)));
0190     calculate();
0191 }
0192 
0193 void gasCalculator::pressureChanged()
0194 {
0195     m_pressure = Value(ui.pressure->value(), KUnitConversion::UnitId(getCurrentUnitId(ui.pressure_unit)));
0196     calculate();
0197 }
0198 
0199 void gasCalculator::massChanged()
0200 {
0201     m_mass = Value(ui.mass->value(), KUnitConversion::UnitId(getCurrentUnitId(ui.mass_unit)));
0202     m_moles = m_mass.convertTo(KUnitConversion::Gram).number() / m_molarMass;
0203     ui.moles->setValue(m_moles);
0204     calculate();
0205 }
0206 
0207 void gasCalculator::molesChanged(double value)
0208 {
0209     m_moles = value;
0210     m_mass = Value(m_moles * m_molarMass, KUnitConversion::Gram);
0211     m_mass = m_mass.convertTo(KUnitConversion::UnitId(getCurrentUnitId(ui.mass_unit)));
0212     ui.mass->setValue(m_mass.number());
0213     calculate();
0214 }
0215 
0216 void gasCalculator::molarMassChanged(double value)
0217 {
0218     if (value == 0.0) {
0219         error(GAS_MOLAR_MASS_ZERO);
0220         return;
0221     }
0222     m_molarMass = value;
0223     m_mass = Value(m_molarMass * m_moles, KUnitConversion::Gram);
0224     m_mass = m_mass.convertTo(KUnitConversion::UnitId(getCurrentUnitId(ui.mass_unit)));
0225     ui.mass->setValue(m_mass.number());
0226     calculate();
0227 }
0228 
0229 void gasCalculator::Vand_aChanged()
0230 {
0231     m_Vand_a = ui.a->value();
0232     calculate();
0233 }
0234 
0235 void gasCalculator::Vand_bChanged()
0236 {
0237     m_Vand_b = Value(ui.b->value(), KUnitConversion::UnitId(getCurrentUnitId(ui.b_unit)));
0238     calculate();
0239 }
0240 
0241 void gasCalculator::setMode(int mode)
0242 {
0243     m_mode = mode;
0244 
0245     ui.moles->setReadOnly(false);
0246     ui.mass->setReadOnly(false);
0247     ui.pressure->setReadOnly(false);
0248     ui.temp->setReadOnly(false);
0249     ui.volume->setReadOnly(false);
0250 
0251     switch (mode) {
0252     case MOLES:
0253         ui.moles->setReadOnly(true);
0254         ui.mass->setReadOnly(true);
0255         break;
0256     case PRESSURE:
0257         ui.pressure->setReadOnly(true);
0258         break;
0259     case TEMPERATURE:
0260         ui.temp->setReadOnly(true);
0261         break;
0262     case VOLUME:
0263         ui.volume->setReadOnly(true);
0264         break;
0265     }
0266 
0267     calculate();
0268 }
0269 
0270 void gasCalculator::calculate()
0271 {
0272     error(RESET_GAS_MESSAGE);
0273 
0274     switch (m_mode) {
0275     case MOLES:
0276         calculateMoles();
0277         break;
0278     case PRESSURE:
0279         calculatePressure();
0280         break;
0281     case TEMPERATURE:
0282         calculateTemp();
0283         break;
0284     case VOLUME:
0285         calculateVol();
0286         break;
0287     }
0288 }
0289 
0290 void gasCalculator::error(int mode)
0291 {
0292     switch (mode) { // Depending on the mode, set the error messages.
0293     case RESET_GAS_MESSAGE:
0294         ui.error->setText(QString());
0295         break;
0296     case VOL_ZERO:
0297         ui.error->setText(i18n("Volume cannot be zero, please enter a valid value."));
0298         break;
0299     case GAS_MOLAR_MASS_ZERO:
0300         ui.error->setText(i18n("Molar mass cannot be zero, please enter a non-zero value."));
0301     default:
0302         break;
0303     }
0304 }