com.hfg.chem.solution.AqueousSolution Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com_hfg Show documentation
Show all versions of com_hfg Show documentation
com.hfg xml, html, svg, and bioinformatics utility library
package com.hfg.chem.solution;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import com.hfg.chem.Matter;
import com.hfg.units.*;
//------------------------------------------------------------------------------
/**
Represents an aqueous solution.
@author J. Alex Taylor, hairyfatguy.com
*/
//------------------------------------------------------------------------------
// com.hfg XML/HTML Coding Library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
// [email protected]
//------------------------------------------------------------------------------
public class AqueousSolution
{
// TODO: Should probably be a Set
private List mComponents = new ArrayList<>(5);
private Quantity mTargetQuantity;
private Quantity mActualQuantity;
// We don't want the auto-scaling to come back with wacky units like cL
// so we'll restrict the list of possible scaling factors.
private static SI_ScalingFactor[] sStandardMassScalingFactors;
private static SI_ScalingFactor[] sStandardVolumeScalingFactors;
static
{
sStandardMassScalingFactors = new SI_ScalingFactor[] {
SI_ScalingFactor.kilo,
SI_ScalingFactor.one,
SI_ScalingFactor.milli,
SI_ScalingFactor.micro,
SI_ScalingFactor.nano
};
sStandardVolumeScalingFactors = new SI_ScalingFactor[] {
SI_ScalingFactor.one,
SI_ScalingFactor.milli,
SI_ScalingFactor.micro,
SI_ScalingFactor.nano
};
}
//###########################################################################
// CONSTRUCTORS
//###########################################################################
//---------------------------------------------------------------------------
public AqueousSolution()
{
}
//###########################################################################
// PUBLIC METHODS
//###########################################################################
//---------------------------------------------------------------------------
/**
The target quantity is the amount of solution intended to be made.
The target quantity should be specified either in terms of volume or in terms of mass.
* @param inValue the target quantity of this aqueous solution
* @return this solution object to enable method chaining
*/
public AqueousSolution setTargetQuantity(Quantity inValue)
{
mTargetQuantity = inValue;
return this;
}
//---------------------------------------------------------------------------
public Quantity getTargetQuantity()
{
return mTargetQuantity;
}
//---------------------------------------------------------------------------
/**
The actual quantity should be specified either in terms of volume or in terms of mass.
* @param inValue the actual quantity of this aqueous solution
* @return this solution object to enable method chaining
*/
public AqueousSolution setActualQuantity(Quantity inValue)
{
mActualQuantity = inValue;
return this;
}
//---------------------------------------------------------------------------
public Quantity getActualQuantity()
{
return mActualQuantity;
}
//---------------------------------------------------------------------------
public AqueousSolution subtract(Quantity inValue)
{
mActualQuantity = mActualQuantity.subtract(inValue);
return this;
}
//---------------------------------------------------------------------------
public AqueousSolution defineComponent(Matter inSubstance, Quantity inConcentration)
{
mComponents.add(new MixtureComponent(inSubstance, inConcentration));
return this;
}
//---------------------------------------------------------------------------
public AqueousSolution defineComponent(MixtureComponent inComponent)
{
mComponents.add(inComponent);
return this;
}
//---------------------------------------------------------------------------
public Collection getComponents()
{
return Collections.unmodifiableCollection(mComponents);
}
//---------------------------------------------------------------------------
public Quantity getQuantity(Matter inMatter)
{
Quantity quantity = null;
for (MixtureComponent component : mComponents)
{
if (component.getSubstance().equals(inMatter))
{
quantity = component.getQuantity();
break;
}
}
return quantity;
}
//---------------------------------------------------------------------------
public Quantity calcQuantityOfStockSolutionNeeded(AqueousSolution inStockSolution)
{
Quantity stockQuantityNeeded = null;
Quantity componentTargetQuantity = null;
Matter stockComponent = inStockSolution.getComponents().iterator().next().getSubstance();
for (MixtureComponent component : mComponents)
{
if (component.getSubstance().equals(stockComponent))
{
componentTargetQuantity = component.getQuantity();
break;
}
}
Quantity stockComponentQuantity = inStockSolution.getQuantity(stockComponent);
Quantity componentQuantityNeeded = new Quantity(componentTargetQuantity.doubleValue(), componentTargetQuantity.getUnit().getNumerator());
Quantity componentDenominatorQuantity = new Quantity(1, componentTargetQuantity.getUnit().getDenominator());
double scalingFactor = componentDenominatorQuantity.convertTo(getTargetQuantity().getUnit()).doubleValue() * getTargetQuantity().doubleValue();
componentQuantityNeeded = componentQuantityNeeded.multiplyBy(scalingFactor);
if (componentQuantityNeeded.getUnit().getQuantityType().equals(QuantityType.AMOUNT_OF_SUBSTANCE))
{
Unit stockSolutionNumerator = inStockSolution.getQuantity(stockComponent).getUnit().getNumerator();
if (stockSolutionNumerator.getQuantityType().equals(QuantityType.AMOUNT_OF_SUBSTANCE))
{
componentQuantityNeeded = componentQuantityNeeded.convertTo(AmountOfSubstanceUnit.mole);
componentQuantityNeeded = componentQuantityNeeded.divideBy(inStockSolution.getQuantity(stockComponent).doubleValue());
stockQuantityNeeded = new Quantity(componentQuantityNeeded.doubleValue(), inStockSolution.getQuantity(stockComponent).getUnit().getDenominator());
}
else if (stockSolutionNumerator.getQuantityType().equals(QuantityType.MASS))
{
componentQuantityNeeded = componentQuantityNeeded.convertTo(AmountOfSubstanceUnit.mole);
// Convert from moles to grams using the molecular weight
componentQuantityNeeded = new Quantity(componentQuantityNeeded.multiplyBy(stockComponent.getAverageMass()).doubleValue(), MassUnit.gram);
stockQuantityNeeded = new Quantity(componentQuantityNeeded.divideBy(stockComponentQuantity.doubleValue()).doubleValue(), stockComponentQuantity.getUnit().getDenominator());
}
}
else if (componentQuantityNeeded.getUnit().getQuantityType().equals(QuantityType.MASS))
{
Unit stockSolutionNumerator = inStockSolution.getQuantity(stockComponent).getUnit().getNumerator();
if (stockSolutionNumerator.getQuantityType().equals(QuantityType.AMOUNT_OF_SUBSTANCE))
{
componentQuantityNeeded = componentQuantityNeeded.convertTo(MassUnit.gram);
// Convert from grams to moles using the molecular weight
componentQuantityNeeded = new Quantity(componentQuantityNeeded.divideBy(stockComponent.getAverageMass()).doubleValue(), AmountOfSubstanceUnit.mole);
stockQuantityNeeded = new Quantity(componentQuantityNeeded.divideBy(stockComponentQuantity.doubleValue()).doubleValue(), stockComponentQuantity.getUnit().getDenominator());
}
else if (stockSolutionNumerator.getQuantityType().equals(QuantityType.MASS))
{
componentQuantityNeeded = componentQuantityNeeded.convertTo(stockSolutionNumerator);
componentQuantityNeeded = componentQuantityNeeded.divideBy(inStockSolution.getQuantity(stockComponent).doubleValue());
stockQuantityNeeded = new Quantity(componentQuantityNeeded.doubleValue(), inStockSolution.getQuantity(stockComponent).getUnit().getDenominator());
}
}
SI_ScalingFactor[] allowedAutoScalingFactors = null;
if (stockQuantityNeeded.getUnit().getQuantityType().equals(QuantityType.VOLUME))
{
allowedAutoScalingFactors = sStandardVolumeScalingFactors;
}
else if (stockQuantityNeeded.getUnit().getQuantityType().equals(QuantityType.MASS))
{
allowedAutoScalingFactors = sStandardMassScalingFactors;
}
stockQuantityNeeded = stockQuantityNeeded.autoScale(allowedAutoScalingFactors);
return stockQuantityNeeded;
}
//---------------------------------------------------------------------------
public Quantity calcMassOfComponentNeeded(Matter inComponent)
{
Quantity componentTargetQuantity = null;
for (MixtureComponent component : mComponents)
{
if (component.getSubstance().equals(inComponent))
{
componentTargetQuantity = component.getQuantity();
break;
}
}
Quantity componentQuantityNeeded = new Quantity(componentTargetQuantity.doubleValue(), componentTargetQuantity.getUnit().getNumerator());
Quantity componentDenominatorQuantity = new Quantity(1, componentTargetQuantity.getUnit().getDenominator());
double scalingFactor = componentDenominatorQuantity.convertTo(getTargetQuantity().getUnit()).doubleValue() * getTargetQuantity().doubleValue();
componentQuantityNeeded = componentQuantityNeeded.multiplyBy(scalingFactor);
if (componentQuantityNeeded.getUnit().getQuantityType().equals(QuantityType.AMOUNT_OF_SUBSTANCE))
{
componentQuantityNeeded = componentQuantityNeeded.convertTo(AmountOfSubstanceUnit.mole);
// Convert from moles to grams using the molecular weight
componentQuantityNeeded = new Quantity(componentQuantityNeeded.multiplyBy(inComponent.getAverageMass()).doubleValue(), MassUnit.gram);
}
componentQuantityNeeded = componentQuantityNeeded.autoScale(sStandardMassScalingFactors);
return componentQuantityNeeded;
}
}