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
};
}
}
}