This commit is contained in:
h z
2024-06-21 23:42:10 +08:00
commit 6242ed2cf1
52 changed files with 4686 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom 12
/// </summary>
public class AAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.A;
/// <inheritdoc />
public override int AtomicNumber => 12;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateA;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateA;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateA;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassA;
}

View File

@@ -0,0 +1,386 @@
using System.Text;
using Skeleton.Algebra.AdditionalProperties.Extensions;
using Skeleton.Algebra.DimensionProviders;
using Skeleton.Constants;
using Skeleton.DataStructure;
using Skeleton.Utils.Helpers;
using VirtualChemistry.Chemistry.Bonds.Implements;
using VirtualChemistry.Chemistry.Bonds.Resolver;
using VirtualChemistry.Chemistry.Compounds.Implements;
using VirtualChemistry.Chemistry.Mixtures.Implements;
using VirtualChemistry.Constants;
using VirtualChemistry.DataStructure.Packs;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// meta atom
/// </summary>
public abstract class BaseAtom
{
/// <summary>
///
/// </summary>
protected BaseAtom()
{
LogEigenState = new(_ => EigenStateMatrix.Log());
BondInformationMatrix = new(
x => Bonds
.Select(bond => bond.LogState.GetFrom(x))
.DefaultIfEmpty(LieSU3.Zero)
.SpLieSum()
.Exp()
);
LogKernelMatrix = new(_ => KernelState.Log());
StateMatrix = new(x => BondInformationMatrix.GetFrom(x).ConjugateOn(EigenStateMatrix));
LogStateMatrix = new(x => BondInformationMatrix.GetFrom(x).ConjugateOn(LogEigenState.GetFrom(x)));
StructureMatrix = new(x =>
{
var h = Bonds
.Select(b => b.LogConnectionMatrix.GetFrom(x))
.DefaultIfEmpty(LieSU3.Zero)
.Union(new[] { LogStateMatrix.GetFrom(x), LogKernelMatrix.GetFrom(x) });
var s = h.SpLieSum().Exp();
return s;
}
);
EnergyDistributionFactor = new CacheItem<double>(
x =>
{
C3 v = StructureMatrix.GetFrom(x).Hermitian() * ChemistryConstant.AtomEnergyDistributionVector;
return ChemistryConstant.AtomEnergyDistributionSpectrum.Rayleigh<IDim3>(v);
}
);
}
/// <summary>
/// singleton to represent no atom
/// </summary>
public static readonly BaseAtom Null = new NullAtom();
/// <summary>
/// energy holds in the atom
/// </summary>
public double Energy
{
get => Bonds.Sum(bond => bond.Energy);
set
{
double energyFactor = Bonds.Sum(bond => bond.EnergyDistributionFactor.Get);
foreach (BaseBond bond in Bonds)
bond.Energy = value * bond.EnergyDistributionFactor.Get / energyFactor;
}
}
/// <summary>
/// describe how energy in molecular is distributed in this atom
/// </summary>
public CacheItem<double> EnergyDistributionFactor { get; }
/// <summary>
/// element name/ atom name
/// </summary>
public abstract string Element { get; }
/// <summary>
/// atomic number, redundant information as element
/// </summary>
public abstract int AtomicNumber { get; }
/// <summary>
/// atomic mass, wont change as long as atomic number is fixed
/// </summary>
public abstract double AtomicMass { get; }
/// <summary>
/// compound of this atom
/// </summary>
public Compound Compound { get; set; } = Compound.Null;
/// <summary>
/// homogeneous mixture of its compound
/// </summary>
public HomogeneousMixture HomogeneousMixture => Compound.HomogeneousMixture;
/// <summary>
/// bonds
/// </summary>
public HashSet<BaseBond> Bonds { get; set; } = new HashSet<BaseBond>();
/// <summary>
/// bonds that already connected with other bond
/// </summary>
public IEnumerable<BaseBond> ConnectedBonds => Bonds.Where(x => x.Connected);
/// <summary>
/// bonds that not connected with any other bond yet
/// </summary>
public IEnumerable<BaseBond> UnconnectedBonds => Bonds.Where(x => !x.Connected);
/// <summary>
/// atoms that connected to this atom directly
/// </summary>
public IEnumerable<BaseAtom> ConnectedAtoms => ConnectedBonds
.Select(bond => bond.ConnectedBond.Atom);
/// <summary>
/// mass of all directly connected atoms
/// </summary>
public double GroupMass => ConnectedAtoms
.Select(atom => atom.AtomicMass)
.DefaultIfEmpty(0d)
.Sum();
/// <summary>
/// if there is a path to specific atom
/// private use only
/// </summary>
/// <param name="atom"></param>
/// <param name="visited"></param>
/// <returns></returns>
private bool HasPathTo(BaseAtom atom, HashSet<BaseAtom> visited)
{
if (atom == this)
return true;
if (ConnectedAtoms.Contains(atom))
return true;
visited.Add(this);
return ConnectedAtoms
.Where(connectedAtom => !visited.Contains(connectedAtom))
.Any(connectedAtom => connectedAtom.HasPathTo(atom, visited));
}
/// <summary>
/// if there is a path to a specific atom
/// </summary>
/// <param name="atom"></param>
/// <returns></returns>
public bool HasPathTo(BaseAtom atom) => HasPathTo(atom, new HashSet<BaseAtom>());
/// <summary>
/// get the compound by connections
/// </summary>
public Compound GrabCompound
{
get
{
Compound res = new ();
res.Atoms.Add(this);
int aCount = 0;
while (aCount != res.Atoms.Count)
{
aCount = res.Atoms.Count;
foreach (BaseAtom a in res.Atoms
.SelectMany(a => a.ConnectedAtoms)
.Where(a => !res.Atoms.Contains(a))
.ToArray()
)
res.Atoms.Add(a);
}
res.HomogeneousMixture = HomogeneousMixture.Null;
res.Amount = 0d;
return res;
}
}
/// <summary>
/// how far is an atom from this one(directly connected atoms has distance 1)
/// </summary>
/// <param name="atom"></param>
/// <param name="visited"></param>
/// <returns></returns>
private int DistanceTo(BaseAtom atom, HashSet<BaseAtom> visited)
{
if (Compound != atom.Compound)
return -1;
if (atom == this)
return 0;
if(Compound.CachedDistance(this, atom) > 0)
return Compound.CachedDistance(this, atom);
if (ConnectedAtoms.Contains(atom))
return 1;
visited.Add(this);
int distance = ConnectedAtoms
.Where(connectedAtom => !visited.Contains(connectedAtom))
.Select(connectedAtom => connectedAtom.DistanceTo(atom, visited))
.DefaultIfEmpty(int.MaxValue)
.Min();
Compound.CacheDistance(this, atom, distance + 1);
return distance + 1;
}
/// <summary>
/// how far is an atom from this one(directly connected atoms has distance 1)
/// </summary>
/// <param name="atom"></param>
/// <returns></returns>
public int DistanceTo(BaseAtom atom) => DistanceTo(atom, new HashSet<BaseAtom>());
/// <summary>
/// all connections of this atom
/// </summary>
public IEnumerable<ConnectionInfo> Connections =>
Bonds
.Where(bond => bond.Connected)
.Select(bond => new ConnectionInfo(bond, bond.ConnectedBond, bond.ConnectedBond.Atom));
/// <summary>
/// distance info as map
/// </summary>
/// <returns></returns>
private Dictionary<int, HashSet<BaseAtom>> DistanceMap()
{
Dictionary<int, HashSet<BaseAtom>> res = new Dictionary<int, HashSet<BaseAtom>>();
foreach (BaseAtom atom in Compound.Atoms)
{
int dist = DistanceTo(atom);
if(!res.ContainsKey(dist))
res.Add(dist, new HashSet<BaseAtom>());
res[dist].Add(atom);
}
return res;
}
/// <summary>
/// order bonds by selectors
/// </summary>
public IOrderedEnumerable<BaseBond> OrderedBonds =>
Bonds
.OrderBy(bond => bond.Connected)
.ThenBy(bond => bond.BondNumber)
.ThenBy(bond => bond.Connected ? bond.ConnectedBond.BondNumber : 0)
.ThenBy(bond => bond.Connected ? bond.ConnectedBond.Atom.AtomicNumber : 0);
/// <summary>
/// kernel state matrix of the atom, wont change
/// </summary>
public abstract SU3 KernelState { get; }
/// <summary>
/// adj matrix wont change
/// </summary>
public abstract SU3 AdjointState { get; }
/// <summary>
/// eig matrix wont change
/// </summary>
public abstract SU3 EigenStateMatrix { get; }
/// <summary>
/// will never expire
/// </summary>
public CacheItem<LieSU3> LogKernelMatrix { get; }
/// <summary>
///
/// </summary>
public CacheItem<SU3> BondInformationMatrix { get; }
/// <summary>
/// will never expire
/// </summary>
public CacheItem<LieSU3> LogEigenState { get; }
/// <summary>
/// state matrix
/// </summary>
public CacheItem<SU3> StateMatrix { get; }
/// <summary>
/// log state matrix
/// </summary>
public CacheItem<LieSU3> LogStateMatrix { get; }
/// <summary>
/// get an unconnected bond of specific type
/// </summary>
/// <param name="bondType"></param>
/// <returns></returns>
public BaseBond NextUnconnected(string bondType) =>
Bonds
.Where(bond => bond.BondType == bondType)
.FirstOrDefault(bond => !bond.Connected, BaseBond.Null);
/// <summary>
/// get an unconnected bond of specific type, except for bonds in exclude set
/// </summary>
/// <param name="bondType"></param>
/// <param name="exclude"></param>
/// <returns></returns>
public BaseBond NextUnconnected(string bondType, HashSet<BaseBond> exclude) =>
Bonds
.Where(bond => bond.BondType == bondType)
.Where(bond => !exclude.Contains(bond))
.FirstOrDefault(bond => !bond.Connected, BaseBond.Null);
/// <summary>
/// get an unconnected bond of specific type that is not the excluded bond
/// </summary>
/// <param name="bondType"></param>
/// <param name="exclude"></param>
/// <returns></returns>
public BaseBond NextUnconnected(string bondType, BaseBond exclude) =>
Bonds
.Where(bond => bond.BondType == bondType)
.Where(bond => exclude != bond)
.FirstOrDefault(bond => !bond.Connected, BaseBond.Null);
/// <summary>
/// structure matrix
/// </summary>
public CacheItem<SU3> StructureMatrix { get; }
/// <summary>
/// the representation of the compound relative to a center atom
/// </summary>
/// <param name="center"></param>
/// <param name="visited"></param>
/// <returns></returns>
public StringBuilder IsoRepresentation(BaseAtom center, HashSet<BaseBond> visited)
{
HashSet<BaseBond> toVisit = Bonds
.Where(b => b.Connected)
.Where(b => !visited.Contains(b))
.Where(b => !visited.Contains(b.ConnectedBond))
.ToHashSet();
foreach (BaseBond b in toVisit)
{
visited.Add(b);
visited.Add(b.ConnectedBond);
}
Dictionary<BaseBond, StringBuilder> subRepresentations = new ();
foreach (BaseBond b in toVisit)
subRepresentations[b] =
b.ConnectedBond.Atom.IsoRepresentation(center, new HashSet<BaseBond>(visited));
StringBuilder res = new StringBuilder($"{Element}#{DistanceTo(center)}-[");
IEnumerable<BaseBond> visitOrder = toVisit
.GroupedOrderBy(bond => bond.BondNumber)
.GroupedThenBy(bond => bond.ConnectedBond.BondNumber)
.GroupedThenBy(bond => bond.ConnectedBond.Atom.AtomicNumber)
.GroupedThenBy(bond => bond.ConnectedBond.Atom.ConnectedAtoms.Count())
.GroupedThenBy(bond => subRepresentations[bond].ToString())
.SelectMany(g => g);
foreach (BaseBond b in visitOrder)
{
res.Append($"<{b.BondType}={b.ConnectedBond.BondType}*");
res.Append(subRepresentations[b]);
res.Append(">");
}
res.Append("]");
return res;
}
/// <summary>
/// the representation of the compound with this atom as center
/// </summary>
public string FullRepresentation => IsoRepresentation(this, new HashSet<BaseBond>()).ToString();
/// <summary>
/// initializer
/// </summary>
public void C()
{
Bonds = new HashSet<BaseBond>();
for (int bondNumber = 1; bondNumber <= 7; bondNumber++)
{
int xDiff = AtomicNumber - AlgebraConstant.Ludic(bondNumber);
if (AtomicNumber % AlgebraConstant.Ludic(bondNumber) != 0 &&
(xDiff < 0 || xDiff % 7 != 0))
continue;
for (int idx = 0; idx < ChemistryConstant.BondMaxNumbers(bondNumber); idx++)
Bonds.Add(BondResolver.Resolve(bondNumber));
}
foreach (BaseBond b in Bonds)
b.Atom = this;
}
}

