m4
This commit is contained in:
26
src/Chemistry/Atoms/Implements/AAtom.cs
Normal file
26
src/Chemistry/Atoms/Implements/AAtom.cs
Normal 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;
|
||||
}
|
||||
386
src/Chemistry/Atoms/Implements/BaseAtom.cs
Normal file
386
src/Chemistry/Atoms/Implements/BaseAtom.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
27
src/Chemistry/Atoms/Implements/CxAtom.cs
Normal file
27
src/Chemistry/Atoms/Implements/CxAtom.cs
Normal 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;
|
||||
}
|
||||
27
src/Chemistry/Atoms/Implements/DAtom.cs
Normal file
27
src/Chemistry/Atoms/Implements/DAtom.cs
Normal 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;
|
||||
}
|
||||
26
src/Chemistry/Atoms/Implements/EAtom.cs
Normal file
26
src/Chemistry/Atoms/Implements/EAtom.cs
Normal 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;
|
||||
}
|
||||
26
src/Chemistry/Atoms/Implements/EsAtom.cs
Normal file
26
src/Chemistry/Atoms/Implements/EsAtom.cs
Normal 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;
|
||||
}
|
||||
27
src/Chemistry/Atoms/Implements/KAtom.cs
Normal file
27
src/Chemistry/Atoms/Implements/KAtom.cs
Normal 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;
|
||||
}
|
||||
27
src/Chemistry/Atoms/Implements/MAtom.cs
Normal file
27
src/Chemistry/Atoms/Implements/MAtom.cs
Normal 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;
|
||||
}
|
||||
30
src/Chemistry/Atoms/Implements/NullAtom.cs
Normal file
30
src/Chemistry/Atoms/Implements/NullAtom.cs
Normal 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();
|
||||
}
|
||||
27
src/Chemistry/Atoms/Implements/PAtom.cs
Normal file
27
src/Chemistry/Atoms/Implements/PAtom.cs
Normal 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;
|
||||
}
|
||||
26
src/Chemistry/Atoms/Implements/QAtom.cs
Normal file
26
src/Chemistry/Atoms/Implements/QAtom.cs
Normal 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;
|
||||
}
|
||||
26
src/Chemistry/Atoms/Implements/RAtom.cs
Normal file
26
src/Chemistry/Atoms/Implements/RAtom.cs
Normal 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;
|
||||
}
|
||||
26
src/Chemistry/Atoms/Implements/SoAtom.cs
Normal file
26
src/Chemistry/Atoms/Implements/SoAtom.cs
Normal 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;
|
||||
}
|
||||
27
src/Chemistry/Atoms/Implements/UAtom.cs
Normal file
27
src/Chemistry/Atoms/Implements/UAtom.cs
Normal 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;
|
||||
}
|
||||
27
src/Chemistry/Atoms/Implements/UeAtom.cs
Normal file
27
src/Chemistry/Atoms/Implements/UeAtom.cs
Normal 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;
|
||||
}
|
||||
26
src/Chemistry/Atoms/Implements/VAtom.cs
Normal file
26
src/Chemistry/Atoms/Implements/VAtom.cs
Normal 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;
|
||||
}
|
||||
27
src/Chemistry/Atoms/Implements/ViAtom.cs
Normal file
27
src/Chemistry/Atoms/Implements/ViAtom.cs
Normal 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;
|
||||
}
|
||||
72
src/Chemistry/Atoms/Resolver/AtomResolver.cs
Normal file
72
src/Chemistry/Atoms/Resolver/AtomResolver.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
318
src/Chemistry/Bonds/Implements/BaseBond.cs
Normal file
318
src/Chemistry/Bonds/Implements/BaseBond.cs
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/Chemistry/Bonds/Implements/DBond.cs
Normal file
23
src/Chemistry/Bonds/Implements/DBond.cs
Normal 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;
|
||||
}
|
||||
24
src/Chemistry/Bonds/Implements/HBond.cs
Normal file
24
src/Chemistry/Bonds/Implements/HBond.cs
Normal 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;
|
||||
}
|
||||
25
src/Chemistry/Bonds/Implements/MBond.cs
Normal file
25
src/Chemistry/Bonds/Implements/MBond.cs
Normal 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;
|
||||
|
||||
}
|
||||
27
src/Chemistry/Bonds/Implements/NullBond.cs
Normal file
27
src/Chemistry/Bonds/Implements/NullBond.cs
Normal 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();
|
||||
}
|
||||
24
src/Chemistry/Bonds/Implements/PBond.cs
Normal file
24
src/Chemistry/Bonds/Implements/PBond.cs
Normal 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;
|
||||
}
|
||||
25
src/Chemistry/Bonds/Implements/QBond.cs
Normal file
25
src/Chemistry/Bonds/Implements/QBond.cs
Normal 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;
|
||||
|
||||
}
|
||||
24
src/Chemistry/Bonds/Implements/SBond.cs
Normal file
24
src/Chemistry/Bonds/Implements/SBond.cs
Normal 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;
|
||||
}
|
||||
24
src/Chemistry/Bonds/Implements/YBond.cs
Normal file
24
src/Chemistry/Bonds/Implements/YBond.cs
Normal 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;
|
||||
}
|
||||
53
src/Chemistry/Bonds/Resolver/BondResolver.cs
Normal file
53
src/Chemistry/Bonds/Resolver/BondResolver.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
477
src/Chemistry/Compounds/Implements/Compound.cs
Normal file
477
src/Chemistry/Compounds/Implements/Compound.cs
Normal 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; }
|
||||
}
|
||||
111
src/Chemistry/Compounds/Resolver/CompoundResolver.cs
Normal file
111
src/Chemistry/Compounds/Resolver/CompoundResolver.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
27
src/Chemistry/Containers/IChemicalContainer.cs
Normal file
27
src/Chemistry/Containers/IChemicalContainer.cs
Normal 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; }
|
||||
}
|
||||
29
src/Chemistry/Containers/NullContainer.cs
Normal file
29
src/Chemistry/Containers/NullContainer.cs
Normal 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; }
|
||||
}
|
||||
12
src/Chemistry/Environments/Implements/Environment.cs
Normal file
12
src/Chemistry/Environments/Implements/Environment.cs
Normal 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; }
|
||||
}
|
||||
158
src/Chemistry/Mixtures/Implements/HeterogeneousMixture.cs
Normal file
158
src/Chemistry/Mixtures/Implements/HeterogeneousMixture.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
772
src/Chemistry/Mixtures/Implements/HomogeneousMixture.cs
Normal file
772
src/Chemistry/Mixtures/Implements/HomogeneousMixture.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user