/// <summary> /// Applies the material specs. /// </summary> /// <param name="emitted">The emitted.</param> /// <param name="original">The original.</param> public static void ApplyMaterialSpecs(Substance emitted, Substance original) { _Debug.Assert(emitted.MaterialType.Equals(original.MaterialType)); ArrayList emittedSpecs = new ArrayList(); foreach (DictionaryEntry de in original.GetMaterialSpecs()) { Guid specGuid = (Guid)de.Key; double specMass = (double)de.Value; double origPctg = specMass / original.Mass; double emittedMass = emitted.Mass * origPctg; emittedSpecs.Add(new DictionaryEntry(specGuid, emittedMass)); } emitted.SetMaterialSpecs(emittedSpecs); }
/// <summary> /// Loads the contents of this Memento into the provided object. /// </summary> /// <param name="ism">The object to receive the contents of the memento.</param> public void Load(ISupportsMementos ism) { Substance substance = (Substance)ism; substance.m_mass = m_mass; substance.Temperature = m_temperature; substance.m_type = m_materialType; if (m_matlSpecs != null) { substance.SetMaterialSpecs(m_matlSpecs); } else { substance.ClearMaterialSpecs(); } OnLoadCompleted?.Invoke(this); }
/// <summary> /// Removes the specified substance from this substance. Both substances must be of the same material type, or an exception will fire.. /// </summary> /// <param name="substance">The substance.</param> /// <returns>Substance.</returns> /// <exception cref="ApplicationException">Fired if the substances are not of the same material type.</exception> /// <exception cref="WriteProtectionViolationException">Fired if there is a write lock on the substance.</exception> public virtual Substance Remove(Substance substance) { if (!m_type.Equals(substance.m_type)) { throw new ApplicationException("Substance " + Name + " being removed from substance " + substance.Name + "!"); } if (!m_writeLock.IsWritable) { throw new WriteProtectionViolationException(this, m_writeLock); } // Trace.Write("Removing " + substance.Mass + " kg of " + substance.Name + " from an existing " + m_mass + " kg, "); // TODO: Assert we are not removing more than is there. double mass = Math.Min(substance.Mass, m_mass); Substance s = Remove(mass); // _Debug.WriteLine("leaving " + m_mass + " kg."); m_ssh.ReportChange(); MaterialChanged?.Invoke(this, MaterialChangeType.Contents); return(s); }
/// <summary> /// Ascertains equality between this one and the other one. /// </summary> /// <param name="otherOne">The other one.</param> /// <returns><c>true</c> if this one and the other one are equal, <c>false</c> otherwise.</returns> public bool Equals(ISupportsMementos otherOne) { Substance otherSubstance = otherOne as Substance; if (otherSubstance == null) { return(false); } if (m_materialSpecs != null && otherSubstance.m_materialSpecs == null) { return(false); } if (m_materialSpecs == null && otherSubstance.m_materialSpecs != null) { return(false); } if (m_materialSpecs != null) { if (otherSubstance.m_materialSpecs != null && m_materialSpecs.Count != otherSubstance.m_materialSpecs.Count) { return(false); } foreach (DictionaryEntry de in m_materialSpecs) { if (otherSubstance.m_materialSpecs != null && !otherSubstance.m_materialSpecs.Contains(de.Key)) { return(false); } if (otherSubstance.m_materialSpecs != null && !de.Value.Equals(otherSubstance.m_materialSpecs[de.Key])) { return(false); } } } else if (otherSubstance.m_materialSpecs != null) { return(false); } return(m_mass.Equals(otherSubstance.m_mass) && Temp.Equals(otherSubstance.Temp) && m_type.Equals(otherSubstance.m_type)); }
public void TestRemovalByPercentageFromSubstance() { Model model = new Model("Hello, world.", Guid.NewGuid()); BasicReactionSupporter brs = new BasicReactionSupporter(); LoadSampleCatalog(brs.MyMaterialCatalog); Debug.WriteLine("\r\nWe now work on a substance."); MaterialType mt = brs.MyMaterialCatalog["Hydrochloric Acid"]; Substance s = (Substance)mt.CreateMass(100, 20); Debug.WriteLine("We have " + s); MaterialTransferSpecByPercentage tsbp = new MaterialTransferSpecByPercentage(brs.MyMaterialCatalog["Hydrochloric Acid"], .75, TimeSpan.FromMinutes(5)); IMaterial removee = tsbp.GetExtract(s); Debug.WriteLine("Want to remove " + tsbp); Debug.WriteLine("Successful in removing " + removee + ".\r\nWhat remains is "); Debug.WriteLine(s); Assert.IsTrue(Math.Abs(s.Mass - 25.00) < 0.01, "The Water part is not 25 kg"); Assert.IsTrue(tsbp.Duration.Hours == 6 && tsbp.Duration.Minutes == 15, "Removing 75% Water part did not take 5 Min"); }
public void TestChangeNotifications() { Model model = new Model("Test Model", Guid.NewGuid()); BasicReactionSupporter brs = new BasicReactionSupporter(); InitializeForTesting(brs); MaterialType waterType = (MaterialType)brs.MyMaterialCatalog["Water"]; string results = string.Empty; Substance w1 = (Substance)waterType.CreateMass(100, 37); w1.MaterialChanged += new MaterialChangeListener(delegate(IMaterial material, MaterialChangeType type) { results += string.Format("{0} changed in {1}\r\n", material, type); }); w1.Temperature = 85.0; w1.Add((Substance)waterType.CreateMass(100, 37)); Assert.IsTrue(results.Equals(RESULT1)); results = string.Empty; w1.SuspendChangeEvents(); w1.Temperature = 95.0; w1.Add((Substance)waterType.CreateMass(100, 37)); w1.ResumeChangeEvents(false); Assert.IsTrue(results.Equals(string.Empty)); results = string.Empty; w1.SuspendChangeEvents(); w1.Temperature = 95.0; w1.Add((Substance)waterType.CreateMass(100, 37)); w1.ResumeChangeEvents(true); Assert.IsTrue(results.Equals(RESULT2)); // NOW, SAME TEST, BUT ON A MIXTURE INSTEAD. MaterialType acetoneType = (MaterialType)brs.MyMaterialCatalog["Acetone"]; Mixture m1 = new Mixture("My Goo"); m1.MaterialChanged += new MaterialChangeListener(delegate(IMaterial material, MaterialChangeType type) { results += string.Format("{0} changed in {1}\r\n", material, type); }); results = string.Empty; m1.AddMaterial((Substance)waterType.CreateMass(100, 37)); m1.AddMaterial((Substance)acetoneType.CreateMass(100, 45)); Assert.IsTrue(results.Equals(RESULT3)); results = string.Empty; m1.SuspendChangeEvents(); m1.AddMaterial((Substance)waterType.CreateMass(100, 99)); m1.AddMaterial((Substance)acetoneType.CreateMass(100, 99)); Assert.IsTrue(results.Equals(string.Empty)); m1.ResumeChangeEvents(false); Assert.IsTrue(results.Equals(string.Empty)); results = string.Empty; m1.SuspendChangeEvents(); m1.AddMaterial((Substance)waterType.CreateMass(100, 99)); m1.AddMaterial((Substance)acetoneType.CreateMass(100, 99)); Assert.IsTrue(results.Equals(string.Empty)); m1.ResumeChangeEvents(true); Assert.IsTrue(results.Equals(RESULT4)); }
public void TestRemovalByPercentageFromMixture() { Model model = new Model("Hello, world.", Guid.NewGuid()); BasicReactionSupporter brs = new BasicReactionSupporter(); LoadSampleCatalog(brs.MyMaterialCatalog); // Define reactions Reaction r = new Reaction(null, "Reaction", Guid.NewGuid()); r.AddReactant(brs.MyMaterialCatalog["Caustic Soda"], 0.5231); r.AddReactant(brs.MyMaterialCatalog["Hydrochloric Acid"], 0.4769); r.AddProduct(brs.MyMaterialCatalog["Water"], 0.2356); r.AddProduct(brs.MyMaterialCatalog["Sodium Chloride"], 0.7644); brs.MyReactionProcessor.AddReaction(r); Mixture mixture = new Mixture(model, "Test mixture 1", Guid.NewGuid()); brs.MyReactionProcessor.Watch(mixture); // Add substances AddSubstance(ref mixture, brs.MyMaterialCatalog["Caustic Soda"], 40, 20.0); AddSubstance(ref mixture, brs.MyMaterialCatalog["Hydrochloric Acid"], 40, 20.0); mixture.Temperature = 100.0; // Definitions to retrive substances from mixture Substance water = null; Substance hydrochloricAcid = null; Substance sodiumCloride = null; foreach (Substance su in mixture.Constituents) { switch (su.Name) { case "Water": water = su; break; case "Hydrochloric Acid": hydrochloricAcid = su; break; case "Sodium Chloride": sodiumCloride = su; break; } } Assert.IsTrue(Math.Abs(hydrochloricAcid.Mass - 3.53) < 0.01, "The Hydrochloric Acid part is not 3.53 kg"); Assert.IsTrue(Math.Abs(water.Mass - 18.01) < 0.01, "The Water part is not 18.01 kg"); Assert.IsTrue(Math.Abs(sodiumCloride.Mass - 58.45) < 0.01, "The Sodium Cloride part is not 58.45 kg"); // Duration for removing mass given is per 1 kg MaterialTransferSpecByPercentage tsbp = new MaterialTransferSpecByPercentage(brs.MyMaterialCatalog["Water"], .5, TimeSpan.FromMinutes(5)); IMaterial removee = tsbp.GetExtract(mixture); Debug.WriteLine("Want to remove " + tsbp); Debug.WriteLine("Successful in removing " + removee + ".\r\nWhat remains is "); Debug.WriteLine(mixture); // Now try to remove by mass from a substance. foreach (Substance su in mixture.Constituents) { switch (su.Name) { case "Water": water = su; break; case "Hydrochloric Acid": hydrochloricAcid = su; break; case "Sodium Chloride": sodiumCloride = su; break; } } Assert.IsTrue(Math.Abs(hydrochloricAcid.Mass - 3.53) < 0.01, "The Hydrochloric Acid part is not 3.53 kg"); Assert.IsTrue(Math.Abs(water.Mass - 9.00) < 0.01, "The Water part is not 9.00 kg"); Assert.IsTrue(Math.Abs(sodiumCloride.Mass - 58.45) < 0.01, "The Sodium Cloride part is not 58.45 kg"); Assert.IsTrue(tsbp.Duration.Minutes == 45, "Removing 50% Water part did not take 5 Min"); // there are also a few seconds and miliseconds }
public void TestSecondaryReactions() { Model model = new Model("Hello, world.", Guid.NewGuid()); BasicReactionSupporter brs = new BasicReactionSupporter(); LoadSampleCatalog(brs.MyMaterialCatalog); // Add more substances to catalog brs.MyMaterialCatalog.Add(new MaterialType(model, "Tuberus Magnificus", Guid.NewGuid(), 1.02, 4.9, MaterialState.Solid, 22.5)); brs.MyMaterialCatalog.Add(new MaterialType(model, "French Fried Potatoes", Guid.NewGuid(), 1.02, 5.1, MaterialState.Liquid, 22.8)); // Define reactions Reaction r1 = new Reaction(null, "Reaction 1", Guid.NewGuid()); r1.AddReactant(brs.MyMaterialCatalog["Caustic Soda"], 0.5231); r1.AddReactant(brs.MyMaterialCatalog["Hydrochloric Acid"], 0.4769); r1.AddProduct(brs.MyMaterialCatalog["Water"], 0.2356); r1.AddProduct(brs.MyMaterialCatalog["Sodium Chloride"], 0.7644); brs.MyReactionProcessor.AddReaction(r1); Reaction r2 = new Reaction(null, "Make French Fries", Guid.NewGuid()); r2.AddReactant(brs.MyMaterialCatalog["Sodium Chloride"], 0.1035); r2.AddReactant(brs.MyMaterialCatalog["Tuberus Magnificus"], 0.8965); r2.AddProduct(brs.MyMaterialCatalog["French Fried Potatoes"], 1.000); brs.MyReactionProcessor.AddReaction(r2); Mixture mixture = new Mixture(model, "Contents of vat 1", Guid.NewGuid()); brs.MyReactionProcessor.Watch(mixture); AddSubstance(ref mixture, brs.MyMaterialCatalog["Caustic Soda"], 40, 20.0); AddSubstance(ref mixture, brs.MyMaterialCatalog["Hydrochloric Acid"], 40, 20.0); AddSubstance(ref mixture, brs.MyMaterialCatalog["Tuberus Magnificus"], 40, 20.0); mixture.Temperature = 100.0; Substance water = null; Substance hydrochloricAcid = null; Substance sodiumCloride = null; Substance ff = null; foreach (Substance s in mixture.Constituents) { switch (s.Name) { case "Water": water = s; break; case "Hydrochloric Acid": hydrochloricAcid = s; break; case "Sodium Chloride": sodiumCloride = s; break; case "French Fried Potatoes": ff = s; break; } } Assert.IsTrue(Math.Abs(hydrochloricAcid.Mass - 3.53) < 0.01, "The Hydrochloric Acid part is not 3.53 kg"); Assert.IsTrue(Math.Abs(water.Mass - 18.01) < 0.01, "The Water part is not 18.01 kg"); Assert.IsTrue(Math.Abs(sodiumCloride.Mass - 53.83) < 0.01, "The Sodium Cloride part is not 53.83 kg"); Assert.IsTrue(Math.Abs(ff.Mass - 44.62) < 0.01, "The French Fries part is not 44.62 kg"); Debug.WriteLine(mixture); }
public void TestReactionBasics() { BasicReactionSupporter brs = new BasicReactionSupporter(); Initialize(brs); Mixture mixture = new Mixture(null, "test mixture"); mixture.OnReactionHappened += new ReactionHappenedEvent(mixture_OnReactionHappened); brs.MyReactionProcessor.Watch(mixture); mixture.AddMaterial(brs.MyMaterialCatalog["Hydrochloric Acid"].CreateMass(10, 20)); mixture.AddMaterial(brs.MyMaterialCatalog["Caustic Soda"].CreateMass(12, 44)); foreach (IMaterial constituent in mixture.Constituents) { _Debug.WriteLine(constituent.ToString()); } /* Calculation mass: * 0.5231 + 0.4769 = 0.2356 + 0.7644 * 100 % Ractions = min(10 kg / 0.4769, 12 kg / 0.5231) = about 20.97 * --> Left over Caustic Soda = 12 kg - (20.97 * 0.5231)= about 1.03 kg * Water = 20.97 * 0.2356 = about 4.94 kg * Sodium Cloride = 20.97 * 0.7644 = about 16.03 kg * = 22.00 kg * Calculation temperature: * Hydrochloric Acid specific heat = 4.18 * Caustic Soda specific heat = 2.55 * Heat of Hydrochloric Acid is 10 kg * 2.55 * 20 dC = about 510.00 dC * Heat of Caustic Soda is 12 kg * 4.18 * 44 dC = about 2207.04 dC * Subtotal = about 2717.04 dC * Divide by 10 * 2.55 + 12 * 4.18 = 75.66 * Mixture temperature is 2717.04 / 75.66 = about 35.91 dC */ Substance water = null; Substance sodium = null; Substance soda = null; foreach (Substance s in mixture.Constituents) { switch (s.Name) { case "Water": water = s; break; case "Sodium Chloride": sodium = s; break; case "Caustic Soda": soda = s; break; } } _Debug.Assert(Math.Abs(soda.Mass - 1.03) < 0.01, "The Caustic Soda part is not 2.88 kg"); _Debug.Assert(Math.Abs(water.Mass - 4.94) < 0.01, "The Water part is not 4.5 kg"); _Debug.Assert(Math.Abs(sodium.Mass - 16.03) < 0.01, "The Sodium Cloride part is not 14.61 kg"); Console.WriteLine(mixture.Temperature); _Debug.Assert(Math.Abs(mixture.Temperature - 35.91) < 0.01, "The temperature is not 33.09 degrees C"); }
public void TestRemovalByMassFromMixture() { Model model = new Model("Hello, world.", Guid.NewGuid()); BasicReactionSupporter brs = new BasicReactionSupporter(); LoadSampleCatalog(brs.MyMaterialCatalog); // Define reactions Reaction r = new Reaction(null, "Reaction", Guid.NewGuid()); r.AddReactant(brs.MyMaterialCatalog["Caustic Soda"], 0.5231); r.AddReactant(brs.MyMaterialCatalog["Hydrochloric Acid"], 0.4769); r.AddProduct(brs.MyMaterialCatalog["Water"], 0.2356); r.AddProduct(brs.MyMaterialCatalog["Sodium Chloride"], 0.7644); brs.MyReactionProcessor.AddReaction(r); Mixture mixture = new Mixture(model, "Test mixture 1", Guid.NewGuid()); brs.MyReactionProcessor.Watch(mixture); // Add substances AddSubstance(ref mixture, brs.MyMaterialCatalog["Caustic Soda"], 40, 20.0); AddSubstance(ref mixture, brs.MyMaterialCatalog["Hydrochloric Acid"], 40, 20.0); mixture.Temperature = 100.0; // Definitions to retrive substances from mixture Substance water = null; Substance hydrochloricAcid = null; Substance sodiumCloride = null; foreach (Substance su in mixture.Constituents) { switch (su.Name) { case "Water": water = su; break; case "Hydrochloric Acid": hydrochloricAcid = su; break; case "Sodium Chloride": sodiumCloride = su; break; } } _Debug.Assert(Math.Abs(hydrochloricAcid.Mass - 3.53) < 0.01, "The Hydrochloric Acid part is not 3.53 kg"); _Debug.Assert(Math.Abs(water.Mass - 18.01) < 0.01, "The Water part is not 18.01 kg"); _Debug.Assert(Math.Abs(sodiumCloride.Mass - 58.45) < 0.01, "The Sodium Cloride part is not 58.45 kg"); // Remove 10 kg of water MaterialTransferSpecByMass tsbm = new MaterialTransferSpecByMass(brs.MyMaterialCatalog["Water"], 10, TimeSpan.FromMinutes(5)); _Debug.WriteLine("Want to remove " + tsbm); IMaterial removee = tsbm.GetExtract(mixture); _Debug.WriteLine("Successful in removing " + removee + ".\r\nWhat remains is "); _Debug.WriteLine(mixture); foreach (Substance su in mixture.Constituents) { switch (su.Name) { case "Water": water = su; break; case "Hydrochloric Acid": hydrochloricAcid = su; break; case "Sodium Chloride": sodiumCloride = su; break; } } _Debug.Assert(Math.Abs(hydrochloricAcid.Mass - 3.53) < 0.01, "The Hydrochloric Acid part is not 3.53 kg"); _Debug.Assert(Math.Abs(water.Mass - 8.01) < 0.01, "The Water part is not 8.01 kg"); _Debug.Assert(Math.Abs(sodiumCloride.Mass - 58.45) < 0.01, "The Sodium Chloride part is not 58.45 kg"); _Debug.Assert(tsbm.Duration.Equals(new TimeSpan(0, 0, 5, 0, 0)), "Removing 10 kg Water part did not take 5 Min"); }
/// <summary> /// Removes the specified mass from this substance. /// </summary> /// <param name="mass">The mass.</param> /// <returns>Substance.</returns> /// <exception cref="WriteProtectionViolationException">Fired if there is a write lock on the substance.</exception> public virtual Substance Remove(double mass) { if (!m_writeLock.IsWritable) { throw new WriteProtectionViolationException(this, m_writeLock); } Substance s = (Substance)MaterialType.CreateMass(mass, Temperature); if (m_mass == float.MaxValue) { if (m_materialSpecs != null) { // First figure out the total mass... double totalMass = m_materialSpecs.Cast <DictionaryEntry>().Sum(de => (double)de.Value); if (totalMass > 0.0) { foreach (DictionaryEntry de in m_materialSpecs) { if (s.m_materialSpecs == null) { s.m_materialSpecs = new Hashtable(); } s.m_materialSpecs.Add(de.Key, mass * ((double)de.Value) / totalMass); } } } return(s); } else { double pctRemoved = mass / m_mass; Hashtable ht = new Hashtable(); if (m_materialSpecs != null) { foreach (DictionaryEntry de in m_materialSpecs) { if (s.m_materialSpecs == null) { s.m_materialSpecs = new Hashtable(); } if (s.m_materialSpecs.ContainsKey(de.Key)) { s.m_materialSpecs[de.Key] = pctRemoved * ((double)de.Value); } else { s.m_materialSpecs.Add(de.Key, pctRemoved * ((double)de.Value)); } if (pctRemoved < 1.0) { ht.Add(de.Key, (1.0 - pctRemoved) * ((double)de.Value)); } } } m_materialSpecs = ht; } double have = Energy; double minus = s.Energy; m_mass -= s.Mass; // Have to set Mass before setting energy, since energy->temp requires mass. Energy = (have - minus); m_ssh.ReportChange(); MaterialChanged?.Invoke(this, MaterialChangeType.Contents); return(s); }