View File

@@ -0,0 +1,27 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 13
/// </summary>
public class CxAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.Cx;
/// <inheritdoc />
public override int AtomicNumber => 13;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateCx;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateCx;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateCx;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassCx;
}

View File

@@ -0,0 +1,27 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 4
/// </summary>
public class DAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.D;
/// <inheritdoc />
public override int AtomicNumber => 4;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateD;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateD;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateD;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassD;
}

View File

@@ -0,0 +1,26 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 10
/// </summary>
public class EAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.E;
/// <inheritdoc />
public override int AtomicNumber => 10;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateE;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateE;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateE;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassE;
}

View File

@@ -0,0 +1,26 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 3
/// </summary>
public class EsAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.Es;
/// <inheritdoc />
public override int AtomicNumber => 3;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateEs;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateEs;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateEs;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassEs;
}

View File

@@ -0,0 +1,27 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 7
/// </summary>
public class KAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.K;
/// <inheritdoc />
public override int AtomicNumber => 7;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateK;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateK;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateK;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassK;
}

View File

@@ -0,0 +1,27 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 6
/// </summary>
public class MAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.M;
/// <inheritdoc />
public override int AtomicNumber => 6;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateM;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateM;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateM;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassM;
}

View File

@@ -0,0 +1,30 @@
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # -1, the atom used to represent no atom
/// </summary>
public sealed class NullAtom : BaseAtom
{
/// <inheritdoc />
public NullAtom()
{
}
/// <inheritdoc />
public override string Element => "Null";
/// <inheritdoc />
public override int AtomicNumber => throw new Exception();
/// <inheritdoc />
public override double AtomicMass => throw new Exception();
/// <inheritdoc />
public override SU3 KernelState => throw new Exception();
/// <inheritdoc />
public override SU3 AdjointState => throw new Exception();
/// <inheritdoc />
public override SU3 EigenStateMatrix => throw new Exception();
}

View File

@@ -0,0 +1,27 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 8
/// </summary>
public class PAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.P;
/// <inheritdoc />
public override int AtomicNumber => 8;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateP;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateP;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateP;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassP;
}

View File

@@ -0,0 +1,26 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 1
/// </summary>
public class QAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.Q;
/// <inheritdoc />
public override int AtomicNumber => 1;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateQ;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateQ;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateQ;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassQ;
}

View File

@@ -0,0 +1,26 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 2
/// </summary>
public class RAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.R;
/// <inheritdoc />
public override int AtomicNumber => 2;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateR;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateR;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateR;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassR;
}

View File

@@ -0,0 +1,26 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 9
/// </summary>
public class SoAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.So;
/// <inheritdoc />
public override int AtomicNumber => 9;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateSo;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateSo;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateSo;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassSo;
}

View File

@@ -0,0 +1,27 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 11
/// </summary>
public class UAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.U;
/// <inheritdoc />
public override int AtomicNumber => 11;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateU;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateU;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateU;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassU;
}

View File

@@ -0,0 +1,27 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 5
/// </summary>
public class UeAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.Ue;
/// <inheritdoc />
public override int AtomicNumber => 5;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateUe;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateUe;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateUe;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassUe;
}

View File

@@ -0,0 +1,26 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 14
/// </summary>
public class VAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.V;
/// <inheritdoc />
public override int AtomicNumber => 14;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateV;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateV;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateV;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassV;
}

View File

@@ -0,0 +1,27 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Implements;
/// <summary>
/// atom # 15
/// </summary>
public class ViAtom : BaseAtom
{
/// <inheritdoc />
public override string Element => ChemistryConstant.Elements.Vi;
/// <inheritdoc />
public override int AtomicNumber => 15;
/// <inheritdoc />
public override SU3 AdjointState => ChemistryConstant.AtomAdjoints.AtomAdjointStateVi;
/// <inheritdoc />
public override SU3 KernelState => ChemistryConstant.AtomKernels.AtomKernelStateVi;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.AtomEigenStates.AtomEigenStateVi;
/// <inheritdoc />
public override double AtomicMass => ChemistryConstant.AtomicMasses.AtomicMassVi;
}

View File

@@ -0,0 +1,72 @@
using VirtualChemistry.Chemistry.Atoms.Implements;
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Atoms.Resolver;
/// <summary>
/// get an atom instance from descriptions
/// </summary>
public static class AtomResolver
{
/// <summary>
/// create an atom from string
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static BaseAtom Resolve(string element)
{
BaseAtom res = element switch
{
ChemistryConstant.Elements.Q => new QAtom(),
ChemistryConstant.Elements.R => new RAtom(),
ChemistryConstant.Elements.Es => new EsAtom(),
ChemistryConstant.Elements.D => new DAtom(),
ChemistryConstant.Elements.Ue => new UeAtom(),
ChemistryConstant.Elements.M => new MAtom(),
ChemistryConstant.Elements.K => new KAtom(),
ChemistryConstant.Elements.P => new PAtom(),
ChemistryConstant.Elements.So => new SoAtom(),
ChemistryConstant.Elements.E => new EAtom(),
ChemistryConstant.Elements.U => new UAtom(),
ChemistryConstant.Elements.A => new AAtom(),
ChemistryConstant.Elements.Cx => new CxAtom(),
ChemistryConstant.Elements.V => new VAtom(),
ChemistryConstant.Elements.Vi => new ViAtom(),
_ => throw new Exception($"TODO-----{element}")
};
res.C();
return res;
}
/// <summary>
/// create an atom by number
/// </summary>
/// <param name="atomicNumber"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static BaseAtom Resolve(int atomicNumber)
{
BaseAtom res = atomicNumber switch
{
1 => new QAtom(),
2 => new RAtom(),
3 => new EsAtom(),
4 => new DAtom(),
5 => new UeAtom(),
6 => new MAtom(),
7 => new KAtom(),
8 => new PAtom(),
9 => new SoAtom(),
10 => new EAtom(),
11 => new UAtom(),
12 => new AAtom(),
13 => new CxAtom(),
14 => new VAtom(),
15 => new ViAtom(),
_ => throw new Exception("TODO")
};
res.C();
return res;
}
}

View File

