/// <summary> /// Private helper method for GetSensorGasEndPoint(Sensor). /// </summary> /// <param name="sensor"></param> /// <param name="gasEndPoints"></param> /// <returns></returns> private GasEndPoint GetSensorGasEndPoint(Sensor sensor, List <GasEndPoint> gasEndPoints) { MeasurementType sensorMeasurementType = ((SensorType)sensor.Type).MeasurementType; string sensorGasCode = sensor.CalibrationGas.Code; double sensorConcentration = sensor.CalibrationGasConcentration; double lelMultiplier = GasType.Cache[sensorGasCode].LELMultiplier; int pointNumber = 0; Log.Debug("SCAN 1 (find appropriate gas with desired concentration)..."); foreach (GasEndPoint gasEndPoint in gasEndPoints) { Cylinder cyl = gasEndPoint.Cylinder; LogGasEndPoint(gasEndPoint, ++pointNumber); // Ignore already tried cylinders. if (_triedGasEndPoints.ContainsKey(gasEndPoint)) { Log.Debug("...Rejected. Already tried cylinder."); continue; } // Ignore empty cylinders. if (cyl.Pressure == PressureLevel.Empty) { _triedGasEndPoints[gasEndPoint] = gasEndPoint; Log.Debug("...Rejected. Cylinder empty."); continue; } // Check the measurement type for how to multiply the concentration. // Make sure we convert sensor's LEL // concentration to PPM for matching against cylinders concentrations if (sensorMeasurementType == MeasurementType.LEL) { // Convert sensor's cal gas concentration from %LEL to PPM sensorConcentration = sensor.CalibrationGasConcentration / lelMultiplier; // We want to round the concentration to the nearest hundred. // e.g., if concentration is 3928, we want to round it to 3900. // // DO NOT DO THE FOLLOWING COMMENTED OUT LINE! IT NEEDS TO BE KEPT // SEPARATED AS THREE SEPARATE LINES, OTHERWISE IT MIGHT CRASHES WINCE. // SOME BUG IN COMPACT FRAMEWORK? // sensorConcentration = Math.Round( sensorConcentration / 100.0, 0 ) * 100.0; sensorConcentration /= 100.0; sensorConcentration = Math.Round(sensorConcentration, 0); sensorConcentration *= 100.0; Log.Debug(string.Format("...Sensor concentration of {0}%% LEL equals {1} PPM ({2} multiplier).", sensor.CalibrationGasConcentration, sensorConcentration, lelMultiplier)); } else if (sensorMeasurementType == MeasurementType.VOL) { sensorConcentration = sensor.CalibrationGasConcentration * 10000; Log.Debug(string.Format("...Sensor concentration of {0}%% VOL equals {1} PPM.", sensor.CalibrationGasConcentration, sensorConcentration)); } // For oxygen sensors, ignore 20.9 concentration end points. if ((sensorGasCode == GasCode.O2) && cyl.IsZeroAir) { Log.Debug("...Rejected. Can't use ZeroAir for O2."); continue; } // For oxygen sensors, ignore 20.9 concentration end points. if ((sensorGasCode == GasCode.O2) && cyl.IsFreshAir) { Log.Debug("...Rejected. Can't use FreshAir for O2."); continue; } // Ignore cylinders lacking the right gases. if (!cyl.ContainsGas(sensorGasCode, sensorConcentration, sensorMeasurementType)) { Log.Debug("...Rejected. Does not contain " + sensorGasCode + " with concentration " + sensorConcentration); continue; } // Ensure bump tests for O2 sensors use concentrations of 19% O2 or less. if (sensorGasCode == GasCode.O2) { // The following Find should always succeed assuming we already did a Cylinder.ContainsGas call earlier. GasConcentration gasConcentration = cyl.GasConcentrations.Find(gc => gc.Type.Code == sensorGasCode); // Parts per million (ppm) of X divided by 10,000 = percentage concentration of X if ((gasConcentration.Concentration / 10000.0) > 19.0) { Log.Debug("...Rejected. Can't use concentrations above 19% for O2."); continue; } } // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases if (lelMultiplier > 0.0) { // We now know this cylinder contains the desired gas concentration. But we don't allow // calibration of combustible sensor using any cylinder that is higher than 60% LEL. // So, find the gas in the cylinder and check it's LEL level. double cylinderPPM = -1.0; foreach (GasConcentration gasConcentration in cyl.GasConcentrations) { if (gasConcentration.Type.Code == sensorGasCode) { cylinderPPM = gasConcentration.Concentration; break; } } if (cylinderPPM < 0) // this should never happen. Which means we better check. { Log.Debug("...Rejected. Does not contain " + sensorGasCode); continue; } double cylinderLEL = cylinderPPM * lelMultiplier; if (cylinderLEL > 60.0) // cylinder is higher than 60%? Don't use it. { Log.Debug(string.Format("...Rejected. Contains {0} with too high LEL concentration ({1}%%).", sensorGasCode, Math.Round(cylinderLEL, 1))); Log.Debug("...Will not use concentration higher than 60%% LEL."); continue; } } // Found a cylinder with the correct gas and concentration. _triedGasEndPoints[gasEndPoint] = gasEndPoint; Log.Debug("...SELECTED. Contains " + sensorGasCode + " with desired concentration " + sensorConcentration); return(gasEndPoint); } Log.Debug("SCAN 2 (find appropriate gas with any concentration)..."); pointNumber = 0; foreach (GasEndPoint gasEndPoint in gasEndPoints) { LogGasEndPoint(gasEndPoint, ++pointNumber); // Ignore already tried cylinders. if (_triedGasEndPoints.ContainsKey(gasEndPoint)) { Log.Debug("...Rejected. Already tried cylinder."); continue; } // Ignore empty cylinders. if (gasEndPoint.Cylinder.Pressure == PressureLevel.Empty) { _triedGasEndPoints[gasEndPoint] = gasEndPoint; Log.Debug("...Rejected. Cylinder empty."); continue; } // For oxygen sensors, ignore 20.9 concentration end points. if ((sensorGasCode == GasCode.O2) && gasEndPoint.Cylinder.IsZeroAir) { Log.Debug("...Rejected. Can't use Zero Air for O2."); continue; } // For oxygen sensors, ignore 20.9 concentration end points. if ((sensorGasCode == GasCode.O2) && gasEndPoint.Cylinder.IsFreshAir) { Log.Debug("...Rejected. Can't use FreshAir for O2."); continue; } // Ignore cylinders lack the right gases. if (!gasEndPoint.Cylinder.ContainsGas(sensorGasCode)) { Log.Debug("...Rejected. Does not contain " + sensorGasCode); continue; } // Ensure bump tests for O2 sensors use concentrations of 19% O2 or less. if (sensorGasCode == GasCode.O2) { // The following Find should always succeed assuming we already did a Cylinder.ContainsGas call earlier. GasConcentration gasConcentration = gasEndPoint.Cylinder.GasConcentrations.Find(gc => gc.Type.Code == sensorGasCode); // Parts per million (ppm) of X divided by 10,000 = percentage concentration of X if ((gasConcentration.Concentration / 10000.0) > 19.0) { Log.Debug("...Rejected. Can't use concentrations above 19% for O2."); continue; } } // SGF Feb-10-2009 DSW-72 // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases if (lelMultiplier > 0.0) { // We now know this cylinder contains the desired gas concentration. But we don't allow // calibration of combustible sensor using any cylinder that is higher than 60% LEL. // So, find the gas in the cylinder and check it's LEL level. double cylinderPPM = -1.0; foreach (GasConcentration gasConcentration in gasEndPoint.Cylinder.GasConcentrations) { if (gasConcentration.Type.Code == sensorGasCode) { cylinderPPM = gasConcentration.Concentration; break; } } if (cylinderPPM < 0) // this should never happen. Which means we better check. { Log.Debug("...Rejected. Does not contain " + sensorGasCode); continue; } double cylinderLEL = cylinderPPM * lelMultiplier; if (cylinderLEL > 60.0) // cylinder is higher than 60%? Don't use it. { Log.Debug(string.Format("...Rejected. Contains {0} with too high LEL concentration ({1}%%).", sensorGasCode, Math.Round(cylinderLEL, 1))); Log.Debug("...Will not use concentration higher than 60%% LEL."); continue; } } // Found a cylinder with the correct gas. _triedGasEndPoints[gasEndPoint] = gasEndPoint; Log.Debug("...SELECTED. Contains " + sensorGasCode); return(gasEndPoint); } return(null); }
/// <summary> /// Get the calibration test gas end point for a sensor. /// </summary> /// <param name="installedComponent">The sensor to get the gas for.</param> /// <returns>The correct gas end point.</returns> /// <exception cref="CorrectCalibrationGasUnavailable"> /// Thrown when no cylinder is provided for the sensor. /// </exception> protected GasEndPoint GetSensorGasEndPoint( InstalledComponent installedComponent ) { Sensor sensor = null; MeasurementType sensorMeasurementType = MeasurementType.Unknown; if (installedComponent != null) { sensor = installedComponent.Component as Sensor; sensorMeasurementType = ((SensorType)sensor.Type).MeasurementType; } #region LogDebug if (sensor != null) { Log.Debug( "Calibration.GetSensorGasEndPoint" ); Log.Debug( "Finding appropriate cal gas for Sensor: " + sensor.Type + ", UID: " + sensor.Uid + ", CalGas Code: " + sensor.CalibrationGas.Code + ", Conc: " + sensor.CalibrationGasConcentration + ", Pos: " + installedComponent.Position ); } #endregion // If this is a sensor that uses 20.9 O2 for its calibration gas, // then attempt to find a cylinder that offers Zero Air; if // Zero Air is not available, find Fresh Air. If neither are // available, then fall out of this code and proceed to the main // processing loop below. if ( sensor.CalibrationGas.Code == GasCode.O2 && sensor.CalibrationGasConcentration == 20.9 ) { GasEndPoint air = GetSensorZeroAir( installedComponent, false, true ); if (air != null) { _triedGasEndPoints[air] = air; Cylinder cyl = air.Cylinder; if (cyl.IsZeroAir) Log.Debug("...SELECTED GasEndPoint. Has ZeroAir for O2 at 20.9."); else if (cyl.IsFreshAir) Log.Debug("...SELECTED GasEndPoint. Has FreshAir for O2 at 20.9."); else // We do not expect to reach this line of code, but it has been placed here to // log that GetSensorZeroAir returned a cylinder that was Fresh Air or Zero Air. Log.Debug(string.Format("...SELECTED GasEndPoint: {0}", cyl.ToString())); return air; } } double sensorConcentration = sensor.CalibrationGasConcentration; double lelMultiplier = GasType.Cache[ sensor.CalibrationGas.Code ].LELMultiplier; int pointCount = 0; Log.Debug( "SCAN 1 (Find appropriate gas with desired concentration)..." ); foreach ( GasEndPoint gasEndPoint in GasEndPoints ) { Cylinder cyl = gasEndPoint.Cylinder; #region LogDebug string msg = "GasEndPoint #" + ++pointCount; Log.Debug(msg); msg = "...Pos=" + gasEndPoint.Position //+ ", ID=" + cyl.ID + ", FactID=" + cyl.FactoryId + ", Part=" + cyl.PartNumber + ", Fresh=" + cyl.IsFreshAir + ", ZeroAir=" + cyl.IsZeroAir + ", Pressure=" + cyl.Pressure.ToString(); if ( cyl.Volume != DomainModelConstant.NullInt ) msg += ", Vol=" + cyl.Volume; Log.Debug( msg ); msg = "......"; foreach ( GasConcentration gasCon in cyl.GasConcentrations ) { msg += "[" + gasCon.Type.Code; msg += " "; msg += ( gasCon.Concentration == DomainModelConstant.NullDouble ) ? "fresh" : gasCon.Concentration.ToString(); msg += "]"; } Log.Debug( msg ); #endregion // Ignore already tried cylinders. if ( _triedGasEndPoints.ContainsKey( gasEndPoint ) ) { Log.Debug( "...Rejected. Already tried cylinder." ); continue; } // Ignore empty cylinders. if ( cyl.Pressure == PressureLevel.Empty ) { _triedGasEndPoints[ gasEndPoint ] = gasEndPoint; Log.Debug( "...Rejected. Cylinder empty." ); continue; } // Check the measurement type for how to multiply the concentration. // Make sure we convert sensor's LEL // concentration to PPM for matching against cylinders concentrations if (sensorMeasurementType == MeasurementType.LEL) { // Convert sensor's cal gas concentration from %LEL to PPM sensorConcentration = sensor.CalibrationGasConcentration / lelMultiplier; // We want to round the concentration to the nearest hundred. // e.g., if concentration is 3928, we want to round it to 3900. // // DO NOT DO THE FOLLOWING COMMENTED OUT LINE! IT NEEDS TO BE KEPT // SEPARATED AS THREE SEPARATE LINES, OTHERWISE IT CRASHES WINCE. // SOME BUG IN COMPACT FRAMEWORK? // sensorConcentration = Math.Round( sensorConcentration / 100.0, 0 ) * 100.0; sensorConcentration /= 100.0; sensorConcentration = Math.Round( sensorConcentration, 0 ); sensorConcentration *= 100.0; Log.Debug( string.Format( "...Sensor concentration of {0}%% LEL equals {1} PPM ({2} multiplier)", sensor.CalibrationGasConcentration, sensorConcentration, lelMultiplier ) ); } else if (sensorMeasurementType == MeasurementType.VOL) { sensorConcentration = sensor.CalibrationGasConcentration * 10000; Log.Debug( string.Format( "...Sensor concentration of {0}%% VOL equals {1} PPM", sensor.CalibrationGasConcentration, sensorConcentration ) ); } // Ignore cylinders lacking the right gases. if (!cyl.ContainsGas(sensor.CalibrationGas.Code, sensorConcentration, sensorMeasurementType)) { Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code + " with desired concentration " + sensorConcentration ); continue; } // SGF Feb-10-2009 DSW-72 // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases if ( lelMultiplier > 0.0 ) { // We now know this cylinder contains the desired gas concentration. But we don't allow // calibration of combustible sensor using any cylinder that is higher than 60% LEL. // So, find the gas in the cylinder and check it's LEL level. double cylinderPPM = -1.0; foreach ( GasConcentration gasConcentration in cyl.GasConcentrations ) { if ( gasConcentration.Type.Code == sensor.CalibrationGas.Code ) { cylinderPPM = gasConcentration.Concentration; break; } } if ( cylinderPPM < 0 ) // this should never happen. Which means we better check. { Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code ); continue; } double cylinderLEL = cylinderPPM * lelMultiplier; if ( cylinderLEL > 60.0 ) // cylinder is higher than 60%? Don't use it. { Log.Debug( string.Format( "...Rejected. Contains {0} with too high LEL concentration ({1}%%)", sensor.CalibrationGas.Code, Math.Round( cylinderLEL, 1 ) ) ); Log.Debug( "...Will not use concentration higher than 60%% LEL." ); continue; } } // Found a cylinder with the correct gas and concentration. _triedGasEndPoints[ gasEndPoint ] = gasEndPoint; Log.Debug( "...SELECTED. Contains " + sensor.CalibrationGas.Code + " with desired concentration " + sensorConcentration ); return gasEndPoint; } // end-foreach 1 Log.Debug( "SCAN 2 (find appropriate gas with any concentration)..." ); pointCount = 0; foreach ( GasEndPoint gasEndPoint in GasEndPoints ) { Cylinder cyl = gasEndPoint.Cylinder; #region LogDebug string msg = "GasEndPoint #" + ++pointCount; Log.Debug(msg); msg = "...Pos=" + gasEndPoint.Position //+ ", ID=" + cyl.ID + ", FactID=" + cyl.FactoryId + ", Part=" + cyl.PartNumber + ", Fresh=" + cyl.IsFreshAir + ", ZeroAir=" + cyl.IsZeroAir + ", Pressure=" + cyl.Pressure.ToString(); if ( cyl.Volume != DomainModelConstant.NullInt ) msg += ", Vol=" + cyl.Volume; Log.Debug( msg ); msg = "......"; foreach ( GasConcentration gasCon in cyl.GasConcentrations ) { msg += "[" + gasCon.Type.Code; msg += " "; msg += ( gasCon.Concentration == DomainModelConstant.NullDouble ) ? "fresh" : gasCon.Concentration.ToString(); msg += "]"; } Log.Debug( msg ); #endregion // Ignore already tried cylinders. if ( _triedGasEndPoints.ContainsKey( gasEndPoint ) ) { Log.Debug( "...Rejected. Already tried cylinder." ); continue; } // Ignore cylinders lack the right gases. if ( ! cyl.ContainsGas( sensor.CalibrationGas.Code ) ) { Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code ); continue; } // SGF Feb-10-2009 DSW-72 // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases if ( lelMultiplier > 0.0 ) { // We now know this cylinder contains the right gas. But we don't allow // calibration of combustible sensor using any cylinder that is higher than 60% LEL. // So, find the gas in the cylinder and check it's LEL level. double cylinderPPM = -1.0; foreach ( GasConcentration gasConcentration in cyl.GasConcentrations ) { if ( gasConcentration.Type.Code == sensor.CalibrationGas.Code ) { cylinderPPM = gasConcentration.Concentration; break; } } if ( cylinderPPM < 0 ) // this should never happen. Which means we better check. { Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code ); continue; } double cylinderLEL = cylinderPPM * lelMultiplier; if ( cylinderLEL > 60.0 ) // cylinder is higher than 60%? Don't use it. { Log.Debug( string.Format( "...Rejected. Contains {0} with too high LEL concentration ({1}%%)", sensor.CalibrationGas.Code, Math.Round( cylinderLEL, 1 ) ) ); Log.Debug( "...Will not use concentration higher than 60%% LEL." ); continue; } } // end-if MeasurementTypes.LEL // Found a cylinder with the correct gas. _triedGasEndPoints[ gasEndPoint ] = gasEndPoint; Log.Debug( "...SELECTED. Contains " + sensor.CalibrationGas.Code ); return gasEndPoint; } // end-foreach 2 // If this is a sensor that uses O2 for its calibration gas, and no cylinder has been found // yet, then attempt to find a cylinder that offers Fresh Air. We don't try to find a Zero // Air cylinder because one of the scans above would have already selected it if one was // available. Also, O2 sensors with a cal gas concentration of 20.9 should have already // selected a Zero Air or Fresh Air cylinder so we don't need to check again. if ( sensor.CalibrationGas.Code == GasCode.O2 && sensor.CalibrationGasConcentration != 20.9 ) { GasEndPoint air = GetSensorFreshAir( installedComponent, true ); if ( air != null ) { _triedGasEndPoints[air] = air; Cylinder cyl = air.Cylinder; if ( cyl.IsFreshAir ) Log.Debug( "...SELECTED GasEndPoint. Has FreshAir for O2." ); else // We do not expect to reach this line of code, but it has been placed here to // log that GetSensorFreshAir returned a cylinder. Log.Debug( string.Format( "...SELECTED GasEndPoint: {0}", cyl.ToString() ) ); return air; } } Log.Debug( "NO APPROPRIATE CALIBRATION GAS FOUND!" ); throw new CorrectCalibrationGasUnavailable( string.Format( "Sensor {0}, CalGas={1}({2})", sensor.Uid, sensor.CalibrationGas.Code, sensor.CalibrationGasConcentration ) ); // No gas end point was found. }