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

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

13
VirtualChemistry.csproj Normal file
View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\RiderProjects\Skeleton\Skeleton.csproj" />
</ItemGroup>
</Project>

27
VirtualChemistry.sln Normal file
View File

@@ -0,0 +1,27 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualChemistry", "VirtualChemistry.csproj", "{36979A00-F434-4001-A80E-ECBF92A0AB5E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Skeleton", "..\RiderProjects\Skeleton\Skeleton.csproj", "{CB0ED85F-CAC0-4B53-96A8-16048A928890}"
EndProject
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{36979A00-F434-4001-A80E-ECBF92A0AB5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36979A00-F434-4001-A80E-ECBF92A0AB5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36979A00-F434-4001-A80E-ECBF92A0AB5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36979A00-F434-4001-A80E-ECBF92A0AB5E}.Release|Any CPU.Build.0 = Release|Any CPU
{917762E5-D59D-4724-8F1A-73F739573E99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{917762E5-D59D-4724-8F1A-73F739573E99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{917762E5-D59D-4724-8F1A-73F739573E99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{917762E5-D59D-4724-8F1A-73F739573E99}.Release|Any CPU.Build.0 = Release|Any CPU
{CB0ED85F-CAC0-4B53-96A8-16048A928890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB0ED85F-CAC0-4B53-96A8-16048A928890}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB0ED85F-CAC0-4B53-96A8-16048A928890}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB0ED85F-CAC0-4B53-96A8-16048A928890}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

7
global.json Normal file
View File

@@ -0,0 +1,7 @@
{
"sdk": {
"version": "6.0.0",
"rollForward": "latestMinor",
"allowPrerelease": false
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

103
src/Constants/CachedKeys.cs Normal file
View File

@@ -0,0 +1,103 @@
namespace VirtualChemistry.Constants;
/// <summary>
/// keys for tensors
/// </summary>
public static class CachedKeys
{
/// <summary>
///
/// </summary>
public const string StateMatrix = $"{TypePrefix.SU3}_StateMatrix";
/// <summary>
///
/// </summary>
public const string LogStateMatrix = $"{TypePrefix.LieSU3}_LogStateMatrix";
/// <summary>
///
/// </summary>
public const string StructureMatrix = $"{TypePrefix.SU3}_StructureMatrix";
/// <summary>
///
/// </summary>
public const string LogConnectionMatrix = $"{TypePrefix.LieSU3}_LogConnectionMatrix";
/// <summary>
///
/// </summary>
public const string EnergyDistributionFactor = $"{TypePrefix.Complex}_EnergyDistributionFactor";
/// <summary>
///
/// </summary>
public const string HeatConductivity = $"{TypePrefix.Double}_HeatConductivity";
/// <summary>
///
/// </summary>
public const string FreeDensity = $"{TypePrefix.Double}_FreeDensity";
/// <summary>
///
/// </summary>
public const string CompressionStiffness = $"{TypePrefix.Double}_CompressionStiffness";
/// <summary>
///
/// </summary>
public const string CompressionElasticity = $"{TypePrefix.Double}_CompressionElasticity";
/// <summary>
///
/// </summary>
public const string CompressionBias = $"{TypePrefix.Double}_CompressionBias";
/// <summary>
///
/// </summary>
public const string BondInformationMatrix = $"{TypePrefix.SU3}_BondInformationMatrix";
/// <summary>
///
/// </summary>
public const string LogEigenStateMatrix = $"{TypePrefix.LieSU3}_LogEigenStateMatrix";
/// <summary>
///
/// </summary>
public const string LogKernelMatrix = $"{TypePrefix.LieSU3}_LogKernelMatrix";
/// <summary>
///
/// </summary>
public const string HalfBondInformation = $"{TypePrefix.LieSU3}_HalfBondInformation";
}
/// <summary>
/// tensor type info
/// </summary>
public static class TypePrefix
{
/// <summary>
/// real
/// </summary>
public const string Double = "D";
/// <summary>
/// complex
/// </summary>
public const string Complex = "C";
/// <summary>
/// c3
/// </summary>
public const string C3 = "C3";
/// <summary>
/// c33
/// </summary>
public const string C33 = "C33";
/// <summary>
/// u3
/// </summary>
public const string U3 = "U3";
/// <summary>
/// su3
/// </summary>
public const string SU3 = "SU3";
/// <summary>
/// lie u3
/// </summary>
public const string LieU3 = "LieU3";
/// <summary>
/// lie su3
/// </summary>
public const string LieSU3 = "LieSU3";
}

View File

@@ -0,0 +1,653 @@
using System.Numerics;
using Skeleton.Constants;
using VirtualChemistry.Utils.Helpers;
namespace VirtualChemistry.Constants;
/// <summary>
/// chemistry related constants
/// </summary>
public static class ChemistryConstant
{
private static readonly Complex I = Complex.ImaginaryOne;
/// <summary>
/// volume of a single atom
/// </summary>
public static readonly double AtomVolume = Math.Exp(-2 * Math.PI);
/// <summary>
/// to calculate edv for atom
/// </summary>
public static readonly C3 AtomEnergyDistributionVector = new C3
(
Complex.Exp(Math.PI * I / 4d),
Complex.Exp(Math.PI * I * 11d / 12d),
Complex.Exp(Math.PI * I * 19d / 12d)
);
/// <summary>
/// to calculate edv for bond
/// </summary>
public static readonly C3 BondEnergyDistributionVector = new C3
(
Complex.Exp(Math.PI * I * 5d / 4d),
Complex.Exp(Math.PI * 23d / 12d),
Complex.Exp(Math.PI * I * 7d / 12d)
);
/// <summary>
/// to calculate edv from atom
/// </summary>
public static readonly DiagR3 AtomEnergyDistributionSpectrum = new DiagR3(1d / 4d, 11d / 12d, 19d / 12d);
/// <summary>
/// to calculate edv for bond
/// </summary>
public static readonly DiagR3 BondEnergyDistributionSpectrum = new DiagR3(5d / 4d, 23d / 12d, 7d / 12d);
/// <summary>
/// to calculate energy conductivity
/// </summary>
public static readonly DiagR3 EnergyConductivitySpectrum = new DiagR3(2d/15d, 7d/15d, 11d/15d);
/// <summary>
/// all bond types
/// </summary>
public static class BondTypes
{
/// <summary>
/// type m
/// </summary>
public const string M = "m";
/// <summary>
/// type s
/// </summary>
public const string S = "s";
/// <summary>
/// type d
/// </summary>
public const string D = "d";
/// <summary>
/// type y
/// </summary>
public const string Y = "y";
/// <summary>
/// type q
/// </summary>
public const string Q = "q";
/// <summary>
/// type p
/// </summary>
public const string P = "p";
/// <summary>
/// type h
/// </summary>
public const string H = "h";
/// <summary>
/// all types
/// </summary>
public static readonly string[] All = new[] { M, S, D, Y, Q, P, H };
}
/// <summary>
/// all atom types
/// </summary>
public static class Elements
{
/// <summary>
/// atom q
/// </summary>
public const string Q = "Q";
/// <summary>
/// atom r
/// </summary>
public const string R = "R";
/// <summary>
/// atom es
/// </summary>
public const string Es = "Es";
/// <summary>
/// atom d
/// </summary>
public const string D = "D";
/// <summary>
/// atom ue
/// </summary>
public const string Ue = "Ue";
/// <summary>
/// atom m
/// </summary>
public const string M = "M";
/// <summary>
/// atom k
/// </summary>
public const string K = "K";
/// <summary>
/// atom p
/// </summary>
public const string P = "P";
/// <summary>
/// atom so
/// </summary>
public const string So = "So";
/// <summary>
/// atom e
/// </summary>
public const string E = "E";
/// <summary>
/// atom u
/// </summary>
public const string U = "U";
/// <summary>
/// atom a
/// </summary>
public const string A = "A";
/// <summary>
/// atom cx
/// </summary>
public const string Cx = "Cx";
/// <summary>
/// atom v
/// </summary>
public const string V = "V";
/// <summary>
/// atom vi
/// </summary>
public const string Vi = "Vi";
}
private static double AtomicMass(int atomicNumber) =>
Math.Tan(ChemistryHelper.AtomHeightOrder(atomicNumber) * Math.PI / 2d);
private static SU3 AtomEigenState(int atomicNumber)
{
SU3 dam = ChemistryHelper.AtomAdjointStateMatrix(atomicNumber);
return dam.ConjugateOn(ChemistryHelper.AtomKernel(atomicNumber));
}
/// <summary>
/// adjoint matrices for atom
/// </summary>
public static class AtomAdjoints
{
/// <summary>
/// for q
/// </summary>
public static readonly SU3 AtomAdjointStateQ = ChemistryHelper.AtomAdjointStateMatrix(1);
/// <summary>
/// for r
/// </summary>
public static readonly SU3 AtomAdjointStateR = ChemistryHelper.AtomAdjointStateMatrix(2);
/// <summary>
/// for es
/// </summary>
public static readonly SU3 AtomAdjointStateEs = ChemistryHelper.AtomAdjointStateMatrix(3);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateD = ChemistryHelper.AtomAdjointStateMatrix(4);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateUe = ChemistryHelper.AtomAdjointStateMatrix(5);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateM = ChemistryHelper.AtomAdjointStateMatrix(6);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateK = ChemistryHelper.AtomAdjointStateMatrix(7);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateP = ChemistryHelper.AtomAdjointStateMatrix(8);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateSo = ChemistryHelper.AtomAdjointStateMatrix(9);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateE = ChemistryHelper.AtomAdjointStateMatrix(10);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateU = ChemistryHelper.AtomAdjointStateMatrix(11);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateA = ChemistryHelper.AtomAdjointStateMatrix(12);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateCx = ChemistryHelper.AtomAdjointStateMatrix(13);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateV = ChemistryHelper.AtomAdjointStateMatrix(14);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointStateVi = ChemistryHelper.AtomAdjointStateMatrix(15);
}
/// <summary>
///
/// </summary>
public static class AtomKernels
{
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateQ = ChemistryHelper.AtomKernel(1);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateR = ChemistryHelper.AtomKernel(2);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateEs = ChemistryHelper.AtomKernel(3);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateD = ChemistryHelper.AtomKernel(4);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateUe = ChemistryHelper.AtomKernel(5);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateM = ChemistryHelper.AtomKernel(6);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateK = ChemistryHelper.AtomKernel(7);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateP = ChemistryHelper.AtomKernel(8);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateSo = ChemistryHelper.AtomKernel(9);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateE = ChemistryHelper.AtomKernel(10);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateU = ChemistryHelper.AtomKernel(11);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateA = ChemistryHelper.AtomKernel(12);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateCx = ChemistryHelper.AtomKernel(13);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateV = ChemistryHelper.AtomKernel(14);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomKernelStateVi = ChemistryHelper.AtomKernel(15);
}
/// <summary>
/// atom eigen state matrices
/// </summary>
public static class AtomEigenStates
{
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateQ = AtomEigenState(1);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateR = AtomEigenState(2);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateEs = AtomEigenState(3);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateD = AtomEigenState(4);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateUe = AtomEigenState(5);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateM = AtomEigenState(6);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateK = AtomEigenState(7);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateP = AtomEigenState(8);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateSo = AtomEigenState(9);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateE = AtomEigenState(10);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateU = AtomEigenState(11);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateA = AtomEigenState(12);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateCx = AtomEigenState(13);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateV = AtomEigenState(14);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomEigenStateVi = AtomEigenState(15);
}
/// <summary>
/// atomic masses for atoms
/// </summary>
public static class AtomicMasses
{
/// <summary>
///
/// </summary>
public static readonly double AtomicMassQ = AtomicMass(1);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassR = AtomicMass(2);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassEs = AtomicMass(3);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassD = AtomicMass(4);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassUe = AtomicMass(5);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassM = AtomicMass(6);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassK = AtomicMass(7);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassP = AtomicMass(8);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassSo = AtomicMass(9);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassE = AtomicMass(10);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassU = AtomicMass(11);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassA = AtomicMass(12);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassCx = AtomicMass(13);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassV = AtomicMass(14);
/// <summary>
///
/// </summary>
public static readonly double AtomicMassVi = AtomicMass(15);
}
private static SU3 BondEigenState(int bondNumber)
{
SU3 dam = ChemistryHelper.BondAdjointStateMatrix(bondNumber);
return dam.ConjugateOn(ChemistryHelper.BondKernel(bondNumber));
}
/// <summary>
/// kernel matrices for bonds
/// </summary>
public static class BondKernels
{
/// <summary>
///
/// </summary>
public static readonly SU3 BondKernelM = ChemistryHelper.BondKernel(1);
/// <summary>
///
/// </summary>
public static readonly SU3 BondKernelS = ChemistryHelper.BondKernel(2);
/// <summary>
///
/// </summary>
public static readonly SU3 BondKernelD = ChemistryHelper.BondKernel(3);
/// <summary>
///
/// </summary>
public static readonly SU3 BondKernelY = ChemistryHelper.BondKernel(4);
/// <summary>
///
/// </summary>
public static readonly SU3 BondKernelQ = ChemistryHelper.BondKernel(5);
/// <summary>
///
/// </summary>
public static readonly SU3 BondKernelP = ChemistryHelper.BondKernel(6);
/// <summary>
///
/// </summary>
public static readonly SU3 BondKernelH = ChemistryHelper.BondKernel(7);
}
/// <summary>
/// adjoint matrices for bond
/// </summary>
public static class BondAdjoints
{
/// <summary>
///
/// </summary>
public static readonly SU3 BondAdjointM = ChemistryHelper.BondAdjointStateMatrix(1);
/// <summary>
///
/// </summary>
public static readonly SU3 BondAdjointS = ChemistryHelper.BondAdjointStateMatrix(2);
/// <summary>
///
/// </summary>
public static readonly SU3 BondAdjointD = ChemistryHelper.BondAdjointStateMatrix(3);
/// <summary>
///
/// </summary>
public static readonly SU3 BondAdjointY = ChemistryHelper.BondAdjointStateMatrix(4);
/// <summary>
///
/// </summary>
public static readonly SU3 BondAdjointQ = ChemistryHelper.BondAdjointStateMatrix(5);
/// <summary>
///
/// </summary>
public static readonly SU3 BondAdjointP = ChemistryHelper.BondAdjointStateMatrix(6);
/// <summary>
///
/// </summary>
public static readonly SU3 BondAdjointH = ChemistryHelper.BondAdjointStateMatrix(7);
}
/// <summary>
/// eigen state matrices for bond
/// </summary>
public static class BondEigenStates
{
/// <summary>
///
/// </summary>
public static readonly SU3 BondEigenStateM = BondEigenState(1);
/// <summary>
///
/// </summary>
public static readonly SU3 BondEigenStateS = BondEigenState(2);
/// <summary>
///
/// </summary>
public static readonly SU3 BondEigenStateD = BondEigenState(3);
/// <summary>
///
/// </summary>
public static readonly SU3 BondEigenStateY = BondEigenState(4);
/// <summary>
///
/// </summary>
public static readonly SU3 BondEigenStateQ = BondEigenState(5);
/// <summary>
///
/// </summary>
public static readonly SU3 BondEigenStateP = BondEigenState(6);
/// <summary>
///
/// </summary>
public static readonly SU3 BondEigenStateH = BondEigenState(7);
}
/// <summary>
/// max bond numbers for specific bond number
/// </summary>
/// <param name="bondNumber"></param>
/// <returns></returns>
public static int BondMaxNumbers(int bondNumber) => bondNumber switch
{
1 => 1,
2 => 2,
3 => 1,
4 => 2,
5 => 2,
6 => 1,
7 => 2,
_ => -1
};
/// <summary>
/// filters to calculate the color of mixtures
/// </summary>
public static class OpticalFilter
{
/// <summary>
/// to calculate redness
/// </summary>
public static readonly U3 RedFilter = new LieU3
(
I,0, -1,
0, I, 0,
1, 0, -I
).Exp();
/// <summary>
/// to calculate greenness
/// </summary>
public static readonly U3 GreenFilter = new LieU3
(
0, -I, 0,
-I, 0, -1,
0, 1, 0
).Exp();
/// <summary>
/// to calculate blueness
/// </summary>
public static readonly U3 BlueFilter = new LieU3
(
0, 0, -I,
0, 0, -1,
-I, 1, 0
).Exp();
/// <summary>
/// to calculate alpha channel
/// </summary>
public static readonly U3 OpacityFilter = new LieU3(
I, -I, -I,
-I, I, -1,
-I, 1, -I
).Exp();
/// <summary>
/// red
/// </summary>
public static readonly H3 RedDefinite = RedFilter.ConjugateOn(AlgebraConstant.UniformSpectrum3);
/// <summary>
/// green
/// </summary>
public static readonly H3 GreenDefinite = GreenFilter.ConjugateOn(AlgebraConstant.UniformSpectrum3);
/// <summary>
/// blue
/// </summary>
public static readonly H3 BlueDefinite = BlueFilter.ConjugateOn(AlgebraConstant.UniformSpectrum3);
/// <summary>
/// alpha
/// </summary>
public static readonly H3 OpacityDefinite = OpacityFilter.ConjugateOn(new DiagR3(0.05d, 0.74d, 1d));
}
/// <summary>
/// all elements
/// </summary>
public static readonly string[] ElementSymbols =
{
"Q", "R", "Es", "D", "Ue",
"M", "K", "P", "So", "E",
"U", "A", "Cx", "V", "Vi"
};
/// <summary>
/// x
/// </summary>
public static class CommonResources
{
/// <summary>
/// x
/// </summary>
public const string Letroline = "res://Data/Chemicals/HighEnergyMixtureLetroline.btx";
}
/// <summary>
/// Used to measure Cayley value of homogeneous mixture
/// </summary>
public static readonly C3 CayleyMeasure = new (1 - I, I, -1 + I);
/// <summary>
/// Used to measure Euclid value of homogeneous mixture
/// </summary>
public static readonly C3 EuclidMeasure = new(1, I, -I);
}

View File

@@ -0,0 +1,54 @@
using Skeleton.Utils.Helpers;
namespace VirtualChemistry.DataStructure.Caches;
/// <summary>
/// cache to store a specific type of data
/// </summary>
/// <typeparam name="TValue"></typeparam>
public class Cache<TValue> : Dictionary<string, TValue>, ICache
{
/// <inheritdoc />
public Cache()
{
UpdateRequest = new HashSet<string>();
}
/// <summary>
/// indexer
/// </summary>
/// <param name="key"></param>
/// <param name="getter">re calculate by getter if key is expired of no value stored in the specified key</param>
public TValue this[string key, Func<TValue> getter]
{
get
{
if(ValueOutdated(key))
{
UpdateRequest.Remove(key);
return this[key] = getter();
}
return this[key];
}
}
/// <inheritdoc />
public void DeleteCache()
{
Keys.ForEach(x => Remove(x));
UpdateRequest = new HashSet<string>();
}
/// <inheritdoc />
public void DeleteCache(string key) => Remove(key);
private HashSet<string> UpdateRequest { get; set; }
private bool ValueOutdated(string key) => !ContainsKey(key) || UpdateRequest.Contains(key);
/// <inheritdoc />
public void Expire(string key) => UpdateRequest.Add(key);
/// <inheritdoc />
public void Expire(IEnumerable<string> keys) => keys.ForEach(Expire);
}

View File

@@ -0,0 +1,156 @@
using System.Numerics;
using Skeleton.Utils.Helpers;
namespace VirtualChemistry.DataStructure.Caches;
/// <summary>
/// a general propose cache to store many type of tensors
/// </summary>
public class GeneralCache
{
private Cache<C3> C3Cache { get; set; } = new();
private Cache<C33> C33Cache { get; set; } = new();
private Cache<Complex> ComplexCache { get; set; } = new();
private Cache<double> DoubleCache { get; set; } = new();
private Cache<U3> U3Cache { get; set; } = new();
private Cache<SU3> SU3Cache { get; set; } = new();
private Cache<LieU3> LieU3Cache { get; set; } = new();
private Cache<LieSU3> LieSU3Cache { get; set; } = new();
private static T Identity<T>(T x) => x;
private Func<T, T> RegisterOnExpire<T>(string key, Action? e)
{
if (e != null && !OnExpire.ContainsKey(key))
OnExpire[key] = e;
return Identity<T>;
}
/// <summary>
/// C3 tensor getter
/// </summary>
/// <param name="key"></param>
/// <param name="getter"></param>
/// <param name="onExpire">a function to expire other keys if this key is expired</param>
public C3 this[string key, Func<C3> getter, Action? onExpire = null] =>
RegisterOnExpire<C3>(key, onExpire)(C3Cache[key, getter]);
/// <summary>
/// C33 tensor getter
/// </summary>
/// <param name="key"></param>
/// <param name="getter"></param>
/// <param name="onExpire"></param>
public C33 this[string key, Func<C33> getter, Action? onExpire = null] =>
RegisterOnExpire<C33>(key, onExpire)(C33Cache[key, getter]);
/// <summary>
/// complex getter
/// </summary>
/// <param name="key"></param>
/// <param name="getter"></param>
/// <param name="onExpire"></param>
public Complex this[string key, Func<Complex> getter, Action? onExpire = null] =>
RegisterOnExpire<Complex>(key, onExpire)(ComplexCache[key, getter]);
/// <summary>
/// real getter
/// </summary>
/// <param name="key"></param>
/// <param name="getter"></param>
/// <param name="onExpire"></param>
public double this[string key, Func<double> getter, Action? onExpire = null] =>
RegisterOnExpire<double>(key, onExpire)(DoubleCache[key, getter]);
/// <summary>
/// U3 getter
/// </summary>
/// <param name="key"></param>
/// <param name="getter"></param>
/// <param name="onExpire"></param>
public U3 this[string key, Func<U3> getter, Action? onExpire = null] =>
RegisterOnExpire<U3>(key, onExpire)(U3Cache[key, getter]);
/// <summary>
/// SU3 getter
/// </summary>
/// <param name="key"></param>
/// <param name="getter"></param>
/// <param name="onExpire"></param>
public SU3 this[string key, Func<SU3> getter, Action? onExpire = null] =>
RegisterOnExpire<SU3>(key, onExpire)(SU3Cache[key, getter]);
/// <summary>
/// LieU3 getter
/// </summary>
/// <param name="key"></param>
/// <param name="getter"></param>
/// <param name="onExpire"></param>
public LieU3 this[string key, Func<LieU3> getter, Action? onExpire = null] =>
RegisterOnExpire<LieU3>(key, onExpire)(LieU3Cache[key, getter]);
/// <summary>
/// LieSU3 getter
/// </summary>
/// <param name="key"></param>
/// <param name="getter"></param>
/// <param name="onExpire"></param>
public LieSU3 this[string key, Func<LieSU3> getter, Action? onExpire = null] =>
RegisterOnExpire<LieSU3>(key, onExpire)(LieSU3Cache[key, getter]);
/// <summary>
/// general propose getter
/// </summary>
/// <param name="key"></param>
/// <exception cref="Exception"></exception>
public ICache this[string key] => key.Split('_')[0] switch
{
"D" => DoubleCache,
"C" => ComplexCache,
"C3" => C3Cache,
"C33" => C33Cache,
"U3" => U3Cache,
"SU3" => SU3Cache,
"LieU3" => LieU3Cache,
"LieSU3" => LieSU3Cache,
_ => throw new Exception()
};
/// <summary>
/// general expire
/// </summary>
/// <param name="key"></param>
public void Expire(string key)
{
if (OnExpire.ContainsKey(key))
OnExpire[key]();
this[key].Expire(key);
}
/// <summary>
/// general expire
/// </summary>
/// <param name="keys"></param>
public void Expire(IEnumerable<string> keys) => keys.ForEach(Expire);
/// <summary>
/// general delete cache
/// </summary>
/// <param name="key"></param>
public void DeleteCache(string key) => this[key].DeleteCache(key);
/// <summary>
/// trigger the action when key is expired
/// </summary>
public Dictionary<string, Action> OnExpire { get; set; } = new();
/// <summary>
/// get raw real(constant)
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public double GetRaw(string key) => DoubleCache.GetValueOrDefault(key);
/// <summary>
/// init a constant real
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void SetRaw(string key, double value) => DoubleCache[key] = value;
}

View File

@@ -0,0 +1,27 @@
namespace VirtualChemistry.DataStructure.Caches;
/// <summary>
/// interface for cache
/// </summary>
public interface ICache
{
/// <summary>
/// delete all cache
/// </summary>
public void DeleteCache();
/// <summary>
/// delete for a specific key
/// </summary>
/// <param name="key"></param>
public void DeleteCache(string key);
/// <summary>
/// expire a key, the value need to be re calculated from getter
/// </summary>
/// <param name="key"></param>
public void Expire(string key);
/// <summary>
/// expire a set of keys
/// </summary>
/// <param name="keys"></param>
public void Expire(IEnumerable<string> keys);
}

View File

@@ -0,0 +1,33 @@
using Skeleton.DataStructure.Packs;
using VirtualChemistry.Chemistry.Bonds.Implements;
namespace VirtualChemistry.DataStructure.Packs;
using BondGroup = HashSet<BaseBond>;
/// <inheritdoc />
public class BondGroups : Pack4<BondGroup, BondGroup, BondGroup, BondGroup>
{
/// <summary>
///
/// </summary>
public BondGroup Group1 => Item1;
/// <summary>
///
/// </summary>
public BondGroup Group2 => Item2;
/// <summary>
///
/// </summary>
public BondGroup Group3 => Item3;
/// <summary>
///
/// </summary>
public BondGroup Group4 => Item4;
/// <inheritdoc />
public BondGroups(BondGroup g1, BondGroup g2, BondGroup g3, BondGroup g4) : base(g1, g2, g3, g4)
{
}
}

View File

@@ -0,0 +1,67 @@
using Skeleton.DataStructure.Packs;
using VirtualChemistry.Chemistry.Atoms.Implements;
using VirtualChemistry.Chemistry.Bonds.Implements;
using VirtualChemistry.Chemistry.Compounds.Implements;
namespace VirtualChemistry.DataStructure.Packs;
/// <summary>
/// compound dump map
/// </summary>
public class CompoundDumpMap : Pack3<Dictionary<BaseAtom, string>, Dictionary<BaseBond, string>, string>
{
/// <summary>
/// atom map
/// </summary>
public Dictionary<BaseAtom, string> AtomMap => Item1;
/// <summary>
/// bond map
/// </summary>
public Dictionary<BaseBond, string> BondMap => Item2;
/// <summary>
/// save string
/// </summary>
public string DumpString => Item3;
/// <summary>
/// constructor
/// </summary>
/// <param name="atomMap"></param>
/// <param name="bondMap"></param>
/// <param name="dumpString"></param>
public CompoundDumpMap(Dictionary<BaseAtom, string> atomMap, Dictionary<BaseBond, string> bondMap, string dumpString) :
base(atomMap, bondMap, dumpString)
{
}
}
/// <summary>
/// resolve map for compound
/// </summary>
public class CompoundResolveMap : Pack3<Dictionary<string, BaseAtom>, Dictionary<string, BaseBond>, Compound>
{
/// <summary>
/// atom map
/// </summary>
public Dictionary<string, BaseAtom> AtomMap => Item1;
/// <summary>
/// bond map
/// </summary>
public Dictionary<string, BaseBond> BondMap => Item2;
/// <summary>
/// created compound
/// </summary>
public Compound ResolvedCompound => Item3;
/// <summary>
/// constructor
/// </summary>
/// <param name="atomMap"></param>
/// <param name="bondMap"></param>
/// <param name="resolvedCompound"></param>
public CompoundResolveMap(Dictionary<string, BaseAtom> atomMap, Dictionary<string, BaseBond> bondMap,
Compound resolvedCompound) :
base(atomMap, bondMap, resolvedCompound)
{
}
}

View File

@@ -0,0 +1,37 @@
using Skeleton.DataStructure.Packs;
using VirtualChemistry.Chemistry.Atoms.Implements;
using VirtualChemistry.Chemistry.Bonds.Implements;
namespace VirtualChemistry.DataStructure.Packs;
/// <summary>
/// connection info of an atom and a bond
/// </summary>
public class ConnectionInfo : Pack3<BaseBond, BaseBond, BaseAtom>
{
/// <summary>
/// constructor
/// </summary>
/// <param name="bondFrom"></param>
/// <param name="bondTo"></param>
/// <param name="connectedAtom"></param>
public ConnectionInfo(BaseBond bondFrom, BaseBond bondTo, BaseAtom connectedAtom)
{
Item1 = bondFrom;
Item2 = bondTo;
Item3 = connectedAtom;
}
/// <summary>
/// from bond
/// </summary>
public BaseBond BondFrom => Item1;
/// <summary>
/// to bond
/// </summary>
public BaseBond BondTo => Item2;
/// <summary>
/// to atom
/// </summary>
public BaseAtom ConnectedAtom => Item3;
}

View File

@@ -0,0 +1,64 @@
using Skeleton.DataStructure.Packs;
using VirtualChemistry.Chemistry.Atoms.Implements;
using VirtualChemistry.Chemistry.Bonds.Implements;
namespace VirtualChemistry.DataStructure.Packs;
/// <summary>
/// all connections from one atom to another
/// </summary>
public class FullConnectionInfo : Pack3<BaseAtom, HashSet<BaseBond>, BaseAtom>
{
/// <summary>
/// constructor
/// </summary>
/// <param name="bond"></param>
public FullConnectionInfo(BaseBond bond) : base(bond.Atom, new HashSet<BaseBond>() { bond }, bond.ConnectedBond.Atom)
{
}
/// <summary>
/// from atom
/// </summary>
public BaseAtom Atom1 => Item1;
/// <summary>
/// connected bonds
/// </summary>
public HashSet<BaseBond> Bonds => Item2;
/// <summary>
/// bonds of atom 1
/// </summary>
public BaseAtom Atom2 => Item3;
private string OnwRepresentation => $"{Atom1.Element}-[{String.Join('|', Bonds.Select(bond => $"{bond.BondType}-{bond.ConnectedBond.BondType}"))}]-{Atom2.Element}";
private string RevRepresentation => $"{Atom2.Element}-[{String.Join('|', Bonds.Select(bond => $"{bond.ConnectedBond.BondType}-{bond.BondType}"))}]-{Atom1.Element}";
/// <summary>
/// save string
/// </summary>
public string Representation => Atom1.AtomicNumber + Bonds.Sum(bond => bond.BondNumber) >
Atom2.AtomicNumber + Bonds.Sum(bond => bond.ConnectedBond.BondNumber)
? OnwRepresentation
: RevRepresentation;
/// <summary>
/// try to add a bond to bonds
/// </summary>
/// <param name="bond"></param>
/// <returns></returns>
public bool TryAbsorbBond(BaseBond bond)
{
if(bond.Atom == Atom1 && bond.ConnectedBond.Atom == Atom2)
{
Bonds.Add(bond);
return true;
}
if (bond.Atom == Atom2 && bond.ConnectedBond.Atom == Atom1)
{
Bonds.Add(bond.ConnectedBond);
return true;
}
return false;
}
}

42
src/Using.cs Normal file
View File

@@ -0,0 +1,42 @@
global using C2 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.OnField<System.Numerics.Complex>.FVector;
global using C3 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.OnField<System.Numerics.Complex>.FVector;
global using C4 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.OnField<System.Numerics.Complex>.FVector;
global using R2 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.OnField<double>.FVector;
global using R3 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.OnField<double>.FVector;
global using R4 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.OnField<double>.FVector;
global using C22 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.OnField<System.Numerics.Complex>.FMatrix;
global using C33 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.OnField<System.Numerics.Complex>.FMatrix;
global using C44 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.OnField<System.Numerics.Complex>.FMatrix;
global using R22 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.OnField<double>.FMatrix;
global using R33 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.OnField<double>.FMatrix;
global using R44 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.OnField<double>.FMatrix;
global using U2 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.FUnitaryMatrix;
global using U3 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.FUnitaryMatrix;
global using U4 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.FUnitaryMatrix;
global using SU2 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.FSpecialUnitaryMatrix;
global using SU3 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.FSpecialUnitaryMatrix;
global using SU4 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.FSpecialUnitaryMatrix;
global using LieU2 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.FLieUnitaryMatrix;
global using LieU3 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.FLieUnitaryMatrix;
global using LieU4 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.FLieUnitaryMatrix;
global using LieSU2 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.FSpecialLieUnitaryMatrix;
global using LieSU3 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.FSpecialLieUnitaryMatrix;
global using LieSU4 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.FSpecialLieUnitaryMatrix;
global using C2Space = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.OnField<System.Numerics.Complex>.FVectorSpace;
global using C3Space = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.OnField<System.Numerics.Complex>.FVectorSpace;
global using C4Space = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.OnField<System.Numerics.Complex>.FVectorSpace;
global using R2Space = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim2>.OnField<double>.FVectorSpace;
global using R3Space = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.OnField<double>.FVectorSpace;
global using R4Space = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim4>.OnField<double>.FVectorSpace;
global using DiagR3 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.OnField<double>.FDiagonalMatrix;
global using H3 = Skeleton.Algebra.CategoryOf<Skeleton.Algebra.DimensionProviders.IDim3>.FHermitianMatrix;

View File

@@ -0,0 +1,282 @@
using System.Numerics;
namespace VirtualChemistry.Utils.Helpers;
/// <summary>
/// helper functions for chemistry
/// </summary>
public static class ChemistryHelper
{
private static readonly Complex I = Complex.ImaginaryOne;
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static double BondHeightOrder(int n) => Math.Pow(4d / 5d, n) - 1;
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static double BondWeightOrder(int n)
{
double ra = n / 11d;
int det = (int)Math.Floor(ra / 0.5d);
if (det % 2 == 0)
return ra % 0.5d;
return 0.5 - (ra % 0.5d);
}
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex BondHeight(int n) => Complex.Exp(I * Math.PI * BondHeightOrder(n));
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex BondWeight(int n) => Complex.Exp(I * Math.PI * BondWeightOrder(n));
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex BondE1(int n) => BondHeight(n);
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex BondE2(int n) => BondWeight(n);
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex BondE3(int n) => 1 / (BondE1(n)*BondE2(n));
/// <summary>
///
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public static SU3 BondKernel(int p) => new
(
BondE1(p), 0, 0,
0, BondE2(p), 0,
0, 0, BondE3(p)
);
private static readonly double Sqrt13 = Math.Sqrt(13d);
private static readonly double Sqrt7 = Math.Sqrt(7d);
private static readonly double Sqrt3 = Math.Sqrt(3d);
private static readonly double Sqrt2 = Math.Sqrt(2d);
private static readonly double Sqrt21 = Sqrt3 * Sqrt7;
/// <summary>
///
/// </summary>
public static readonly Complex BondAdjointEigen1 = I * Math.Sqrt(0.5d * (5d + Sqrt21));
/// <summary>
///
/// </summary>
public static readonly Complex BondAdjointEigen2 = I * Math.Sqrt(0.5d * (5d - Sqrt21));
/// <summary>
///
/// </summary>
public static readonly C3 BondAdjointEigenVector1 = new C3
(
1d/Sqrt2,
-I/2d,
1/2
);
/// <summary>
///
/// </summary>
public static readonly C3 BondAdjointEigenVector2 = new C3
(
0,
I/Sqrt2,
1d/Sqrt2
);
/// <summary>
///
/// </summary>
public static readonly C3 BondAdjointEigenVector3 = new C3
(
-1d/Sqrt2,
I/Sqrt2,
1d/2d
);
/// <summary>
///
/// </summary>
public static readonly C33 BondAdjointCoMatrix =
new C33(new[] { BondAdjointEigenVector1, BondAdjointEigenVector2, BondAdjointEigenVector3 }, false);
/// <summary>
///
/// </summary>
/// <param name="bondNumber"></param>
/// <returns></returns>
public static SU3 BondAdjointStateMatrix(int bondNumber)
{
double t = Math.Cos(bondNumber * Math.E) + Sqrt3;
Complex a1 = Complex.Exp(t * BondAdjointEigen1);
Complex a2 = Complex.Exp(t * BondAdjointEigen2);
Complex a3 = 1 / (a1 * a2);
C33 expBondAdjointEigenDiagonal = new
(
a1, 0d, 0d,
0d, a2, 0d,
0d, 0d, a3
);
return new SU3(BondAdjointCoMatrix * expBondAdjointEigenDiagonal * BondAdjointCoMatrix.Inv());
}
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static double AtomHeightOrder(int n) => 1 - Math.Pow(6d / 7d, n);
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static double AtomWeightOrder(int n)
{
double ra = n / 7d;
if ((int)Math.Floor(ra / 0.5) % 2 == 0)
return ra % 0.5d;
return 0.5d - (ra % 0.5d);
}
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex AtomHeight(int n) => Complex.Exp(I * Math.PI * AtomHeightOrder(n));
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex AtomWeight(int n) => Complex.Exp(I * Math.PI * AtomWeightOrder(n));
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex AtomE1(int n) => AtomHeight(n);
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex AtomE2(int n) => AtomWeight(n);
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static Complex AtomE3(int n) => 1 / (AtomE1(n) * AtomE2(n));
/// <summary>
///
/// </summary>
/// <param name="atomicNumber"></param>
/// <returns></returns>
public static SU3 AtomKernel(int atomicNumber) => new
(
AtomE1(atomicNumber), 0, 0,
0, AtomE2(atomicNumber), 0,
0, 0, AtomE3(atomicNumber)
);
/// <summary>
///
/// </summary>
public static readonly Complex AtomAdjointEigen1 = I * Complex.Sqrt(0.5 * (5 + Sqrt21));
/// <summary>
///
/// </summary>
public static readonly Complex AtomAdjointEigen2 = I * Complex.Sqrt(0.5 * (5 - Sqrt21));
/// <summary>
///
/// </summary>
public static readonly C3 AtomAdjointEigenVector1 = new C3
(
0d,
-I * (Sqrt2 - 1d) / (Complex.Sqrt(4d - 2d * Sqrt2)),
1d / (Complex.Sqrt(4 - 2 * Sqrt2))
);
/// <summary>
///
/// </summary>
public static readonly C3 AtomAdjointEigenVector2 = new C3
(
1d,
0d,
0d
);
/// <summary>
///
/// </summary>
public static readonly C3 AtomAdjointEigenVector3 = new C3
(
0d,
I * (1d + Sqrt2) / Complex.Sqrt(2d * (2d + Sqrt2)),
1d / Complex.Sqrt(2d * (2d + Sqrt2))
);
/// <summary>
///
/// </summary>
public static readonly SU3 AtomAdjointCoMatrix =
new ( new []{ AtomAdjointEigenVector1, AtomAdjointEigenVector2, AtomAdjointEigenVector3 }, false);
/// <summary>
///
/// </summary>
/// <param name="atomicNumber"></param>
/// <returns></returns>
public static SU3 AtomAdjointStateMatrix(int atomicNumber)
{
double t = Math.Cos(atomicNumber * Math.E) + Sqrt3;
Complex a1 = Complex.Exp(t * AtomAdjointEigen1);
Complex a2 = Complex.Exp(t * AtomAdjointEigen2);
Complex a3 = 1 / (a1 * a2);
SU3 expAtomAdjointEigenDiagonal = new SU3
(
a1, 0, 0,
0, a2 , 0,
0, 0, a3
);
return AtomAdjointCoMatrix.ConjugateOn(expAtomAdjointEigenDiagonal);
}
}