@@ -0,0 +1,318 @@
using Skeleton.Algebra.AdditionalProperties.Extensions;
using Skeleton.Algebra.DimensionProviders;
using Skeleton.Algebra.Extensions;
using Skeleton.DataStructure;
using VirtualChemistry.Chemistry.Atoms.Implements;
using VirtualChemistry.Chemistry.Compounds.Implements;
using VirtualChemistry.Chemistry.Mixtures.Implements;
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Bonds.Implements;
/// <summary>
/// meta bond
/// </summary>
public abstract class BaseBond
{
/// <summary>
///
/// </summary>
protected BaseBond()
{
StateMatrix = new (_ =>
Connected ? EigenStateMatrix * ConnectedBond.EigenStateMatrix : EigenStateMatrix
);
LogKernel = new (_ => KernelStateMatrix.Log());
HalfBondInformation = new(x =>
LogKernel.GetFrom(x) + Atom.StructureMatrix.GetFrom(x).Log()
);
StructureMatrix = new(x =>
(HalfBondInformation.GetFrom(x) + (Connected ? ConnectedBond.HalfBondInformation.GetFrom(x) : LieSU3.Zero))
.Exp()
);
EnergyDistributionFactor = new(x =>
{
C3 v = StructureMatrix.GetFrom(x).Hermitian() * ChemistryConstant.BondEnergyDistributionVector;
return ChemistryConstant.BondEnergyDistributionSpectrum.Rayleigh<IDim3>(v);
}
);
LogConnectionMatrix = new(x => Connected
? (AdjointStateMatrix * ConnectedBond.AdjointStateMatrix)
.ConjugateOn(Atom.LogKernelMatrix.GetFrom(x))
: LieSU3.Zero
);
LogState = new (x => StateMatrix.GetFrom(x).Log());
AntibondingCatalyzeFactor = new(x =>
{
if (Connected || HomogeneousMixture == HomogeneousMixture.Null)
return 0;
U3 s = LogState.GetFrom(x).CayleyPositive();
LieSU3 f0 = HomogeneousMixture.LogStateMatrix.GetFrom(x).ConjugatedBy<IDim3, LieSU3>(s);
LieSU3 f1 = f0 ^ LogState.GetFrom(x);
U3 f2 = f1.CayleyNegative();
return f2.Det().Imaginary;
}
);
BondingCatalyzeFactor = new(x =>
{
if (!Connected || HomogeneousMixture == HomogeneousMixture.Null)
return 0;
U3 s = LogState.GetFrom(x).CayleyNegative();
LieSU3 f0 = HomogeneousMixture.LogStateMatrix.GetFrom(x).ConjugatedBy<IDim3, LieSU3>(s);
LieSU3 f1 = f0 ^ LogState.GetFrom(x);
U3 f2 = f1.CayleyPositive();
return f2.Det().Imaginary;
}
);
}
/// <summary>
///
/// </summary>
public Compound Compound => Atom.Compound;
/// <summary>
///
/// </summary>
public HomogeneousMixture HomogeneousMixture => Compound.HomogeneousMixture;
/// <summary>
/// null singleton
/// </summary>
public static readonly BaseBond Null = new NullBond();
/// <summary>
/// energy hold in this atom
/// </summary>
public double Energy { get; set; }
/// <summary>
/// how energy in the molecular is distributed into this atom
/// </summary>
public CacheItem<double> EnergyDistributionFactor { get; }
/// <summary>
/// the connected bond
/// </summary>
public BaseBond ConnectedBond { get; set; } = Null;
/// <summary>
/// atom that holds this bond
/// </summary>
public BaseAtom Atom { get; set; } = BaseAtom.Null;
/// <summary>
/// type of the bond
/// </summary>
public abstract string BondType { get; }
/// <summary>
/// kernel state matrix of the matrix, won't change as long as bond type is fixed
/// </summary>
public abstract SU3 KernelStateMatrix { get; }
/// <summary>
/// adj state matrix of the bond, won't change as long as bond type fixed
/// </summary>
public abstract SU3 AdjointStateMatrix { get; }
/// <summary>
/// eigen state matrix of bond, won't change as long as bond type fixed
/// </summary>
public abstract SU3 EigenStateMatrix { get; }
/// <summary>
/// log of the kernel state matrix
/// never expire
/// </summary>
public CacheItem<LieSU3> LogKernel { get; }
/// <summary>
/// skew hermitian matrix that represent the information of bond and its atom
/// </summary>
public CacheItem<LieSU3> HalfBondInformation { get; }
/// <summary>
/// special unitary matrix that represent the structure of the bond(its atom, connected bond and atom of connected bond)
/// </summary>
public CacheItem<SU3> StructureMatrix { get; }
/// <summary>
/// log of connection matrix
/// </summary>
public CacheItem<LieSU3> LogConnectionMatrix { get; set; }
/// <summary>
/// a special unitary matrix that represent the state of the bond
/// </summary>
public CacheItem<SU3> StateMatrix { get; }
/// <summary>
/// log of state matrix
/// </summary>
public CacheItem<LieSU3> LogState { get; }
/// <summary>
/// connect with another bond
/// </summary>
/// <param name="bond"></param>
/// <exception cref="Exception"></exception>
public void Connect(BaseBond bond)
{
if(Connected || bond.Connected)
return;
if(Atom.HomogeneousMixture != HomogeneousMixture.Null)
if (!Atom.Compound.Amount.IsEqualApprox(bond.Atom.Compound.Amount))
return;
if (bond == this)
throw new Exception("TODO");
ConnectedBond = bond;
bond.ConnectedBond = this;
StructureChanged();
bond.StructureChanged();
if (Atom.Compound.Atoms.Contains(bond.Atom))
return;
bond.Atom.HomogeneousMixture.Compounds.Remove(bond.Atom.Compound);
bond.Atom.Compound.Amount = 0d;
foreach (BaseAtom atom in bond.Atom.Compound.Atoms.ToHashSet())
{
Atom.Compound.Atoms.Add(atom);
atom.Compound = Atom.Compound;
}
}
/// <summary>
/// disconnect with connected bond
/// </summary>
public void Disconnect()
{
if (!Connected)
return;
BaseBond disconnectedBond = ConnectedBond;
ConnectedBond = BaseBond.Null;
disconnectedBond.ConnectedBond = BaseBond.Null;
StructureChanged();
disconnectedBond.StructureChanged();
if (Atom.HasPathTo(disconnectedBond.Atom))
return;
Compound newCompound = disconnectedBond.Atom.GrabCompound;
newCompound.Amount = Atom.Compound.Amount;
/*
newCompound.HomogeneousMixture = Atom.HomogeneousMixture;*/
foreach (BaseAtom atom in newCompound.Atoms)
{
atom.Compound = newCompound;
if (Atom.Compound.Atoms.Contains(atom))
Atom.Compound.Atoms.Remove(atom);
}
Atom.HomogeneousMixture.AddCompound(newCompound);
}
/// <summary>
/// if the bond is connected
/// </summary>
public bool Connected => ConnectedBond != Null;
/// <summary>
/// bond number, redundant information of bond type
/// </summary>
public abstract int BondNumber { get; }
private void StructureChanged()
{
//Atom.Compound.ResetDistanceCache();
Atom.Compound.CacheInit();
HalfBondInformation.Expire();
StateMatrix.Expire();
LogConnectionMatrix.Expire();
}
/// <summary>
/// Conditions for a pair of unconnected bonds tp connect:
/// 1. Energy difference of the two bond is less than a threshold
/// 2. Energy in both bonds is higher than bonding energy
///
/// if bond is connected, the antibonding energy is NaN
/// </summary>
/// <returns></returns>
public double EigenBondingEnergy()
{
if (Connected)
return double.NaN;
SU3 s1 = StructureMatrix.Get * Atom.StructureMatrix.Get;
C33 s2 = StructureMatrix.Get + Atom.StructureMatrix.Get;
double lowerLimit = -Math.PI;
double upperLimit = Math.PI;
C3 coVector = s2.Hermitian().ColumnAverage;
return s1
.ConjugateOn(new DiagR3(lowerLimit, 0d, upperLimit))
.Rayleigh(coVector);
}
/// <summary>
/// Conditions for a connected bond to break:
/// 1. energy difference of two connected bond is greater than a threshold
/// 2. energy in either bond is higher than antibonding energy
///
/// if bond is unconnected, the antibonding energy is
/// </summary>
/// <returns></returns>
public double EigenAntibondingEnergy()
{
if(!Connected)
return double.NaN;
SU3 s1 = Atom.StructureMatrix.Get.Hermitian() * StructureMatrix.Get;
SU3 s2 = ConnectedBond.Atom.StructureMatrix.Get.Hermitian() * ConnectedBond.StructureMatrix.Get;
C33 sw = s1 + s2;
SU3 w = (s1.Log() + s2.Log()).Exp();
C3 coVector = sw.ColumnAverageBivariant;
double upperLimit = -Math.PI;
double lowerLimit = Math.PI;
return w
.ConjugateOn(new DiagR3(lowerLimit, 0d, upperLimit))
.Rayleigh(coVector);
}
/// <summary>
/// how antibonding energy affected by mixture
/// </summary>
public CacheItem<double> AntibondingCatalyzeFactor { get; set; }
/// <summary>
/// hot bonding energy affected by chemical environment
/// </summary>
public CacheItem<double> BondingCatalyzeFactor { get; set; }
public double BondingEnergy => EigenBondingEnergy() + BondingCatalyzeFactor.Get;
public double AntiBondingEnergy => EigenAntibondingEnergy() + AntibondingCatalyzeFactor.Get;
/// <summary>
/// how to pair bonds
/// </summary>
public int BondingGroup
{
get
{
U3 sP = HalfBondInformation.Get.CayleyPositive();
U3 eN = HomogeneousMixture.LogStateMatrix.Get.CayleyNegative();
DiagR3 h = new(0, Math.PI, Math.PI * 2);
U3 w = sP * eN;
double t = w.ConjugateOn(h).Rayleigh(sP.ColumnAverageBivariant);
/*
//Complex t = (sP * eN).Trace();// + eN.Trace() * eN.Trace();
C33 a1 = sP * eN;
C33 a2 = eN * sP;
C33 w = a1 - a2;
Complex t = (w).Det() + a1.Trace() + a2.Trace();// * (eN*sP ).Trace();// * EigenStateMatrix.Trace();*/
//Console.WriteLine($"TRACE {t} -");
return t switch
{
> 7 * Math.PI / 4 or < Math.PI / 4 => 0,
> Math.PI / 4 and < 3 * Math.PI / 4 => 1,
> 3 * Math.PI / 4 and < 5 * Math.PI / 4 => 2,
_ => 3
};
}
}
}

View File

@@ -0,0 +1,23 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Bonds.Implements;
/// <summary>
/// bond # 3
/// </summary>
public class DBond : BaseBond
{
/// <inheritdoc />
public override string BondType => ChemistryConstant.BondTypes.D;
/// <inheritdoc />
public override int BondNumber => 3;
/// <inheritdoc />
public override SU3 KernelStateMatrix => ChemistryConstant.BondKernels.BondKernelD;
/// <inheritdoc />
public override SU3 AdjointStateMatrix => ChemistryConstant.BondAdjoints.BondAdjointD;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.BondEigenStates.BondEigenStateD;
}

View File

@@ -0,0 +1,24 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Bonds.Implements;
/// <summary>
/// bond # 7
/// </summary>
public class HBond : BaseBond
{
/// <inheritdoc />
public override string BondType => ChemistryConstant.BondTypes.H;
/// <inheritdoc />
public override int BondNumber => 7;
/// <inheritdoc />
public override SU3 KernelStateMatrix => ChemistryConstant.BondKernels.BondKernelH;
/// <inheritdoc />
public override SU3 AdjointStateMatrix => ChemistryConstant.BondAdjoints.BondAdjointH;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.BondEigenStates.BondEigenStateH;
}

View File

@@ -0,0 +1,25 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Bonds.Implements;
/// <summary>
/// bond # 1
/// </summary>
public class MBond : BaseBond
{
/// <inheritdoc />
public override string BondType => ChemistryConstant.BondTypes.M;
/// <inheritdoc />
public override int BondNumber => 1;
/// <inheritdoc />
public override SU3 KernelStateMatrix => ChemistryConstant.BondKernels.BondKernelM;
/// <inheritdoc />
public override SU3 AdjointStateMatrix => ChemistryConstant.BondAdjoints.BondAdjointM;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.BondEigenStates.BondEigenStateM;
}

View File

@@ -0,0 +1,27 @@
namespace VirtualChemistry.Chemistry.Bonds.Implements;
/// <summary>
/// bond singleton that represent no bond
/// </summary>
public class NullBond : BaseBond
{
/// <inheritdoc />
public NullBond()
{
}
/// <inheritdoc />
public override string BondType => throw new Exception();
/// <inheritdoc />
public override SU3 KernelStateMatrix => throw new Exception();
/// <inheritdoc />
public override SU3 AdjointStateMatrix => throw new Exception();
/// <inheritdoc />
public override SU3 EigenStateMatrix => throw new Exception();
/// <inheritdoc />
public override int BondNumber => throw new Exception();
}

View File

@@ -0,0 +1,24 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Bonds.Implements;
/// <summary>
/// bond # 6
/// </summary>
public class PBond : BaseBond
{
/// <inheritdoc />
public override string BondType => ChemistryConstant.BondTypes.P;
/// <inheritdoc />
public override int BondNumber => 6;
/// <inheritdoc />
public override SU3 KernelStateMatrix => ChemistryConstant.BondKernels.BondKernelP;
/// <inheritdoc />
public override SU3 AdjointStateMatrix => ChemistryConstant.BondAdjoints.BondAdjointP;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.BondEigenStates.BondEigenStateP;
}

View File

@@ -0,0 +1,25 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Bonds.Implements;
/// <summary>
/// bond # 5
/// </summary>
public class QBond : BaseBond
{
/// <inheritdoc />
public override string BondType => ChemistryConstant.BondTypes.Q;
/// <inheritdoc />
public override int BondNumber => 5;
/// <inheritdoc />
public override SU3 KernelStateMatrix => ChemistryConstant.BondKernels.BondKernelQ;
/// <inheritdoc />
public override SU3 AdjointStateMatrix => ChemistryConstant.BondAdjoints.BondAdjointQ;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.BondEigenStates.BondEigenStateQ;
}

View File

