/// <summary> /// Gets the material to be transferred by extracting it from the source material. /// </summary> /// <param name="source">The material from which the transfer is to be made.</param> /// <returns>The material to be transferred.</returns> public virtual IMaterial GetExtract(IMaterial source) { IMaterial retval = null; if (m_materialType == null) { double massToRemove = source.Mass * Percentage; if (source is Substance) { retval = ((Substance)source).Remove(massToRemove); } else { retval = ((Mixture)source).RemoveMaterial(massToRemove); } } else { if (source is Substance) { Substance s = ((Substance)source); if (s.MaterialType.Equals(m_materialType)) { retval = s.Remove(s.Mass * m_percentage); } else { retval = m_materialType.CreateMass(0, 0); } } else if (source is Mixture) { Mixture m = ((Mixture)source); retval = m.RemoveMaterial(m_materialType, m.ContainedMassOf(m_materialType) * m_percentage); if (retval == null) { retval = m_materialType.CreateMass(0, 0); } } else { throw new ApplicationException("Attempt to remove an unknown implementer of IMaterial from a mixture!"); } } m_actualMass = retval.Mass; m_duration = TimeSpan.FromTicks((long)(m_durationPerKilogram.Ticks * retval.Mass)); return(retval); }
/// <summary> /// Causes the reaction to take place, if possible, in (and perform modifications to, the provided target mixture. /// </summary> /// <param name="target">The target.</param> /// <returns></returns> public ReactionInstance React(Mixture target) { // We will handle a reaction's completion percentage/equilibrium // calculation by first using the reverse reaction to move all of // the already-existent (in proportion) products over to the // reactant side, and then move rxnPct % back to the product side. double fwdScale = double.MaxValue; double revScale = double.MaxValue; if (m_reactants.Count != 0) { foreach (ReactionParticipant rp in m_reactants) { double howMuch = target.ContainedMassOf(rp.MaterialType); if (howMuch > 0 && rp.IsCatalyst) { howMuch = double.MaxValue; } fwdScale = Math.Min(fwdScale, howMuch / rp.Mass); if (s_diagnostics) { _Debug.WriteLine("target contains " + howMuch + " of reactant " + rp.MaterialType.Name + " so fwdScale is " + fwdScale); } } if (fwdScale == double.MaxValue) { fwdScale = 0.0; } } else { fwdScale = 0.0; } fwdScale *= m_rxPct; if (m_products.Count != 0) { foreach (ReactionParticipant rp in m_products) { double howMuch = target.ContainedMassOf(rp.MaterialType); if (howMuch > 0 && rp.IsCatalyst) { howMuch = double.MaxValue; } revScale = Math.Min(revScale, howMuch / rp.Mass); if (s_diagnostics) { _Debug.WriteLine("target contains " + howMuch + " of product " + rp.MaterialType.Name + " so revScale is " + revScale); } } if (revScale == double.MaxValue) { revScale = 0.0; } } else { revScale = 0.0; } revScale *= (1 - m_rxPct); // If we're going to undo and then redo the same thing, the reaction didn't happen. if ((fwdScale == 0.0 && revScale == 0.0) || (Math.Abs(fwdScale - revScale) < 0.000001)) { if (s_diagnostics) { _Debug.WriteLine("Reaction " + Name + " won't happen in mixture " + target); } return(null); } if (s_diagnostics) { _Debug.WriteLine("Mixture is " + target); } if (s_diagnostics) { _Debug.WriteLine("Reaction " + Name + " is happening. " + ToString()); } ReactionGoingToHappenEvent?.Invoke(this, target); target.ReactionGoingToHappen(this); Mixture mixtureWas = (Mixture)target.Clone(); target.SuspendChangeEvents(); if (s_diagnostics) { _Debug.WriteLine(revScale > 0.0 ? "Performing reverse reaction..." : "Reverse reaction won't happen."); } if (revScale > 0.0) { React(target, m_products, m_reactants, revScale); } if (s_diagnostics) { _Debug.WriteLine(fwdScale > 0.0 ? "Performing forward reaction..." : "Forward reaction won't happen."); } if (fwdScale > 0.0) { React(target, m_reactants, m_products, fwdScale * m_rxPct); } // Percent completion is pulled out of the Reaction object. ReactionInstance ri = new ReactionInstance(this, fwdScale, revScale, m_nextRiGuid); m_nextRiGuid = GuidOps.Increment(m_nextRiGuid); ReactionHappenedEvent?.Invoke(ri); target.ReactionHappened(ri); target.AddEnergy(m_energy * (fwdScale - revScale)); target.ResumeChangeEvents(!mixtureWas.ToString("F2", "F3").Equals(target.ToString("F2", "F3"))); // Only emit summary events if the mixture has changed. return(ri); }