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; /// /// meta bond /// public abstract class BaseBond { /// /// /// 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(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(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(s); LieSU3 f1 = f0 ^ LogState.GetFrom(x); U3 f2 = f1.CayleyPositive(); return f2.Det().Imaginary; } ); } /// /// /// public Compound Compound => Atom.Compound; /// /// /// public HomogeneousMixture HomogeneousMixture => Compound.HomogeneousMixture; /// /// null singleton /// public static readonly BaseBond Null = new NullBond(); /// /// energy hold in this atom /// public double Energy { get; set; } /// /// how energy in the molecular is distributed into this atom /// public CacheItem EnergyDistributionFactor { get; } /// /// the connected bond /// public BaseBond ConnectedBond { get; set; } = Null; /// /// atom that holds this bond /// public BaseAtom Atom { get; set; } = BaseAtom.Null; /// /// type of the bond /// public abstract string BondType { get; } /// /// kernel state matrix of the matrix, won't change as long as bond type is fixed /// public abstract SU3 KernelStateMatrix { get; } /// /// adj state matrix of the bond, won't change as long as bond type fixed /// public abstract SU3 AdjointStateMatrix { get; } /// /// eigen state matrix of bond, won't change as long as bond type fixed /// public abstract SU3 EigenStateMatrix { get; } /// /// log of the kernel state matrix /// never expire /// public CacheItem LogKernel { get; } /// /// skew hermitian matrix that represent the information of bond and its atom /// public CacheItem HalfBondInformation { get; } /// /// special unitary matrix that represent the structure of the bond(its atom, connected bond and atom of connected bond) /// public CacheItem StructureMatrix { get; } /// /// log of connection matrix /// public CacheItem LogConnectionMatrix { get; set; } /// /// a special unitary matrix that represent the state of the bond /// public CacheItem StateMatrix { get; } /// /// log of state matrix /// public CacheItem LogState { get; } /// /// connect with another bond /// /// /// 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; } } /// /// disconnect with connected bond /// 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); } /// /// if the bond is connected /// public bool Connected => ConnectedBond != Null; /// /// bond number, redundant information of bond type /// public abstract int BondNumber { get; } private void StructureChanged() { //Atom.Compound.ResetDistanceCache(); Atom.Compound.CacheInit(); HalfBondInformation.Expire(); StateMatrix.Expire(); LogConnectionMatrix.Expire(); } /// /// 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 /// /// 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); } /// /// 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 /// /// 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); } /// /// how antibonding energy affected by mixture /// public CacheItem AntibondingCatalyzeFactor { get; set; } /// /// hot bonding energy affected by chemical environment /// public CacheItem BondingCatalyzeFactor { get; set; } public double BondingEnergy => EigenBondingEnergy() + BondingCatalyzeFactor.Get; public double AntiBondingEnergy => EigenAntibondingEnergy() + AntibondingCatalyzeFactor.Get; /// /// how to pair bonds /// 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 }; } } }