@@ -0,0 +1,24 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Bonds.Implements;
/// <summary>
/// bond # 2
/// </summary>
public class SBond : BaseBond
{
/// <inheritdoc />
public override string BondType => ChemistryConstant.BondTypes.S;
/// <inheritdoc />
public override int BondNumber => 2;
/// <inheritdoc />
public override SU3 KernelStateMatrix => ChemistryConstant.BondKernels.BondKernelS;
/// <inheritdoc />
public override SU3 AdjointStateMatrix => ChemistryConstant.BondAdjoints.BondAdjointS;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.BondEigenStates.BondEigenStateS;
}

View File

@@ -0,0 +1,24 @@
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Bonds.Implements;
/// <summary>
/// bond # 4
/// </summary>
public class YBond : BaseBond
{
/// <inheritdoc />
public override string BondType => ChemistryConstant.BondTypes.Y;
/// <inheritdoc />
public override int BondNumber => 4;
/// <inheritdoc />
public override SU3 KernelStateMatrix => ChemistryConstant.BondKernels.BondKernelY;
/// <inheritdoc />
public override SU3 AdjointStateMatrix => ChemistryConstant.BondAdjoints.BondAdjointY;
/// <inheritdoc />
public override SU3 EigenStateMatrix => ChemistryConstant.BondEigenStates.BondEigenStateY;
}

View File

@@ -0,0 +1,53 @@
using VirtualChemistry.Chemistry.Bonds.Implements;
using VirtualChemistry.Constants;
namespace VirtualChemistry.Chemistry.Bonds.Resolver;
/// <summary>
/// create a bond instance by descriptions
/// </summary>
public static class BondResolver
{
/// <summary>
/// create the bond by type
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static BaseBond Resolve(string type)
{
BaseBond res = type switch
{
ChemistryConstant.BondTypes.M => new MBond(),
ChemistryConstant.BondTypes.S => new SBond(),
ChemistryConstant.BondTypes.D => new DBond(),
ChemistryConstant.BondTypes.Y => new YBond(),
ChemistryConstant.BondTypes.Q => new QBond(),
ChemistryConstant.BondTypes.P => new PBond(),
ChemistryConstant.BondTypes.H => new HBond(),
_ => throw new Exception("TODO")
};
return res;
}
/// <summary>
/// create a bond by number
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static BaseBond Resolve(int number)
{
BaseBond res = number switch
{
1 => new MBond(),
2 => new SBond(),
3 => new DBond(),
4 => new YBond(),
5 => new QBond(),
6 => new PBond(),
7 => new HBond(),
_ => throw new Exception("TODO")
};
return res;
}
}

View File

