예제 #1
0
        private static void CalculateIonicForces(Molecule molecule,
                                                 Dictionary <uint, Vector3D> forceLookup,
                                                 AtomNeighborhoodMap neighborhoodMap)
        {
            var vertexIds = molecule.MoleculeStructure.Vertices.Select(v => v.Id);

            foreach (var vertexId in vertexIds)
            {
                var atom          = molecule.GetAtom(vertexId);
                var charge1       = atom.EffectiveCharge;
                var atom1Position = atom.Position;

                var neighborhood = neighborhoodMap.GetNeighborhood(vertexId);
                foreach (var neighborVertexId in neighborhood)
                {
                    if (neighborVertexId <= vertexId)
                    {
                        continue;
                    }
                    var neighborAtom  = molecule.GetAtom(neighborVertexId);
                    var charge2       = neighborAtom.EffectiveCharge;
                    var r             = atom1Position.VectorTo(neighborAtom.Position);
                    var distance      = r.Magnitude().In(SIPrefix.Pico, Unit.Meter);
                    var chargeProduct = PhysicalConstants.CoulombsConstant.Value
                                        * charge1.Value
                                        * charge2.Value;
                    var ionicForce = -5 * 1e-1 * (chargeProduct / (distance * distance)) * r.Normalize().ToVector3D();

                    forceLookup[vertexId]         += ionicForce;
                    forceLookup[neighborVertexId] += -ionicForce;
                }
            }
        }
예제 #2
0
        public static ForceCalculatorResult CalculateForces(Molecule molecule, AtomNeighborhoodMap neighborhoodMap = null)
        {
            if (!molecule.IsPositioned)
            {
                molecule.PositionAtoms();
            }
            if (neighborhoodMap == null)
            {
                neighborhoodMap = new AtomNeighborhoodMap(molecule);
            }
            var graph = molecule.MoleculeStructure;

            var forceLookup = CalculateBondForces(graph);

            //CalculateIonicForces(molecule, forceLookup, neighborhoodMap);
            CalculateAtomShellRepulsion(molecule, forceLookup, neighborhoodMap);
            var lonePairForceLookup = CalculateLonePairRepulsion(graph, forceLookup);

            if (forceLookup.Values.Any(v => v.X.IsNaN()))
            {
                throw new Exception("Force cannot be 'NaN'");
            }
            if (lonePairForceLookup.Values.Any(v => v.X.IsNaN()))
            {
                throw new Exception("Lone pair repulsion cannot be 'NaN'");
            }
            return(new ForceCalculatorResult(forceLookup, lonePairForceLookup, neighborhoodMap));
        }
예제 #3
0
 public ForceCalculatorResult(Dictionary <uint, Vector3D> forceLookup,
                              Dictionary <Orbital, Vector3D> lonePairForceLookup,
                              AtomNeighborhoodMap neighborhoodMap)
 {
     ForceLookup         = forceLookup;
     LonePairForceLookup = lonePairForceLookup;
     NeighborhoodMap     = neighborhoodMap;
 }
예제 #4
0
        private void RunSimulation(CancellationToken cancellationToken)
        {
            if (!Molecule.IsPositioned)
            {
                Molecule.PositionAtoms();
            }
            var currentAtomPositions = Molecule.MoleculeStructure.Vertices
                                       .ToDictionary(vertex => vertex.Id, vertex => Molecule.GetAtom(vertex.Id).Position);
            var lastNeighborhoodUpdate = 0.To(Unit.Second);
            var atomNeighborhoodMap    = new AtomNeighborhoodMap(Molecule);

            for (var t = 0.To(Unit.Second); t < simulationSettings.SimulationTime; t += simulationSettings.TimeStep)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }
                if (t - lastNeighborhoodUpdate > 400.To(SIPrefix.Femto, Unit.Second))
                {
                    atomNeighborhoodMap.Update();
                }

                var forces = ForceCalculator.CalculateForces(Molecule, atomNeighborhoodMap);
                AddCustomForces(Molecule, t, forces.ForceLookup, customAtomForces);
                ApplyAtomForces(Molecule, t, forces, simulationSettings);
                ApplyLonePairRepulsion(forces);
                // TODO: Redistribute electrons (either here or as a step after molecule is fully connected
                //WriteDebug(molecule);

                var newAtomPositions = Molecule.MoleculeStructure.Vertices
                                       .ToDictionary(vertex => vertex.Id, vertex => Molecule.GetAtom(vertex.Id).Position);
                if (simulationSettings.StopSimulationWhenAtomAtRest && t > simulationSettings.ForceRampUpPeriod)
                {
                    var maximumPositionChange = currentAtomPositions.Keys
                                                .Select(atom => currentAtomPositions[atom].DistanceTo(newAtomPositions[atom]).In(SIPrefix.Pico, Unit.Meter))
                                                .Max();
                    if (maximumPositionChange / simulationSettings.TimeStep.Value < simulationSettings.MovementDetectionThreshold.Value)
                    {
                        break;
                    }
                }
                currentAtomPositions = newAtomPositions;
                OnTimestepCompleted(new SimulationTimestepCompleteEventArgs(t, Molecule));
            }
            OnSimulationFinished();
        }
예제 #5
0
        private static void CalculateAtomShellRepulsion(Molecule molecule,
                                                        Dictionary <uint, Vector3D> forceLookup,
                                                        AtomNeighborhoodMap neighborhoodMap)
        {
            var vertices = molecule.MoleculeStructure.Vertices.Select(v => v.Id);

            foreach (var vertex in vertices)
            {
                var atom          = molecule.GetAtom(vertex);
                var atom1Position = atom.Position;
                var atom1Radius   = atom.Radius.Value;
                //var bondedNeighbors = new HashSet<Atom>(atom.OuterOrbitals
                //    .Where(o => o.IsPartOfBond)
                //    .Select(o => GetBondedAtom(o, atom)));

                var neighborhood = neighborhoodMap.GetNeighborhood(vertex);
                foreach (var neighborVertex in neighborhood)
                {
                    if (neighborVertex <= vertex)
                    {
                        continue;
                    }
                    var neighborAtom = molecule.GetAtom(neighborVertex);
                    //if (bondedNeighbors.Contains(neighborAtom))
                    //    continue;
                    var atom2Radius   = atom.Radius.Value;
                    var atomRadiusSum = atom1Radius + atom2Radius;
                    var r             = atom1Position.VectorTo(neighborAtom.Position);
                    var distance      = r.Magnitude().In(SIPrefix.Pico, Unit.Meter);

                    var shellRepulsionForce = -(1e-5 * (1e-12 / distance)
                                                * Math.Exp(Math.Min(1e12 * (atomRadiusSum - distance), 0)))
                                              * r.Normalize().ToVector3D();

                    forceLookup[vertex]         += shellRepulsionForce;
                    forceLookup[neighborVertex] += -shellRepulsionForce;
                }
            }
        }