@@ -0,0 +1,477 @@
using Skeleton.Algebra.Extensions;
using Skeleton.DataStructure;
using Skeleton.DataStructure.Packs;
using Skeleton.Utils;
using Skeleton.Utils.Helpers;
using Skeleton.Utils.InverseSampling;
using VirtualChemistry.Chemistry.Atoms.Implements;
using VirtualChemistry.Chemistry.Bonds.Implements;
using VirtualChemistry.Chemistry.Compounds.Resolver;
using VirtualChemistry.Chemistry.Mixtures.Implements;
using VirtualChemistry.DataStructure.Packs;
namespace VirtualChemistry.Chemistry.Compounds.Implements;
/// <summary>
/// a cluster of molecular of the same kind
/// </summary>
public class Compound
{
/// <summary>
/// singleton used to represent no compound
/// </summary>
public static readonly Compound Null = new Compound();
private string? IsoRepresentationCache { get; set; }
/// <summary>
/// Constructor
/// </summary>
public Compound()
{
CacheInit();
LogStateMatrix = new(x => Atoms
.Select(atom => atom.LogStateMatrix.GetFrom(x))
.DefaultIfEmpty(LieSU3.Zero)
.SpLieSum()
);
StateMatrix = new(x => LogStateMatrix.GetFrom(x).Exp());
CompressionElasticity = new (x => (
LogStateMatrix.GetFrom(x).CayleyNegative() * StateMatrix.GetFrom(x))
.ConjugateOn(new DiagR3(0d, 2d * Math.PI, 4d * Math.PI))
.Rayleigh(LogStateMatrix.GetFrom(x).ColumnAverage)
);
CompressionBias = new (x =>
{
DiagR3 w1 = new (1d / 11d, 7d / 11d, 10d / 11d);
DiagR3 w2 = new (2d / 17d, 8d / 17d, 16d / 17d);
double p1 = StateMatrix.GetFrom(x).ConjugateOn(w1).Rayleigh(StateMatrix.GetFrom(x).Hermitian().ColumnAverage);
double p2 = StateMatrix.GetFrom(x).Hermitian().ConjugateOn(w2).Rayleigh(StateMatrix.GetFrom(x).ColumnAverageBivariant);
double x1 = InverseSampling.StandardNormal(p1) / 4d - 2d * Math.PI;
double x2 = InverseSampling.StandardNormal(p2) / 3d + 2d * Math.PI;
return Math.Atan(Math.Abs(x1) > Math.Abs(x2) ? x1 : x2) * 2d;
}
);
FreeDensity = new(x =>
{
double avg = (Math.Exp(-4d * Math.PI) + Math.Exp(Math.PI)) / 2d;
DiagR3 spectrum = new DiagR3(Math.Exp(-4d * Math.PI), avg, Math.Exp(Math.PI));
double tempMod = Math.Exp(-Phase);
return tempMod * LogStateMatrix.GetFrom(x)
.CayleyPositive()
.ConjugateOn(spectrum)
.Rayleigh(StateMatrix.GetFrom(x).ColumnAverageBivariant);
});
}
/// <summary>
/// initialize cache
/// </summary>
public void CacheInit()
{
HomogeneousMixture.ResetAllCache();
ResetDistanceCache();
IsoRepresentationCache = null;
}
/// <summary>
///
/// </summary>
public List<string> TraceLog { get; } = new();
/// <summary>
/// compression elasticity, refer to the homogeneous mixture version
/// </summary>
public CacheItem<double> CompressionElasticity { get; }
/// <summary>
/// compression bias, refer to the homogeneous mixture version
/// </summary>
public CacheItem<double> CompressionBias { get; }
/// <summary>
/// all atoms in the molecular
/// </summary>
public HashSet<BaseAtom> Atoms { get; set; } = new ();
/// <summary>
/// all connections in this compound
/// </summary>
public IOrderedEnumerable<FullConnectionInfo> Connections
{
get
{
HashSet<BaseBond> visited = new ();
List<FullConnectionInfo> res = new ();
foreach (BaseBond bond in Bonds.Where(bond => bond.Connected))
{
if(visited.Contains(bond))
continue;
if(res.All(con => !con.TryAbsorbBond(bond)))
res.Add(new FullConnectionInfo(bond));
visited.Add(bond);
visited.Add(bond.ConnectedBond);
}
return res.OrderBy(con => con.Representation);
}
}
public IEnumerable<BaseBond> UnconnectedIndex() => Atoms.Count > 15 ?
Array.Empty<BaseBond>():
Bonds.Where(bond => !bond.Connected && bond.Energy > bond.BondingEnergy);
/// <summary>
/// string used to save the compound
/// </summary>
public string ConnectionInfo => String.Join(':', Connections.Select(con => con.Representation));
/// <summary>
/// all bonds in the compound
/// </summary>
public IEnumerable<BaseBond> Bonds => Atoms.SelectMany(atom => atom.Bonds);
/// <summary>
/// the homogeneous mixture of this compound
/// </summary>
public HomogeneousMixture HomogeneousMixture { get; set; } = HomogeneousMixture.Null;
/// <summary>
/// state matrix of the compound
/// </summary>
public CacheItem<SU3> StateMatrix { get; }
/// <summary>
/// log state matrix
/// </summary>
public CacheItem<LieSU3> LogStateMatrix { get; }
/// <summary>
/// a quantity to compare phase among different materials
/// </summary>
public double Phase => Math.Tanh(Temperature * CompressionElasticity.Get + CompressionBias.Get);
/// <summary>
/// compression stiffness, refer to the homogeneous mixture version
/// </summary>
public double CompressionStiffness => Math.Exp(Math.PI / 2d * (5d * Phase - 3d));
/// <summary>
/// temperature of the compound
/// </summary>
public double Temperature => HomogeneousMixture.Temperature;
/// <summary>
/// unique chemical expression of the compound
/// </summary>
public string Expression =>
Atoms
.GroupBy(atom => atom.Element)
.OrderBy(group => group.First().AtomicNumber)
.Select(group => $"{group.First().Element}"+ (group.Count() > 1 ? group.Count().ToString() : "") )
.DefaultIfEmpty("")
.Aggregate((a, b) => a + b);
/// <summary>
/// dump the compound into save string
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public string Dump()
{
Dictionary<BaseAtom, string> atomMap = new Dictionary<BaseAtom, string>();
Dictionary<BaseBond, string> bondMap = new Dictionary<BaseBond, string>();
HashSet<string> records = new HashSet<string>();
foreach (BaseAtom atom in Atoms)
atomMap[atom] = $"({atom.Element}.{atomMap.Count})";
foreach (BaseBond bond in Bonds.Where(bond => bond.Connected))
bondMap[bond] = $"<{bond.BondType}.{bondMap.Count}>";
foreach (BaseAtom atom in Atoms)
{
if (atom.Bonds.All(bond => !bond.Connected))
{
records.Add($"{atomMap[atom]}-<xxx.0>-<xxx.0>-(xxx.0)");
continue;
}
foreach (BaseBond bond in atom.Bonds.Where(bond => bond.Connected))
{
if (bond == bond.ConnectedBond)
throw new Exception("TODO");
if (bondMap[bond] == bondMap[bond.ConnectedBond])
throw new Exception("TODO");
string record =
$"{atomMap[atom]}-{bondMap[bond]}-{bondMap[bond.ConnectedBond]}-{atomMap[bond.ConnectedBond.Atom]}";
string revRecord =
$"{atomMap[bond.ConnectedBond.Atom]}-{bondMap[bond.ConnectedBond]}-{bondMap[bond]}-{atomMap[atom]}";
if(records.Contains(revRecord))
continue;
records.Add(record);
}
}
return String.Join('|', records) + $"<CompAmtSp>{Amount.ExactDoubleString()}";
}
/// <summary>
/// dump with mapped infomation
/// </summary>
/// <returns></returns>
public CompoundDumpMap MappedDump()
{
Dictionary<BaseAtom, string> atomMap = new();
Dictionary<BaseBond, string> bondMap = new();
HashSet<string> records = new();
foreach (BaseAtom atom in Atoms)
atomMap[atom] = $"{atom.Element}.{atomMap.Count}";
foreach (BaseBond bond in Bonds.Where(bond => bond.Connected))
bondMap[bond] = $"{bond.BondType}.{bondMap.Count}";
foreach (BaseAtom atom in Atoms)
{
if (atom.Bonds.All(bond => !bond.Connected))
{
records.Add($"({atomMap[atom]})-<xxx.0>-<xxx.0>-(xxx.0)");
continue;
}
foreach (BaseBond bond in atom.Bonds.Where(bond => bond.Connected))
{
string record =
$"({atomMap[atom]})-<{bondMap[bond]}>-<{bondMap[bond.ConnectedBond]}>-({atomMap[bond.ConnectedBond.Atom]})";
string revRecord =
$"({atomMap[bond.ConnectedBond.Atom]})-<{bondMap[bond.ConnectedBond]}>-<{bondMap[bond]}>-({atomMap[atom]})";
if(records.Contains(revRecord))
continue;
records.Add(record);
}
}
string dumpString = String.Join('|', records);
return new CompoundDumpMap(atomMap, bondMap, dumpString);
}
/// <summary>
/// make a copy of the compound
/// </summary>
/// <returns></returns>
public Compound Copy() => CompoundResolver.Resolve(Dump());
/// <summary>
/// make a copy with map
/// </summary>
/// <param name="handle"></param>
/// <returns></returns>
public PlainPack2<Compound, BaseBond> CopyWithBondMap(BaseBond handle)
{
CompoundDumpMap dm = MappedDump();
CompoundResolveMap rm = CompoundResolver.MappedResolve(dm.DumpString);
if (dm.BondMap.ContainsKey(handle))
return new PlainPack2<Compound, BaseBond>(rm.ResolvedCompound, rm.BondMap[dm.BondMap[handle]]);
return new PlainPack2<Compound, BaseBond>(rm.ResolvedCompound, rm.AtomMap[dm.AtomMap[handle.Atom]].NextUnconnected(handle.BondType));
}
/// <summary>
/// distance between atoms
/// </summary>
public Dictionary<BaseAtom, Dictionary<BaseAtom, int>> DistanceCache { get; set; } =
new Dictionary<BaseAtom, Dictionary<BaseAtom, int>>();
/// <summary>
/// get the cached distance between two atoms in the compound
/// </summary>
/// <param name="a1"></param>
/// <param name="a2"></param>
/// <returns></returns>
public int CachedDistance(BaseAtom a1, BaseAtom a2)
{
if(DistanceCache.Keys.Contains(a1))
if (DistanceCache[a1].Keys.Contains(a2))
return DistanceCache[a1][a2];
if(DistanceCache.Keys.Contains(a2))
if (DistanceCache[a2].Keys.Contains(a1))
return DistanceCache[a2][a1];
return -1;
}
/// <summary>
/// save distance of two atoms in this compound into cache
/// </summary>
/// <param name="a1"></param>
/// <param name="a2"></param>
/// <param name="distance"></param>
public void CacheDistance(BaseAtom a1, BaseAtom a2, int distance)
{
if (!DistanceCache.ContainsKey(a1))
DistanceCache[a1] = new Dictionary<BaseAtom, int>();
DistanceCache[a1][a2] = distance;
}
/// <summary>
/// reset the cache
/// </summary>
public void ResetDistanceCache() => DistanceCache = new Dictionary<BaseAtom, Dictionary<BaseAtom, int>>();
/// <summary>
/// if two compound has the same structure
/// </summary>
/// <param name="compound"></param>
/// <returns></returns>
public bool IsometricTo(Compound compound)
{
if (!Expression.Equals(compound.Expression))
return false;
if(!ConnectionInfo.Equals(compound.ConnectionInfo))
return false;
if (!StateMatrix.Get.IsEqualApprox(compound.StateMatrix.Get))
return false;
return IsoRepresentation.Equals(compound.IsoRepresentation, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// amount of molecular in this compound
/// </summary>
public double Amount { get; set; }
/// <summary>
/// energy per amount
/// </summary>
public double UnitEnergy
{
get => Energy / Amount;
set => Energy = value * Amount;
}
/// <summary>
/// energy
/// </summary>
public double Energy
{
get => Atoms.Sum(atom => atom.Energy) * Amount;
set
{
double energyPerAmount = value / Amount;
double energyFactor = Atoms.Sum(atom => atom.EnergyDistributionFactor.Get);
foreach (BaseAtom atom in Atoms)
atom.Energy = energyPerAmount * atom.EnergyDistributionFactor.Get / energyFactor;
}
}
/// <summary>
/// amount : total mixture amount
/// </summary>
public double Concentration =>
Amount / (HomogeneousMixture == HomogeneousMixture.Null ? Amount : HomogeneousMixture.Amount);
/// <summary>
/// split into two compounds
/// </summary>
/// <param name="amount"></param>
/// <param name="byRatio"></param>
/// <returns></returns>
public Compound Split(double amount, bool byRatio = false)
{
if (amount.IsEqualApprox(0))
return Null;
if ((!byRatio && amount.IsEqualApprox(Amount)) || (byRatio && amount.IsEqualApprox(1)))
{
HomogeneousMixture.Compounds.Remove(this);
HomogeneousMixture = HomogeneousMixture.Null;
return this;
}
double ebs = Energy;
Compound res = Copy();
if(!byRatio)
{
double ratio = amount / Amount;
Amount -= amount;
res.Amount = amount;
res.Energy = ebs * ratio;
Energy = ebs * (1d - ratio);
}
else
{
res.Amount = Amount * amount;
Amount *= (1d - amount);
res.Energy = ebs * amount;
Energy = ebs * (1d - amount);
}
res.HomogeneousMixture = HomogeneousMixture.Null;
return res;
}
/// <summary>
/// split with bond information
/// </summary>
/// <param name="amount"></param>
/// <param name="handle"></param>
/// <param name="byRatio"></param>
/// <returns></returns>
public PlainPack2<Compound, BaseBond> SplitWithBondMap(double amount, BaseBond handle, bool byRatio = false)
{
/*if (Amount.IsEqualApprox(0))
throw new Exception("DD");
if ((Amount * 0.5).IsEqualApprox(0))
throw new Exception("FS");*/
PlainPack2<Compound, BaseBond> res = CopyWithBondMap(handle);
if (!byRatio)
{
double ratio = amount / Amount;
double splitEnergy = Energy * ratio;
double energy = Energy - splitEnergy;
Amount -= amount;
res.Item1.Amount = amount;
Energy = energy;
res.Item1.Energy = splitEnergy;
}
else
{
double splitEnergy = Energy * amount;
double energy = Energy * (1 - amount);
res.Item1.Amount = Amount * amount;
Amount *= 1 - amount;
Energy = energy;
res.Item1.Energy = splitEnergy;
}
HomogeneousMixture.AddCompound(res.Item1, true, true);
return res;
}
/// <summary>
/// mass per molecular
/// </summary>
public double MolecularMass => Atoms
.Select(atom => atom.AtomicMass)
.DefaultIfEmpty(0d)
.Sum();
/// <summary>
/// unique representation of a compound
/// </summary>
public string IsoRepresentation => IsoRepresentationCache ??= Atoms
.GroupedMinBy(a => -a.AtomicNumber)
.GroupedMinBy(a => a.ConnectedAtoms.Count())
.GroupedApproxMinBy(a => a.GroupMass)
.GroupedApproxMinBy(a => a.StateMatrix.Get.Det().Real)
.GroupedApproxMinBy(a => a.StateMatrix.Get.Trace().Real)
.GroupedApproxMinBy(a => a.StructureMatrix.Get.Det().Real)
.Select(a => a.FullRepresentation)
.Min() ?? "";
/// <summary>
/// a real number from 0 to 1
/// depend on temperature
/// Resolve Level
/// when A is next to B(above or below)
/// the one with higher resolve level will try to absorb the other one
///
/// Higher Level => behaviour like solvent
/// Lower Level => behaviour like solute
/// </summary>
public double ResolveLevel
{
get
{
double Normalizer(double x) => 2d * (Math.Tanh(-x * 3d) + 1d) / 5d + 1d / 5d;
double C(double x) => 1 - Math.Exp(-x);
double z = C(C(Phase));
C3 divisor = (StateMatrix.Get.ColumnAverage + LogStateMatrix.Get.ColumnAverageBivariant.Conj()) / 2d;
double factor = StateMatrix.Get.ConjugateOn(new DiagR3(1d, 1d / 9d, 1d / 3d)).Rayleigh(divisor);
return factor * Normalizer(Phase) / Math.Cosh(z);
}
}
/*
* Phase of compound is determined by compression stiffness
* higher stiffness => more like gas
* lower stiffness => more like solid
*
* resolvability of one solute A in solvent B(resolve level of A is less than B)
* if both A and B are solid => 0
*
* otherwise determined by many factors
*
*/
/// <summary>
///
/// </summary>
public CacheItem<double> FreeDensity { get; }
}

View File

@@ -0,0 +1,111 @@
using System.Text.RegularExpressions;
using Skeleton.Utils;
using VirtualChemistry.Chemistry.Atoms.Implements;
using VirtualChemistry.Chemistry.Atoms.Resolver;
using VirtualChemistry.Chemistry.Bonds.Implements;
using VirtualChemistry.Chemistry.Compounds.Implements;
using VirtualChemistry.DataStructure.Packs;
namespace VirtualChemistry.Chemistry.Compounds.Resolver;
/// <summary>
/// get compound by save string
/// </summary>
public static class CompoundResolver
{
private const string AtomRegex = @"\(([a-zA-Z]+\.[0-9]+)\)";
private const string BondRegex = @"<([a-zA-Z]+\.[0-9]+)>";
/// <summary>
/// resolve into map
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public static CompoundResolveMap MappedResolve(string expression)
{
Compound res = new Compound();
IEnumerable<string> records = expression.Split('|');
Dictionary<string, BaseAtom> atomMap = new();
Dictionary<string, BaseBond> bondMap = new();
foreach (string record in records)
{
List<string> connection = record.Split('-').ToList();
string atom1 = new Regex(AtomRegex).Match(connection[0]).Result("$1");
string bond1 = new Regex(BondRegex).Match(connection[1]).Result("$1");
string bond2 = new Regex(BondRegex).Match(connection[2]).Result("$1");
string atom2 = new Regex(AtomRegex).Match(connection[3]).Result("$1");
if (bond1.Equals("xxx.0", StringComparison.OrdinalIgnoreCase))
{
BaseAtom single = AtomResolver.Resolve(atom1.Split('.')[0]);
atomMap[atom1] = single;
single.Compound = res;
res.Atoms.Add(single);
res.CacheInit();
return new CompoundResolveMap(atomMap, bondMap, res);
}
if (!atomMap.Keys.Contains(atom1))
atomMap[atom1] = AtomResolver.Resolve(atom1.Split('.')[0]);
if (!atomMap.Keys.Contains(atom2))
atomMap[atom2] = AtomResolver.Resolve(atom2.Split('.')[0]);
atomMap[atom1].Compound = res;
atomMap[atom2].Compound = res;
res.Atoms.Add(atomMap[atom1]);
res.Atoms.Add(atomMap[atom2]);
BaseBond ba = atomMap[atom1].NextUnconnected(bond1.Split('.')[0]);
BaseBond bb = atomMap[atom2].NextUnconnected(bond2.Split('.')[0], ba);
ba.Connect(bb);
bondMap[bond1] = ba;
bondMap[bond2] = bb;
}
res.CacheInit();
return new CompoundResolveMap(atomMap, bondMap, res);
}
/// <summary>
/// get the compound by save string
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public static Compound Resolve(string expression)
{
string[] parts = expression.Split("<CompAmtSp>");
expression = parts[0];
Compound res = new Compound();
res.Amount = parts[1].ByteStringToDouble();
IEnumerable<string> records = expression.Split('|');
Dictionary<string, BaseAtom> atomMap = new Dictionary<string, BaseAtom>();
foreach (string record in records)
{
List<string> connection = record.Split('-').ToList();
string atom1 = new Regex(AtomRegex).Match(connection[0]).Result("$1");
string bond1 = new Regex(BondRegex).Match(connection[1]).Result("$1");
string bond2 = new Regex(BondRegex).Match(connection[2]).Result("$1");
string atom2 = new Regex(AtomRegex).Match(connection[3]).Result("$1");
if (bond1.Equals("xxx.0", StringComparison.OrdinalIgnoreCase))
{
BaseAtom single = AtomResolver.Resolve(atom1.Split('.')[0]);
single.Compound = res;
res.Atoms.Add(single);
res.CacheInit();
return res;
}
if (!atomMap.Keys.Contains(atom1))
atomMap[atom1] = AtomResolver.Resolve(atom1.Split('.')[0]);
if (!atomMap.Keys.Contains(atom2))
atomMap[atom2] = AtomResolver.Resolve(atom2.Split('.')[0]);
atomMap[atom1].Compound = res;
atomMap[atom2].Compound = res;
res.Atoms.Add(atomMap[atom1]);
res.Atoms.Add(atomMap[atom2]);
BaseBond b1 = atomMap[atom1].NextUnconnected(bond1.Split('.')[0]);
BaseBond b2 = atomMap[atom2].NextUnconnected(bond2.Split('.')[0], b1);
b1.Connect(b2);
}
res.CacheInit();
return res;
}
}

View File

@@ -0,0 +1,27 @@
using VirtualChemistry.Chemistry.Mixtures.Implements;
namespace VirtualChemistry.Chemistry.Containers;
/// <summary>
///
/// </summary>
public interface IChemicalContainer
{
/// <summary>
///
/// </summary>
/// <returns></returns>
double Volume();
/// <summary>
///
/// </summary>
HeterogeneousMixture Content { get; set; }
/// <summary>
///
/// </summary>
public double EnvironmentPressure { get; set; }
/// <summary>
///
/// </summary>
public double EnvironmentTemperature { get; set; }
}

View File

@@ -0,0 +1,29 @@
using VirtualChemistry.Chemistry.Mixtures.Implements;
namespace VirtualChemistry.Chemistry.Containers;
/// <summary>
/// container singleton used to represent no container
/// </summary>
public sealed class NullContainer : IChemicalContainer
{
private NullContainer()
{
}
/// <summary>
/// instance
/// </summary>
public static readonly NullContainer Null = new();
/// <inheritdoc />
public double Volume() => Double.PositiveInfinity;
/// <inheritdoc />
public HeterogeneousMixture Content { get; set; } = HeterogeneousMixture.Null;
/// <inheritdoc />
public double EnvironmentPressure { get; set; }
/// <inheritdoc />
public double EnvironmentTemperature { get; set; }
}

View File

@@ -0,0 +1,12 @@
namespace VirtualChemistry.Chemistry.Environments.Implements;
/// <summary>
/// the environment
/// </summary>
public class Environment
{
/// <summary>
/// environment temperature
/// </summary>
public double Temperature { get; set; }
}

View File

@@ -0,0 +1,158 @@
using Skeleton.DataStructure.Link;
using VirtualChemistry.Chemistry.Containers;
using VirtualChemistry.Chemistry.Mixtures.Resolver;
namespace VirtualChemistry.Chemistry.Mixtures.Implements;
/// <summary>
/// a collection of homogeneous mixtures
/// </summary>
public class HeterogeneousMixture
{
public HeterogeneousMixture()
{
}
public HeterogeneousMixture(IChemicalContainer c)
{
Container = c;
}
/// <summary>
/// singleton used to represent no mixture
/// </summary>
public static readonly HeterogeneousMixture Null = new HeterogeneousMixture();
/// <summary>
/// container of the mixture
/// </summary>
public IChemicalContainer Container { get; set; } = NullContainer.Null;
/// <summary>
/// volume of the container
/// </summary>
public double ContainerVolume => Container.Volume();
/// <summary>
/// all homogeneous mixtures within
/// </summary>
public HashSet<HomogeneousMixture> Layers { get; set; } = new();
/// <summary>
/// homogeneous mixtures in order from bottom to top
/// </summary>
public Link<HomogeneousMixture> LayerOrder { get; set; } = new();
/// <summary>
/// add an empty homo mixture to the layers
/// </summary>
/// <returns></returns>
public HomogeneousMixture AddLayer()
{
HomogeneousMixture res = new HomogeneousMixture();
AddLayer(res);
return res;
}
/// <summary>
/// remove a homo from the layers
/// </summary>
/// <param name="m"></param>
public void RemoveLayer(HomogeneousMixture m)
{
if (this == Null)
return;
Layers.Remove(m);
LayerOrder.Remove(m.Layer);
m.HeterogeneousMixture = Null;
m.Layer = LinkNode<HomogeneousMixture>.Null;
}
/// <summary>
/// add a homo mixture into this as a new layer
/// </summary>
/// <param name="m"></param>
/// <param name="atHead"></param>
public void AddLayer(HomogeneousMixture m, bool atHead=true)
{
m.HeterogeneousMixture.RemoveLayer(m);
m.HeterogeneousMixture = this;
Layers.Add(m);
if (atHead)
LayerOrder.AddFirst(m);
else
LayerOrder.AddLast(m);
}
/// <summary>
/// total amount of molecular
/// </summary>
public double Amount
{
get => Layers
.Select(l => l.Amount)
.DefaultIfEmpty(0d)
.Sum();
set
{
Dictionary<HomogeneousMixture, double> res = new Dictionary<HomogeneousMixture, double>();
foreach (HomogeneousMixture l in Layers)
res[l] = value * l.Ratio;
foreach (HomogeneousMixture l in Layers)
l.Amount = res[l];
}
}
/// <summary>
/// if this degenerate into a single homo mixture
/// </summary>
public bool IsHomogeneous => Layers.Count == 1;
/// <summary>
/// dump the mixture into save string
/// </summary>
/// <returns></returns>
public string Dump() =>
$"`LAYERS{String.Join(HeterogeneousMixtureResolver.LayerSplit, LayerOrder.Select(layer => layer.Dump()))}`%LAYERS";
/// <summary>
/// volume of contents
/// </summary>
public double Volume => Layers.Sum(layer => layer.Volume);
/// <summary>
/// the total stiffness of all contents
/// </summary>
public double EquivalentStiffness => 1d / Layers.Sum(h => 1d / h.CompressionStiffness);
/// <summary>
/// volume of contents under 0 pressure
/// </summary>
public double FreeVolume => Layers.Sum(h => h.FreeVolume);
private double ContentVolume => Layers.Sum(h => h.Volume);
/// <summary>
/// the force from container
/// </summary>
public double ForceFromContainer => (Math.Min(FreeVolume, Volume) - ContentVolume) * EquivalentStiffness;
/// <summary>
/// process one step of all its homogeneous mixture<br/>
/// including reaction, resolving/precipitating compounds,<br/>
/// heat exchange and volume update
/// </summary>
public void OneStep()
{
foreach (HomogeneousMixture h in Layers)
{
if(h.Layer.Next.IsEnding)
continue;
if(h.Density > h.Layer.Next.Value.Density)
h.Layer.MoveForward();
}
foreach (HomogeneousMixture h in Layers)
h.React();
foreach (HomogeneousMixture h in Layers.ToArray())
h.PrecipitateAndResolve();
foreach (HomogeneousMixture h in Layers)
{
h.Degenerate();
h.VolumeUpdate();
h.HeatExchange();
}
}
}

View File

@@ -0,0 +1,772 @@
using System.Numerics;
using Skeleton.Algebra.Extensions;
using Skeleton.Algebra.ScalarFieldStructure;
using Skeleton.DataStructure;
using Skeleton.DataStructure.Link;
using Skeleton.DataStructure.Packs;
using Skeleton.Utils;
using Skeleton.Utils.Helpers;
using Skeleton.Utils.InverseSampling;
using VirtualChemistry.Chemistry.Bonds.Implements;
using VirtualChemistry.Chemistry.Compounds.Implements;
using VirtualChemistry.Chemistry.Mixtures.Resolver;
using VirtualChemistry.Constants;
using VirtualChemistry.DataStructure.Packs;
namespace VirtualChemistry.Chemistry.Mixtures.Implements;
/// <summary>
/// mixture of many well mixed compounds that can not be seperated by psy methods
/// </summary>
public class HomogeneousMixture
{
/// <summary>
/// Constructor by default
/// </summary>
public HomogeneousMixture()
{
LogStateMatrix = new CacheItem<LieSU3>(x =>
Compounds.Select(compound => compound.LogStateMatrix.GetFrom(x) * compound.Concentration)
.DefaultIfEmpty(LieSU3.Zero)
.SpLieSum()
);
StateMatrix = new(x => LogStateMatrix.GetFrom(x).Exp());
CompressionElasticity = new(x =>
{
DiagR3 spectrum = new (0d, 2d * Math.PI, 4d * Math.PI);
return (LogStateMatrix.GetFrom(x).CayleyNegative() * StateMatrix.GetFrom(x))
.ConjugateOn(spectrum)
.Rayleigh(LogStateMatrix.GetFrom(x).ColumnAverage);
}
);
CompressionBias = new(x =>
{
DiagR3 w1 = new (1d / 11d, 7d / 11d, 10d / 11d);
DiagR3 w2 = new (2d / 17d, 8d / 17d, 16d / 17d);
double p1 = StateMatrix.GetFrom(x)
.ConjugateOn(w1)
.Rayleigh(StateMatrix.GetFrom(x).Hermitian().ColumnAverage);
double p2 = StateMatrix.GetFrom(x)
.Hermitian()
.ConjugateOn(w2)
.Rayleigh(StateMatrix.GetFrom(x).ColumnAverageBivariant);
double x1 = InverseSampling.StandardNormal(p1) / 4d - 2d * Math.PI;
double x2 = InverseSampling.StandardNormal(p2) / 3d + 2d * Math.PI;
return Math.Atan(Math.Abs(x1) > Math.Abs(x2) ? x1 : x2) * 2d;
}
);
FreeDensity = new(x =>
{
double avg = (Math.Exp(-4d * Math.PI) + Math.Exp(Math.PI)) / 2d;
DiagR3 spectrum = new DiagR3(Math.Exp(-4d * Math.PI), avg, Math.Exp(Math.PI));
double tempMod = Math.Exp(-Phase);
return tempMod * LogStateMatrix.GetFrom(x)
.CayleyPositive()
.ConjugateOn(spectrum)
.Rayleigh(StateMatrix.GetFrom(x).ColumnAverageBivariant);
}
);
HeatConductivity = new(x =>
StateMatrix.GetFrom(x).ConjugateOn(ChemistryConstant.EnergyConductivitySpectrum)
.Rayleigh(LogStateMatrix.GetFrom(x) * StateMatrix.GetFrom(x).ColumnAverageBivariant)
);
ResetAllCache();
}
/// <summary>
/// singleton used to represent no mixture
/// </summary>
public static readonly HomogeneousMixture Null = new();
private IEnumerable<BaseBond> ConnectedIndex()
{
HashSet<BaseBond> bs = new();
foreach (Compound c in Compounds)
{
if(c.Amount.IsEqualApprox(0))
continue;
foreach (BaseBond b in c.Bonds)
{
if (b.Compound.Amount.IsEqualApprox(0))
throw new Exception("P??");
if (b.Compound != c)
throw new Exception("??!!?");
if (
b.Connected &&
b.Energy > b.AntiBondingEnergy &&
b.ConnectedBond.Energy > b.ConnectedBond.AntiBondingEnergy &&
!bs.Contains(b.ConnectedBond)
)
{
bs.Add(b);
}
}
}
return bs;
//Compounds.Where(c => !(0.5 * c.Amount).IsEqualApprox(0)).SelectMany(x => x.ConnectedIndex());
}
public void RPC()
{
int s1 = 0;
int s2 = 0;
int s3 = 0;
int s4 = 0;
foreach (Compound c in Compounds)
{
foreach (BaseBond b in c.Bonds)
{
switch (b.BondingGroup)
{
case 0:
s1++;
break;
case 1:
s2++;
break;
case 2:
s3++;
break;
default:
s4++;
break;
}
}
}
Console.WriteLine($"{s1} ---- {s2} ---- {s3} --- {s4}");
}
private BondGroups ReactionGroup()
{
HashSet<BaseBond> group1 = new();
HashSet<BaseBond> group2 = new();
HashSet<BaseBond> group3 = new();
HashSet<BaseBond> group4 = new();
foreach (Compound c in Compounds)
{
if ((c.Amount * 0.125).IsEqualApprox(0) || c.Atoms.Count > 15)
continue;
if(c.Expression.Equals("P2So"))
Console.WriteLine("?");
foreach(BaseBond b in c.Bonds)
{
if(b.Connected || !(b.Energy > b.BondingEnergy))
continue;
switch (b.BondingGroup)
{
case 0:
group1.Add(b);
break;
case 1:
group2.Add(b);
break;
case 2:
group3.Add(b);
break;
case 3:
group4.Add(b);
break;
}
}
}
return new(group1, group2, group3, group4);
}
/// <summary>
/// elasticity range: 0, 4pi
/// elasticity controls the speed k drops from e^pi to e^-4pi
/// elasticity -> 0; k -> constant
/// b -> 4pi; k -> e^pi
/// b -> -4pi; k -> e^-4pi
/// </summary>
public CacheItem<double> CompressionElasticity { get; }
/// <summary>
/// bias range: -4pi, 4pi
/// bias controls the temp of triple point
/// higher b -> higher melting point and higher boiling point
/// </summary>
public CacheItem<double> CompressionBias { get; }
/// <summary>
/// phase -> 1 implies material is more like gas
/// phase -> -1 implies material is more like solid
///
/// </summary>
public double Phase => Compounds.Sum(c => c.Concentration * c.Phase);
/// <summary>
/// stiffness range: e^-4pi, e^pi
/// higher stiffness -> harder to compress -> solid like
/// lower stiffness -> easier to compress -> gas like
/// Stiffness K, Density D, Free Density D0, Temperature T
/// P = K(1/D - 1/D0)
///
/// Temperature range: -pi, pi
/// </summary>
public double CompressionStiffness => Math.Exp(Math.PI / 2d * (5d * Phase - 3d));
/// <summary>
/// e^-4pi ... e^pi
/// </summary>
public CacheItem<double> FreeDensity { get; }
/// <summary>
/// volume that under 0 compression
/// </summary>
public double FreeVolume => Amount / FreeDensity.Get;
/// <summary>
/// P = K (1/D - 1/D0)
/// </summary>
public double Pressure => (Volume - FreeVolume) * CompressionStiffness;
/// <summary>
/// Volume of the mixture
/// </summary>
public double Volume { get; set; }
/// <summary>
/// Heat transfer ability
/// </summary>
public CacheItem<double> HeatConductivity { get; }
/// <summary>
/// energy / amount = temperature
/// </summary>
public double Temperature
{
get => Energy / Amount;
set => Energy = value * Amount;
}
/// <summary>
/// total Energy the mixture holds
/// </summary>
public double Energy
{
get => Compounds.Sum(c => c.Energy);
set
{
foreach (Compound c in Compounds)
c.Energy = value * c.Concentration;
}
}
/// <summary>
/// reset all cache
/// </summary>
public void ResetAllCache()
{
LayerCache = LinkNode<HomogeneousMixture>.Null;
}
/// <summary>
/// the heterogeneous mixture that holds this homogeneous mixture
/// </summary>
public HeterogeneousMixture HeterogeneousMixture { get; set; } = HeterogeneousMixture.Null;
/// <summary>
/// Compounds of this mixture
/// </summary>
public HashSet<Compound> Compounds { get; set; } = new HashSet<Compound>();
/// <summary>
/// Compounds whose ratio is greater than 1%
/// </summary>
public IEnumerable<Compound> MainCompounds => Compounds.Where(c => c.Concentration > 0.001d);
private LinkNode<HomogeneousMixture> LayerCache { get; set; } = LinkNode<HomogeneousMixture>.Null;
/// <summary>
///
/// </summary>
public LinkNode<HomogeneousMixture> Layer
{
get => LayerCache == LinkNode<HomogeneousMixture>.Null
? HeterogeneousMixture.LayerOrder.Find(this)
: LayerCache;
set => LayerCache = value;
}
/// <summary>
/// State matrix of this mixture
/// </summary>
public CacheItem<SU3> StateMatrix { get; }
/// <summary>
/// Log of the state matrix
/// </summary>
public CacheItem<LieSU3> LogStateMatrix { get; }
/// <summary>
/// Split the homogeneous mixture into another heterogeneous mixture by ratio or amount;
/// </summary>
/// <param name="amount"> The amount or ratio</param>
/// <param name="into">another heterogeneous mixture</param>
/// <param name="byRatio">determine if the amount variable is ratio or amount</param>
/// <returns></returns>
public HomogeneousMixture Split(double amount, HeterogeneousMixture into, bool byRatio = false)
{
double ebs = Energy;
double vbs = Volume;
double ratio = byRatio ? amount : amount / Amount;
HomogeneousMixture res = new HomogeneousMixture();
foreach (Compound c in Compounds)
{
Compound split = c.Split(amount, byRatio);
if(split != Compound.Null)
res.AddCompound(split);
}
res.Energy = ebs*ratio;
res.Volume = vbs*ratio;
Energy = ebs * (1 - ratio);
Volume = vbs * (1 - ratio);
into.AddLayer(res);
return res;
}
/// <summary>
/// Add compound into the homogeneous mixture
/// </summary>
/// <param name="compound">compound to add</param>
/// <param name="resetCache"></param>
/// <param name="skipCombine">add without combine to isomorphic compound</param>
public void AddCompound(Compound compound, bool resetCache = true, bool skipCombine=false)
{
if (compound.HomogeneousMixture == this)
return;
bool added = false;
if(!skipCombine)
{
foreach (Compound sCompound in Compounds.Where(x => x.Expression == compound.Expression))
{
if (sCompound.IsometricTo(compound))
{
sCompound.Amount += compound.Amount;
compound.Amount = 0d;
sCompound.Energy += compound.Energy;
added = true;
break;
}
}
}
compound.HomogeneousMixture = added ? Null : this;
if (!added)
Compounds.Add(compound);
if(resetCache)
ResetAllCache();
}
/// <summary>
/// Amount of this mixture
/// </summary>
public double Amount
{
get => Compounds
.Select(c => c.Amount)
.DefaultIfEmpty(0)
.Sum();
set
{
Dictionary<Compound, double> res = new Dictionary<Compound, double>();
foreach (Compound c in Compounds)
res[c] = value * c.Concentration;
foreach (Compound c in Compounds)
c.Amount = res[c];
}
}
/// <summary>
/// ratio of this mixture in the heterogeneous mixture
/// </summary>
public double Ratio =>
Amount / (HeterogeneousMixture == HeterogeneousMixture.Null ? Amount : HeterogeneousMixture.Amount);
/// <summary>
///
/// </summary>
/// <param name="homo"></param>
public void Resolve(HomogeneousMixture homo)
{
foreach (Compound c in homo.Compounds)
Resolve(c, false);
ResetAllCache();
}
/// <summary>
///
/// </summary>
/// <param name="compound"></param>
/// <param name="resetCache"></param>
public void Resolve(Compound compound, bool resetCache = true)
{
AddCompound(compound, resetCache);
}
/// <summary>
/// density of the mixture, amount of molecular per volume
/// </summary>
public double Density => Amount / Volume;
/// <summary>
/// save mixture into string
/// </summary>
/// <returns></returns>
public string Dump() =>
$"`ENV?ENG{Energy.ExactDoubleString()}?V{Volume.ExactDoubleString()}`%ENV`COMPS{String.Join(HomogeneousMixtureResolver.CompoundsSplit, Compounds.Select(c => c.Dump()))}`%COMPS";
/// <summary>
/// update volume
/// </summary>
public void VolumeUpdate()
{
double sVolume = Volume + HeterogeneousMixture.ForceFromContainer / CompressionStiffness;
Volume = Math.Max(sVolume, 1E-6);
}
/// <summary>
/// exchange energy to neighbor mixtures
/// </summary>
public void HeatExchange()
{
if (Layer != Layer.Parent.First)
{
HomogeneousMixture mPrevious = Layer.Previous.Value;
double balanceTemp = (Energy + mPrevious.Energy) / (Amount + mPrevious.Amount);
double dTemp = balanceTemp - Temperature;
double conductivity = Math.Sqrt(HeatConductivity.Get * mPrevious.HeatConductivity.Get);
double transferTemp = dTemp * conductivity;
Temperature += transferTemp;
mPrevious.Temperature -= transferTemp;
}
if (Layer != Layer.Parent.Last)
{
HomogeneousMixture mNext = Layer.Next.Value;
double balanceTemp = (Energy + mNext.Energy) / (Amount + mNext.Amount);
double dTemp = balanceTemp - Temperature;
double conductivity = Math.Sqrt(HeatConductivity.Get * mNext.HeatConductivity.Get);
double transferTemp = dTemp * conductivity;
Temperature += transferTemp;
mNext.Temperature -= transferTemp;
}
double envBalanceTemp = HeterogeneousMixture.Container.EnvironmentTemperature;
double envDTemp = envBalanceTemp - Temperature;
double envConductivity = HeatConductivity.Get;
Temperature += envDTemp * envConductivity;
}
private void ReactConnecting(HashSet<BaseBond> g1, HashSet<BaseBond> g2)
{
double maxCd = -1;
BaseBond xb1 = BaseBond.Null;
BaseBond xb2 = BaseBond.Null;
foreach (BaseBond b1 in g1)
{
foreach (BaseBond b2 in g2)
{
H3 cd = new(Complex.ImaginaryOne / 2 * (b1.LogState.Get + b2.LogState.Get));
double cdX = cd.Rayleigh((b1.LogState.Get + b2.LogState.Get).ColumnAverage);
if (cdX > maxCd)
{
maxCd = cdX;
xb1 = b1;
xb2 = b2;
}
}
}
if (xb1 == BaseBond.Null)
return;
if (xb1 == xb2)
{
PlainPack2<Compound, BaseBond> s = xb1.Compound.SplitWithBondMap(0.5, xb2, true);
xb2 = s.Item2;
}
if (xb1.Compound.Amount.IsSignificantlyGreaterThen(xb2.Compound.Amount))
{
double amountDiff = xb1.Compound.Amount - xb2.Compound.Amount;
Compound oth = xb1.Compound.Split(amountDiff);
xb1.HomogeneousMixture.AddCompound(oth);
}
if (xb1.Compound.Amount.IsSignificantlyLessThen(xb2.Compound.Amount))
{
double amountDiff = xb2.Compound.Amount - xb1.Compound.Amount;
Compound oth = xb2.Compound.Split(amountDiff);
xb2.HomogeneousMixture.AddCompound(oth);
}
string log = $"From Composite React of {xb1.Compound.Amount}*{xb1.Compound.Expression} and {xb2.Compound.Amount}*{xb2.Compound.Expression}";
xb1.Connect(xb2);
xb1.Compound.TraceLog.Add(log);
}
private int ReactionType()
{
Complex d = LogStateMatrix.Get.CayleyPositive().Det();
return d.Phase switch
{
> 7 * Math.PI / 4 or < Math.PI / 4 => 0,
> Math.PI / 4 and < 3 * Math.PI / 4 => 1,
> 3 * Math.PI / 4 and < 5 * Math.PI / 4 => 2,
_ => 3
};
}
/// <summary>
/// react within the homogeneous mixture
/// </summary>
public void React()
{
BaseBond[] connected = ConnectedIndex().ToArray();
foreach (BaseBond bond in connected)
{
if (bond.Compound.Amount.IsEqualApprox(0))
continue;
if (
bond.Energy > bond.AntiBondingEnergy &&
bond.ConnectedBond.Energy > bond.ConnectedBond.AntiBondingEnergy
)
{
bond.Disconnect();
}
}
for (int i = 1; i <= 3; i++)
{
BondGroups bg = ReactionGroup();
int type = ReactionType();
if(type == 0)
{
ReactConnecting(bg.Group1, bg.Group3);
ReactConnecting(bg.Group2, bg.Group4);
}
else if (type == 1)
{
ReactConnecting(bg.Group1, bg.Group1);
ReactConnecting(bg.Group3, bg.Group3);
}
else if (type == 2)
{
ReactConnecting(bg.Group2, bg.Group2);
ReactConnecting(bg.Group3, bg.Group3);
}
else
{
ReactConnecting(bg.Group1, bg.Group4);
ReactConnecting(bg.Group2, bg.Group3);
}
}
}
/// <summary>
/// higher level mixture can resolve lower level mixture
/// </summary>
public double ResolveLevel => Compounds.Sum(c => c.Concentration * c.ResolveLevel);
/// <summary>
/// ability to resolve other compound
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
public double Resolvability(Compound c)
{
LieSU3 s = c.LogStateMatrix.Get ^ LogStateMatrix.Get;
C3 a = new(1, 0.5, 1);
C3 b = new(0.5, 1, 0.5);
Complex w = a * s * b;
w = ComplexFieldStructure.Structure.Fix(w);
double res = -Math.Tan((Math.Sin(w.Phase) * Math.PI - Math.PI) / 2);
if (Math.Abs(res) < 1E-6)
return 0;
return res;
}
/// <summary>
/// a tensor of order 3 abstracted from this mixture
/// </summary>
public C3 Ita => Compounds
.Select(c => c.Concentration * c.StateMatrix.Get.ColumnAverageBivariant)
.Aggregate((a, b) => a + b);
/// <summary>
/// Red component
/// </summary>
public Byte ColorRed => (Byte)
(
StateMatrix.Get
.ConjugateOn(ChemistryConstant.OpticalFilter.RedDefinite)
.Rayleigh(Ita) * 255
);
/// <summary>
/// Green component
/// </summary>
public Byte ColorGreen => (Byte)
(
StateMatrix.Get
.ConjugateOn(ChemistryConstant.OpticalFilter.GreenDefinite)
.Rayleigh(Ita) * 255
);
/// <summary>
/// Blue component
/// </summary>
public Byte ColorBlue => (Byte)
(
StateMatrix.Get
.ConjugateOn(ChemistryConstant.OpticalFilter.BlueDefinite)
.Rayleigh(Ita) * 255
);
/// <summary>
/// Transparent component
/// </summary>
public Byte ColorTransparent => (Byte)
(
StateMatrix.Get
.ConjugateOn(ChemistryConstant.OpticalFilter.OpacityDefinite)
.Rayleigh(Ita) * 255
);
/// <summary>
/// Should not be used by any methods except ResolveNext and ResolvePrev
/// </summary>
private void PureResolve(HomogeneousMixture hOther)
{
HashSet<Compound> toAbsorb = new ();
foreach (Compound c in hOther.Compounds)
{
double maxRes = Resolvability(c);
double oRes = hOther.Resolvability(c);
if(oRes < 0 || maxRes < 0 || maxRes < oRes)
continue;
double maxResAmount = Amount;
foreach (Compound ct in Compounds)
if (ct.IsometricTo(c))
maxResAmount -= ct.Amount;
maxResAmount *= maxRes;
if(maxResAmount < 0)
continue;
double splitAmount = Math.Min(maxResAmount, c.Amount);
if(splitAmount.IsEqualApprox(0))
continue;
string log = $"{splitAmount} split from {c.Amount} * {c.Expression}";
Compound cSplit = c.Split(splitAmount);
cSplit.TraceLog.Add(log);
toAbsorb.Add(cSplit);
}
foreach (Compound c in toAbsorb)
AddCompound(c);
if(hOther.Amount.IsEqualApprox(0))
HeterogeneousMixture.RemoveLayer(hOther);
}
private void ResolveNext()
{
if (HeterogeneousMixture == HeterogeneousMixture.Null || Layer.Next.IsTail)
return;
PureResolve(Layer.Next.Value);
}
private void ResolvePrevious()
{
if (HeterogeneousMixture == HeterogeneousMixture.Null || Layer.Previous.IsHead)
return;
PureResolve(Layer.Previous.Value);
}
private bool Resolve()
{
ResolveNext();
ResolvePrevious();
return false;
}
private bool Precipitate()
{
foreach (Compound c in Compounds)
{
double maxRes = Resolvability(c);
if (maxRes < 0)
continue;
double maxResAmount = maxRes * (Amount - c.Amount);
if(maxResAmount.IsEqualApprox(0))
continue;
double aDiff = c.Amount - maxResAmount;
if (aDiff.IsSignificantlyGreaterThen(0) )
{
Compound oth = c.Split(c.Amount - maxResAmount);
if (oth.FreeDensity.Get > FreeDensity.Get)
{
if (Layer.Next.IsEnding)
{
HomogeneousMixture m = HeterogeneousMixture.AddLayer();
m.Layer.MoveAfter(Layer);
m.AddCompound(oth);
m.Volume = m.FreeVolume;
return true;
}
Layer.Next.Value.AddCompound(oth);
}
else
{
if (Layer.Previous.IsEnding)
{
HomogeneousMixture m = HeterogeneousMixture.AddLayer();
m.Layer.MoveBefore(Layer);
m.AddCompound(oth);
m.Volume = m.FreeVolume;
return true;
}
Layer.Previous.Value.AddCompound(oth);
}
}
}
return false;
}
/// <summary>
///
/// </summary>
/// <returns>if any new layer created or deleted</returns>
public bool PrecipitateAndResolve()
{
bool a = Resolve();
bool b = Precipitate();
return a || b;
}
/// <summary>
/// combine identical compounds in the miture
/// </summary>
public void Degenerate()
{
HashSet<Compound> toRemove = new();
foreach (IGrouping<string, Compound> g in Compounds.GroupBy(c => c.Expression))
{
HashSet<Compound> classified = new();
foreach (Compound c in g)
{
classified.Add(c);
foreach (Compound cx in g.Where(x => !classified.Contains(x)))
{
if (!c.IsometricTo(cx))
continue;
classified.Add(cx);
c.Amount += cx.Amount;
cx.Amount = 0;
toRemove.Add(cx);
}
}
}
foreach (Compound c in toRemove)
{
c.HomogeneousMixture = Null;
Compounds.Remove(c);
}
}
public static void Test()
{
Func<double, double> a = x => -Math.Tan((Math.PI * x - Math.PI) / 2);
Console.WriteLine(a(0));
Console.WriteLine(a(-1));
Console.WriteLine(a(1));
}
}

View File

@@ -0,0 +1,32 @@
using System.Text.RegularExpressions;
using VirtualChemistry.Chemistry.Mixtures.Implements;
namespace VirtualChemistry.Chemistry.Mixtures.Resolver;
/// <summary>
/// get heterogeneous mixture from descriptions
/// </summary>
public static class HeterogeneousMixtureResolver
{
private const string LayersRegex = @"`LAYERS(.*)`%LAYERS";
private static readonly Regex Matcher = new Regex(LayersRegex);
/// <summary>
/// split different homogeneous mixtures
/// </summary>
public const string LayerSplit = "<LayerSp>";
/// <summary>
///
/// </summary>
/// <param name="dumpString"></param>
/// <returns></returns>
public static HeterogeneousMixture Resolve(string dumpString)
{
HeterogeneousMixture res = new HeterogeneousMixture();
string layers = Matcher.Match(dumpString).Result("$1");
foreach (string layerString in layers.Split(LayerSplit))
res.AddLayer(HomogeneousMixtureResolver.Resolve(layerString), false);
return res;
}
}

View File

@@ -0,0 +1,45 @@
using System.Text.RegularExpressions;
using Skeleton.Utils;
using VirtualChemistry.Chemistry.Compounds.Resolver;
using VirtualChemistry.Chemistry.Mixtures.Implements;
namespace VirtualChemistry.Chemistry.Mixtures.Resolver;
/// <summary>
/// get homogeneous mixture from description
/// </summary>
public static class HomogeneousMixtureResolver
{
private const string EnvironmentRegex = @"`ENV(.*)`%ENV";
private const string CompoundsRegex = @"`COMPS(.*)`%COMPS";
private const string MatchString = EnvironmentRegex + CompoundsRegex;
private static readonly Regex Matcher = new Regex(MatchString);
private const string VolumeRegex = @"\?V\(([0-9,]+)\)";
private const string EnergyRegex = @"\?E\(([0-9,]+)\)";
private const string EnvMatchString = VolumeRegex + EnergyRegex;
private static readonly Regex EnvMatcher = new Regex(EnvMatchString);
/// <summary>
/// split different compounds
/// </summary>
public const string CompoundsSplit = "<CompSp>";
/// <summary>
///
/// </summary>
/// <param name="dumpString"></param>
/// <returns></returns>
public static HomogeneousMixture Resolve(string dumpString)
{
Match result = Matcher.Match(dumpString);
HomogeneousMixture res = new HomogeneousMixture();
string envString = result.Result("$1");
Match envRes = EnvMatcher.Match(envString);
double volume = envRes.Result("$1").ByteStringToDouble();
double energy = envRes.Result("$2").ByteStringToDouble();
foreach (string compoundString in result.Result("$2").Split(CompoundsSplit))
res.AddCompound(CompoundResolver.Resolve(compoundString));
res.Volume = volume;
res.Energy = energy;
return res;
}
}