METHOD AND APPARATUS FOR PERFORMING AUTOMATED ANALYSIS

Abstract: A device for analyzing a whole blood sample is provided. The device comprises a conventional hematology analyzer integrated with a fluorescence cyometry analyzer. A controller is provided for controlling the analyzers, obtaining and utilizing data from both and reporting a quantitative result. Methods are also provided for analyzing a whole blood sample. One such method comprises the steps of performing on a single instrument an analysis of impedance associated with the blood sample, an analysis of light scatter associated with the blood sample, and an analysis of fluorescence associated with the blood sample. Data is collected and utilized. A result is reported.

Description: METHOD AND APPARATUS FOR PERFORMING AUTOMATED ANALYSIS REFERENCE TO RELATED APPLICATIONS This is a continuation-in-part application of Serial No. 08/283,379 filed August 1, 1994 entitled METHOD AND APPARATUS FOR PERFORMING AUTOMATED ANALYSIS. The parent application is assigned to the assignee of this application. The disclosure of the parent application is incorporated herein in its entirety by this reference. BACKGROUND This invention relates in general to particle analysis. More particularly, it relates to methods and devices for performing automated blood cell analysis by integrating "impedance," "light scattering," and "fluorescence" analysis and flow cytometric techniques. This invention also relates to a multipurpose reagent system and a method for rapid analysis of a whole blood sample. Peripheral blood of a human usually contains red blood cells (RBC) , platelets (KLT) , and white blood cells (WBC) , all of which are suspended in a conductive medium commonly known as plasma. Plasma comprises proteins, anions and cations. Plasma also contains components which assist in forming blood clots. The blood in an adult usually contains about 4.5 to 5 million RBCs or erythrocytes per cubic millimeter. Mature RBCs have no nuclei and are generally shaped as circular biconcave disks with a diameter of about 7.5 to 8 microns (μ) , and a thickness of about 1.5 to 1.8 microns. RBCs contain hemoglobin which gives blood its red color. Hemoglobin helps transport oxygen and carbon dioxide and plays a role in maintaining pH in blood. The blood in an adult usually contains about 200,000 to 400,000 platelets per cubic millimeter. Platelets are small, biconvex cellular particles whose mean volume is about 7μ to 8μ. Their general configuration includes a granular central portion embedded in a homogeneous matrix. Peripheral blood also contains red cells of earlier maturation levels which are important diagnostic indicators. Two of these are reticulocytes and nucleated red blood cells. At the earliest stage of development the red cell consists mostly of nucleus, and is referred to as an erythroblast. As the erythroblast matures, the nucleus becomes smaller, anucleolate, and more nearly spherical. Subsequent maturity involves a complete loss of nucleus. The immature red cells that retain a nucleus are referred to as nucleated red blood cells (NRBCs) . The NRBC count has been useful in patient monitoring under many disease states. However, NRBCs in peripheral blood often contribute to inaccurate enumeration of the white cell count, due in part to the presence of a nucleus which makes them difficult to distinguish from small white cells. Reticulocytes are red cells at the maturation level just between NRBCs and mature RBCs. Reticulocytes provide a means of evaluating a patient's anemic state. Anemia usually occurs as a result of an uncompensated increase in the rate of removal of erythrocytes from blood, or a decrease in the rate at which they are formed and released into blood. An increased reticulocyte patient count in an anemic patient indicates rapid erythroid turnover which suggests acute blood loss or hemolysis. In normal human blood, the concentration of white cells, referred to as WBCs or leukocytes, is much lower than the concentration of red cells. The normal concentration of WBCs is approximately 7000 per microliter. They vary in size, most of them from about 7.5 to 12.5 microns in diameter. They are more nearly spherical in shape than RBCs and usually somewhat larger in volume. WBCs may be classified generally as either granular or non-granular. The granular WBCs include neutrophils, eosinophils and basophils. The non- granular WBCs include monocytes and lymphocytes. These categories of WBCs are often referred to collectively as a "five-part differential," and, generally, the most significant of these categories are neutrophils and lymphocytes. Neutrophils usually comprise from about 50 to 60% of all WBCs. Their cytoplasm contains numerous minute granules which can be stained. Under certain conditions neutrophils may leave the blood vessels and disintegrate, thereby releasing granules into the connective tissues. These granules are rich in certain enzymes which become active and take part in the body's defense mechanism. Lymphocytes comprise about 30% of the WBCs in humans. The nucleus of a normal lymphocyte occupies nearly the entire cell volume, and thus the cytoplasm surrounding the nucleus is a rather thin shell. Lymphocyte cytoplasm may stain with dyes due to the cytoplasm's content of ribonucleic acid. Lymphocytes may leave the blood vessels and enter the connective tissue where they also constitute a part of the body's defense mechanism, playing a major role in the body's im unological responses. There are three major "subsets" of lymphocytes that are currently clinically significant: T lymphocytes, B lymphocytes, and Natural Killer cells, also known as "large granular lymphocytes" or NK cells. Each of these subsets can be distinguished based on the existence of distinctive cell surface markers or antigens. Also, B lymphocytes have a high density of immunoglobulin of their surfaces, whereas T lymphocytes have little or none. T lymphocytes are characterized by various surface markers against which antibodies can be produced. Categories of T lymphocytes have been identified according to their surface markers and overall function. The "helper" T cells help B cells produce certain classes of antibody molecules, and help other T cells in their immune responses. The "suppressor" T cells are regulatory cells that can suppress the responsiveness of other T or B cells. The suppressor T cells include several subsets which are also recognized by distinct surface markers. The ability to count, size and classify blood cells is useful when evaluating the health of an individual. For example, the level of circulating CD4 lymphocytes (helper-T cells having a CD4 antigen expressed on the surface of the cell) is currently regarded as the best single predictor of progression of HIV infections. The CD4 level may be used for classifying individuals for enrollment in experimental treatment regimes, determining when anti viral therapy should be initiated, and monitoring treatment responses in clinical trials. Because CD4 lymphocyte levels may be important to some HIV-infected individuals, it is desirable to measure this parameter accurately. In the current state of the art of cell analysis, there are two technologies used for counting and classifying cells. These are generally known as "flow cytometry" and "image cytometry." The flow cytometry technology, which essentially consists of passing cells one at a time through a sensing zone of a flow cell, is preferred in clinical applications where patient test load is an important metric. This is mainly because it has at least an order of magnitude advantage in the number of cells that can be analyzed per second. Instrumentation incorporating flow cytometry can be further subdivided into two methods which can be generally classified as "conventional he atology" and "fluorescence cytometry. " A primary distinction between the two methods is that conventional hematology generally distinguish cells by means of size and shape alone using primarily impedance and light scatter technologies, whereas fluorescence cytometry uses cell nucleic acid content and/or surface antigens in addition to size and shape in distinguishing cells. Therefore the fluorescence method may be used to subdivide the cell types into finer classifications. A second distinction between the two methods is that conventional hematology gives results in absolute terms, whereas fluorescence cytometry results are in relative terms. Hematology analyzers deliver precise volumes and dilutions, and are thus able to measure absolute cell concentrations, or absolute counts of cell types per microliter of human blood. The fluorescence cytometry method gives only relative concentrations, or percentages of the various cell types. A third distinction is that the hematology method is generally automated, whereas the fluorescence cytometric method as generally practiced today, is at best semi- automated, both in sample preparation, and in sample analysis. The fluorescence cytometry method is therefore significantly more labor intensive than the hematology method. Both methods use cell by cell analysis. Therefore, due to the high concentration of cells in whole blood, it is necessary to dilute the blood samples prior to analysis so that individual cells can be isolated for sensing within a flowcell. An example of an instrument for performing automated hematology measurements is the Cell-Dyn® 3000 instrument, which has been sold for several years by Sequoia-Turner, a predecessor in interest of Abbott Laboratories. The Cell- Dyn® 3000 instrument uses "impedance" measurements to count and size RBCs and PLTs, "absorption" measurements to determine the concentration of hemoglobin in RBCs (MCH) , and "optical scatter" measurements to count and classify WBCs and the five part differential. The Cell-Dyn® 3000 instrument automatically prepares blood samples, measures cell parameters and generates test results. The complete automation of sample preparation is such that no substantive operator intervention is required once the patient sample of whole blood has been presented to the analyzer. As mentioned previously, in order to assure accurate "patient counts" for the various cell classes, the Cell-Dyn® 3000 instrument provides precise sample volumes, reagent volumes and dilution volumes. Patient counts are generally defined as the number of "events" per microliter of blood. The events may be RBCs, PLTs, WBCs, and classes or subclasses thereof. Other commercially available devices for performing hematology measurements include the Coulter® STKR, the Sysmex® NE8000, and the Technicon® H-l. Each of these uses combinations of scatter, impedance, and absorption to distinguish and quantify cells, and can thus be classified as a conventional hematology instrument. In contrast, the fluorescence flow cytometer incorporates the principles of fluorescence cell analysis with light scatter. In general this requires that the cell be stained with an appropriate color dye, or that a fluorochrome label be attached to an antigen or antibody on the cell's surface thus indicating the occurrence of a specific antigen-antibody reaction. In fluorescence flow cytometry, a suspension of previously stained or fluorescently labelled particles, typically cells in a blood or other biological fluid sample, is transported through a flowcell where the individual particles in the sample are illuminated with one or more focused light beams. One or more detectors detect the interaction between the light beam(s) and the labeled particles flowing through the flowcell. Commonly, some of the detectors are designed to measure fluorescent emissions, while other detectors measure scatter intensity or pulse duration. Thus, each particle that passes through the flowcell can be mapped into a feature space whose axes are the emission colors, light intensities, or other properties, i.e. scatter, measured by the detectors. Preferably, the different particles in the sample can be mapped into distinct and non-overlapping regions of the feature space, allowing each particle to be analyzed based on its mapping in the feature space. In this respect, flow cytometry differs from the conventional hematology instruments in that some of the feature space axis includes fluorescence emissions. As noted above, lymphocyte subclasses are health determinants. Thus, it is desirable that these and other parameters be measured accurately. Although known hematology and fluorescent flow cytometry instruments have made significant advances in the ability to characterize blood cells, a problem still faced in this area is the difficulty in obtaining accurate patient count values for certain classes of cells. An example of this problem is the CD4 cell patient count. Current analysis methods calculate the CD4 cell patient count from cell parameters measured on a hematology instrument and a separate fluorescence flow cytometry instrument. This calculation can provide up to 100% variability in absolute CD4 patient counts done on a single individual one week apart. See, e.g.: Update, Testing In The Blood Bank, Volume 5, No. 2, pages 1 to 6, published 1991 by Ortho Diagnostics Systems, Inc. The following articles discuss additional difficulties with developing CD4 patient counts using current methods and devices; The Lancet , Volume 340, August 22, 1992, page 485 describes variation in CD4 count results when different analyzers are used. The variation appears to stem from different lymphocyte count results. • Journal of Infectious Diseases, 1990, Volume 161, pages 356 to 357 describes variations in CD4 count due to variability in the reported lymphocyte concentration. The resulting variation in CD4 results has a deleterious effect on the patients' morale. • Journal of Acquired Immune Deficiency Syndromes, 1990, Volume 3, No. 2, pages 144 to 181 reports large variations in CD4 counts for both HIV positive and control subjects. The fraction of lymphocytes that are CD4 positive is relatively constant, while the WBC count and the fraction of WBCs that are lymphocytes vary greatly. This variability points to the need for standardized analysis procedures. • Laboratory Medicine, August 1983, Volume 14, No. 8, pages 509 to 514 discusses numerous spurious results and their causes in automated hematology analyzers. The entire disclosure of each of the above-identified references is incorporated herein by reference. One reason for variability in CD4 patient counts is manual sample preparation that cannot be controlled precisely and depends on operator proficiency. For example, a conventional procedure for determining a CD4 patient count starts with drawing two tubes of blood from a patient. One tube is analyzed on a hematology instrument which generates several measured and/or calculated parameters for the blood sample, including a total lymphocyte patient count, a lymphocyte percentage and a total WBC patient count. The 8 second tube of blood is analyzed on a fluorescence flow cytometry instrument. The sample preparation steps for the flow cytometry tests are labor intensive and operator dependent. These steps do not readily lend themselves to automation and precision. To prepare the sample for the flow cytometry instrument, the operator manually pipettes a volume of blood from the sample tube into an analysis tube. A volume of the desired fluorochrome labeled monoclonal antibody is added. The sample/antibody mixture is then incubated for a predetermined time at a predetermined temperature to allow antibody/antigen bindings to take place. After incubation, the operator adds a volume of RBC lyse to destroy the RBCs in the sample. Timing is important during the lysing stage. If the operator does not allow the lyse reaction to continue long enough, RBCs may remain in the sample and distort the measurements. If the operator allows the lyse reaction to continue for too long, the lyse may attack the WBCs. After determining that the lyse reaction is complete, the operator centrifuges and washes the sample to remove any debris left over from lysed RBCs. The centrifuge/wash step may be performed several times until the operator is satisfied that the sample is sufficiently clean. Debris, red cell "stroma" can interfere with the detection processes of the typical flow cytometer. The sample now contains WBCs with antibodies bound to cells bearing the complementary surface antigens. The operator re-suspends the sample in a volume of fixative, and then passes the sample through the fluorescence flow cytometry instrument. The fluorescence flow cytometry instrument generates only percentage values for lymphocyte subsets. This is at least partially due to the fact that the numerous manual dilutions and volume reductions performed during the sample preparation steps do not allow the isolation of a precise measurement volume. Thus, the fluorescence flow cytometry instrument identifies the CD4 positive helper-T cells as the percentage of lymphocytes which are both positive for CD3 (T cell marker), and positive for CD4(helper-T marker). The CD4 patient count is then calculated using the following equations: (%lymph/100)X(WBC count) = lymph count (%helper-T in lymph/100) x lymph count = CD4 count The lymph count and the WBC patient count are taken from the hematology instrument, while the "% helper-T cells in lymph" value is taken from the fluorescence instrument after a correction factor is applied based on the flow cytometer mapping of scatter and fluorescence. There are several problems with the current methods of calculating patient count values for lymphocyte subsets. First of all, the calculation is based on values obtained from separate instruments that each have their own calibration and overall separate functions. Additionally, different testing methods may be used on the different instruments. Not only are hematology instrument measurements different from fluorescence instrument measurements, but also there may be variations in results obtained from different hematology instruments. Previous attempts to automate sample preparation in fluorescence cytometry testing have only been partially successful. Such systems still require the operator to perform sample preparation steps such as separating lymphocytes from other peripheral blood cells by density gradient centrifugation, and/or lysing red cells, removing red cell ghosts and cell debris by centrifugation, or preserving the morphology of the remaining white cells by suspending the white cells in an isotonic saline solution containing appropriate fixatives. These operations generally 10 require the operator to manually alter the volume of the sample, thus compromising sample volume precision which can be achieved with automated mechanical volume dispensers. Another problem with the present technique of doing the measurements on separate instruments is that a relatively large volume of patient blood is needed to fill two tubes. This is a problem because of the increased likelihood that the blood will become hemolyzed (red cells destroyed) as larger amounts of blood are drawn. Additionally, it may not be advisable or possible to draw a sufficient amount of blood from certain patients. In leukocyte analyses, it is desirable that all of the RBCs be lysed. Because RBCs outnumber WBCs by about 700 to 1, a small number of unlysed red cells may significantly distort white cell patient counts . Some reagents used to lyse red cells require too lengthy an incubation period to be practical in an automated clinical analyzer. For example, the Tris buffered ammonium chloride solution recommended by K.A. Murihead in Clinical Cytometry, Ann.N.Y. Acd. Sci., vol. 468, pp. 113-127 (1986) takes about 5 to 10 minutes to lyse red cells, which may be impractical for automation. Furthermore, incomplete hemolysis with certain lytic reagents may result in red cell stroma that retain sufficient hemoglobin or particulate matter to generate high background patient counts in automated clinical electro-optical systems. When this occurs, it is usually necessary to remove the WBCs to be analyzed from the red cell stroma by centrifugation, a procedure that is a limiting factor when adapting a reagent system for automation. Some currently used reagent systems require cytochemical staining of fixed WBCs before differential analysis. These systems require timed addition of multiple reagents and incubation periods and may not be generally adaptable for quantifying nucleated red cells or lymphocyte subsets. Furthermore, each step of reagent addition or other 11 manipulation of a blood sample may decrease the precision of the final patient count obtained. The earliest stage of RBC, the nucleated red cell, NRBC, when found in the peripheral blood on conventional hematology analyzers can be confused for a small lymphocyte, since the lysis will not destroy the nucleus of the NRBC. Because of the ratio of RBCs to WBCs, even a relatively small percentage of NRBCs can lead to substantial error in the WBC and lymphocyte count. This may be troublesome in neonate or pediatric samples, in which the presence of NRBCs in peripheral blood is a normal condition. For this reason, the laboratory may do manual slide inspections on some of these samples. Conventional hematology analyzers are only able to flag these samples by noting the spreading out of the usual lymphocyte scatter cluster. The manual inspection results in a count of the number of NRBCs per 100 nucleated cells. This percentage is then used to correct the analyzer WBC count as follows: Corrected WBC count = Analyzer count(1-manual NRBC percentage/100) Clearly the need exists for an accurate automated count of NRBCs. Another important class of immature red blood cells are "reticulocytes" which typically contain detectable amounts of RNA. A manual method of identifying and counting reticulocytes involves precipitating the RNA with a stain. A smear is pulled from the stained blood and manually examined under a microscope. The precipitated RNA appears as intracellular dots or filaments. Reticulocyte % is determined by manually counting 1,000 RBCs under a microscope and dividing those qualifying as reticulocytes by 10. The reticulocyte patient count is derived from the RBC patient count according to the following equation: 12 Reticulocyte count = (RBC count)x(percent reticulocytes) /100 Both the precision and the accuracy of this manual method are less than desirable. There may be considerable variation in identification of reticulocytes as well as variation in counting techniques. Accordingly, there is a need for a cell analysis system that addresses the deficiencies described above. SUMMARY OF THE INVENTION A device for analyzing a whole blood sample is provided. The device, an automated instrument system for distinguishing and differentiating cells in a sample, comprises a conventional hematology analyzer fully integrated with a fluorescence cytometry analyzer. Both analyzers are controlled by a controller which utilizes the results obtained from each analyzer to report test results in absolute, or quantitative terms. Methods are also provided for analyzing a whole blood sample. One such method comprises the steps of automatedly performing both conventional hematology and fluorescence cytometry analysis on a sample. Data is collected and utilized and a quantitative result is reported when appropriate. A further embodiment provides an automated instrument system comprising a sample handler for receiving a sample container and aspirating and dispensing the sample, a sample analyzer that performs both multi-angle light scatter and fluorescence signal detection , and a controller fully integrating the analyzer to enable the instrument system to report quantitative results of both conventional hematological and fluorescence cytometric results. This instrument system is further able to perform these functions, sequentially if necessary, without any intervention from the 13 instrument operator once the operator has selected an array of tests to be performed by the instrument from a menu presented to the operator, and without separating cells from the sample during any phase of the analyses. BRIEF DESCRIPTION OF THE DRAWINGS Figure 1 is a block diagram of a cell analysis system constructed according to teachings of the present invention; Figure 2 is a block diagram of an embodiment of a software subsystem used with the cell analysis system shown in Figure 1; Figure 3 illustrates one embodiment of a sample processing area of the cell analysis system shown in Figure 1; Figure 4 is a more detailed diagram of the sample processing area shown in Figure 3; Figure 4A is front elevational view of a vent/aspirate assembly of the system shown in Figure 4; Figure 4B is a perspective view of an incubation probe assembly used in the system of Figure 4; Figure 5 is illustrates one embodiment of a fluid distribution system of the cell analysis system shown in Figure 1; Figures 6A, 6B, and 6C illustrate the incubation probe of the cell analysis system during deposition, cleaning and aspiration; Figure 7 is a diagram illustrating one embodiment of an aspiration and deposition system of the cell analysis system shown in Figure 1; Figure 8 is a diagram illustrating one embodiment of an incubation transfer system of the cell analysis system shown in Figure 1; 14 Figure 9 is a diagram illustrating one embodiment of a reticulocyte stain delivery system of the cell analysis system shown in Figure 1; Figure 10A is a diagram illustrating one embodiment of an impedance sample delivery system of the cell analysis system shown in Figure 1. In this view, the valves are open, and the sample is being transferred in bulk to the impedance transducer proximity via the pump 220; Figure 10B is a diagram of the impedance sample delivery system shown in Figure 10A. In this view, the valves are closed, and a volume of the sample is being metered to the impedance transducer; Figure 11A is a diagram illustrating one embodiment of an optical sample delivery system of the cell analysis system shown in Figure 1. In this view, the valves are open, and the sample is being transferred in bulk to the flow cell proximity via the pump 232; Figure 11A is a diagram of the optical sample delivery system shown in Figure 11A. In this view, the valves are closed, and a volume of the sample is being metered to the optical flowcell transducer; Figure 12 is a diagram illustrating one embodiment of a HGB sample delivery system of the cell analysis system shown in Figure 1; Figures 13A-13F are timing diagrams illustrating one embodiment of an integrated, automated, hematology/immunology sample processing method of the cell analysis system shown in Figure 1; Figures 14A and 14B are illustrative displays isolating reticulocytes as described in section 4., below; Figure 15 is a diagram illustrating one embodiment of an optical flowcell transducer of the cell analysis system shown in Figure 1; Figure 16 is a sectional view of the optical flowcell shown in Figure 15; 15 Figure 17 is a diagram illustrating one embodiment of an impedance transducer of the cell analysis system of Figure 1; Figure 18 is a diagram illustrating one embodiment of an HGB transducer of the cell analysis system shown in Figure 1; Figure 19 is a diagram illustrating one embodiment of an optics bench of the cell analysis system shown in Figure 1; Figure 20 is a diagram illustrating the forward path collection system of the optics bench shown in Figure 19; Figure 21 is a diagram illustrating the side-scatter collection system of the optics bench shown in Figure 19; Figure 22 is a diagram of the condenser of the optics bench shown in Figure 19; Figure 23 is a diagram of the ray fan from the flowcell to the cathode of the optics bench shown in Figure 19; Figure 24 is a diagram of the PMT lens set of the optics bench shown in Figure 19; Figure 25 is a block diagram illustrating one embodiment of the analyzer module of the cell analysis system shown in Figure 1; Figure 26 is a block diagram illustrating one embodiment of the data acquisition module shown in Figure 25; Figure 27 is a block diagram illustrating further details of the analyzer module shown in Figure 25; Figure 28 is a diagram illustrating the data repositories of the cell analysis system shown in Figure 1; Figures 29 and 30 are state diagrams illustrating one embodiment of the software architecture shown in Figure 28; Figure 31 is a generic elevational view of an apparatus containing a nozzle for introducing a fluid; Figure 32 is a perspective view of the nozzle of Figure 31; Figure 33 is a sectional view of a portion of the nozzle of Figure 32 with conduits shown in Figure 32 being arranged mutually parallelly for clarity; 16 Figure 34 is a sectional view of a portion of the nozzle of Figure 32 illustrating fluid introduction; Figure 35 is a sectional view substantially similar to that of Figure 34 illustrating fluid introduction; Figure 36 is a sectional view substantially similar to that of Figure 35 illustrating fluid introduction; Figure 37 is a schematic diagram of a sample preparation apparatus described herein; Figure 38 is a partially sectioned view of a portion of the apparatus of Figure 37; Figure 39 is a partially sectioned view of another portion of the apparatus of Figure 37; Figures 40A-40C illustrate displayed data for NRBC obtained by an embodiment of the cell analysis system; Figure 41A and 41B illustrate displayed data for NRBC obtained by an embodiment of the. cell analysis system; Figure 42 is a block schematic diagram of the triple trigger circuit described in section 2., below; Figure 43 is an illustration of the laser beam and flow stream configurations and interactions; Figure 44A-44F are side elevational views of portions of one embodiment of the cell analysis system of Figure 1; Figures 45A-45F illustrate displayed data obtained by an embodiment of the cell analysis system; Figure 46 shows an RBC volume histogram obtained with an embodiment of the cell analysis system; Figures 47 and 48 are illustrations of platelet scattergrams obtained with an embodiment of the cell analysis system; Figures 49A and 49B illustrate event divisions detected by an embodiment of the cell analysis system; Figures 50A and 50B show ALL values of high FL3 cells detected by an embodiment of the cell analysis system; 17 Figures 51A and 51B are examples of a dividing line drawn with an embodiment of the cell analysis system between granulocytes and mononuclear cells; Figures 52A and 52B show examples of a histogram and angular dividing line formed by an embodiment of the cell analysis system; Figure 53 illustrates an example of an ALL histogram and dividing lines obtained with an embodiment of the cell analysis system; Figure 54 illustrates a division drawn at a value equal to the mean of IAS values plus 2.5 times a standard deviation of the IAS values by an embodiment of the cell analysis system; Figure 55 shows a division drawn between 1/4 and 3/4 of the distance from lymphocyte-stroma and lymphocyte-monocyte separation lines formed by an embodiment of the cell analysis system; Figure 56 displays a histogram and a dividing line generated by an embodiment of the cell analysis system; Figure 57 displays another histogram and a dividing line generated by an embodiment of the cell analysis system; Figure 58 illustrates an example of a reticulocyte scattergram drawn by an embodiment of the cell analysis system; Figure 59 shows an example of reticulocyte histogram drawn by an embodiment of the cell analysis system; Figures 60A-60F illustrate an example of data processing as described in Example 6; Figures 61A-61G depict illustrations of data accumulated by an embodiment of the cell analysis system; and Figures 62A-62D illustrate a correlation between fractions of lymphocytes that are positive for both CD3 and CD4, positive for both CD3 and CD8, positive for CD19, and positive for CD3 alone. 18 Figures 63A-63F are tables depicting valves and valve functions as described in section 13. F. DETAILED DESCRIPTION OF THE PREFERRED EMBODIMENTS Embodiments of the present invention comprise an analytical instrument system and a method for analyzing fluid samples. Generally, one such automated instrument system includes a conventional hematology analyzer fully integrated with a controller and a fluorescent cytometer. The instrument system is able to distinguish and classify cells, whereby the data collected by the hematology analyzer is automatedly utilized by the fluorescent cytometer to process samples, analyze sample and classify cells within the sample and report quantitative as well as qualitative results. The automated instrument system herein disclosed combines or integrates conventional hematology with fluorescent cytometry on a single analyzer platform. Heretofore, this approach has not been possible. Both methods benefit by this unique combination. Fluorescence information is improved by total automation and absolute concentrations. The hematology information is enhanced by adding fluorescence cytometry to the technology of colorimetry, impedance, and multi-angle light scatter, thereby enabling superior hematology and total automation of tests which currently are done either manually, or on separate and distinct analyzers. For the sake of this disclosure, automation is distinguished in that an operator does not need to intervene in the sample preparation process or analysis of the sample, once the sample, i.e., whole blood, urine, saliva etc., is presented to the instrument. Additionally, all sample handling, processing and analyzing steps and functions are carried out automatedly by the instrument based upon the tests selected by the operator. All data and other 19 information pertaining to each initial test sample is monitored, collected, and processed by the instrument controller. The embodiments of the invention generally comprise an automated hematology analyzer and a flow cytometry analyzer integrated with a controller which monitors and controls the analyzers, collects data from the analyzers and reports a result. Illustrating by example, integration of the analyzers with a controller allows an operator to input data about a whole blood sample into the controller. The operator selects a series of tests to be performed on the sample, generally whole blood, with the aid of the controller. The operator presents the whole blood sample to the integrated analyzers at a centralized sample handling, or processing area. The controller activates the analyzers, allowing the analyzers to automatedly perform analyses on the whole blood sample under the direction of the controller. The controller utilizes data obtained from the analyzers to formulate a result. The controller reports the result to the operator. It is to be noted that no operator action is needed after the whole blood sample is presented to the integrated analyzers. Because the whole blood sample preparation is entirely automated, in a preferred embodiment, conventional hematology tests are done first with the incubated sample tests to follow. Because the analyzers are integrated with the controller, the controller obtains data from both the hematology analyzer and the flow cytometry analyzer. Thus, the controller is able to report a combined patient blood analysis to the operator. In addition absolute concentrations are reportable because of the precision and repeatability of automated dilution, cell preparation and analysis. Human error has all be been eliminated because the instrument system is the only thing to touch the sample once the operator has programmed the instrument and placed the sample on-board. 20 While specific embodiments of the invention will be discussed in detail to clarify understanding, it is to be remembered that other embodiments are also possible. Any desirable combination of elements of the described embodiments is also possible. _ System Overview Figure 1 is a block diagram of a cell analysis system 60. The system 60 includes an analyzer module 64, a data station module 68, and a pneumatic unit 72. The analyzer module 64 is operatively connected to the data station module 68 by a serial data link 76 implementing a HDLC (high level data link) protocol. The pneumatic unit 72 is operatively connected to the analyzer module 64 by a serial data link 84 and a network of tubing 80. The analyzer module 64 aspirates samples, diluent and reagents, dilutes samples, measures and collects data, transmits measured data to the data station module 68, manages reagents, and disposes of waste. An exemplary analyzer module 64 includes its own power supply, impedance transducer, HGB transducer, optical flowcell/transducer (light scattering and fluorescence) , optical detectors, electronics, reagent reservoirs, fluidics system, integrated and fully automated sample processor for both hematology and fluorescent cytometry tests, and any necessary incubation and/or cooling systems. An exemplary analyzer module includes a Motorola 68302-type microcomputer that controls mechanical components of the analyzer 64 and executes the analyzer's flow sequences. The pneumatic unit 72 houses pneumatic sources for moving fluids through the analyzer module 64. The pneumatic unit 72 receives instructions from the analyzer module 64 via that serial data link 84. 21 The data station module 68 provides general controls to the analyzer module 64, converts measured data into meaningful test results, stores measured data and test results, prints reports, and provides bi-directional communication with an off-line host computer (not shown) . An exemplary data station module 68 includes an 80386 or 80486- type microcomputer, color display, 3 1/2 inch disk drive, at least 540 megabyte hard disk, PC-style keyboard, a pointing device, and LAN connections. The data station 68 includes memory, such as a RAM, a ROM, an EPROM, a SRAM and the like, having sufficient software algorithms to manipulate measured data, calculate parameters, and display results in a variety of formats, including histograms, scattergrams, and other multidimensional plots. Fast Lvse Multipurpose Reaαent System The cell analysis system 60 utilizes a multipurpose reagent system suitable for the rapid analysis of nucleated peripheral blood cells, including white blood cells ("WBC") and nucleated red blood cells ("NRBC"). The multipurpose reagent system can substantially completely and rapidly lyse red blood cells, while concurrently substantially preserving white cell morphology and the antigenicity of lymphocyte surface antigens. The multipurpose reagent system is fully described in a U.S. patent application, serial number 08/297,662, entitled "Multipurpose Reagent System For Rapid Lysis Of Whole Blood Samples", filed August 29, 1994 and owned by the assignee of the present application. The entire disclosure of this application is incorporated herein by reference. One embodiment of the multipurpose reagent system comprises from about 3 to about 7 grams per liter of a non- quaternary ammonium salt, from about 0.04 to about 0.1% by weight volume (i.e., grams per 100 ml) of an aliphatic 22 aldehyde with one to four carbons, from about 10 to about 20 mM of a non-phosphate buffer which is substantially inert to the aliphatic aldehyde, and water. The pH of the reagent system is within a pH range of about 5.5 to about 7.5 and the osmolality of the reagent system is between about 160 to 310 (mOsm/L) . The refractive index of the reagent system can be similar to that of saline and should preferably be within the range of about 1.333 to about 1.336. The non-phosphate buffer is inert to the aliphatic aldehyde in that the non- phosphate buffer will not react with the aliphatic aldehyde. Thus, generally, the non-phosphate buffer should not contain a primary amino group. Another embodiment of the multipurpose reagent system comprises about 135 mm ammonium chloride, about 0.075% by volume of formaldehyde, about 20 mM acetate buffer, about 10 mM potassium bicarbonate, and about 0.01% by weight volume (i.e., grams per 100 ml) of saponin and the like. The pH of the reagent system is adjusted to about pH 6.2 and the osmolality of the reagent system is from about 267 to 270 mOsm/L. The multipurpose reagent system is utilized in the automated determination of differential white cell patient counts, nucleated red blood cells, and lymphocyte immunophenotyping. A method for the rapid analysis of nucleated peripheral whole blood cells includes the following steps: mixing the described multipurpose reagent system with an anticoagulated whole blood sample (whereby the blood is diluted 10 to 100 fold) , mixing the diluent-blood mixture at temperatures from about 25°C to 46°C for at least about 10 seconds, and analyzing the nucleated peripheral blood cells with the automated cell analysis system of the present invention. A method of using the multipurpose reagent system in the differential analysis of peripheral white blood cells is a rapid, one-reagent method of concurrently lysing red blood 23 cells and fixing white blood cells, wherein the white cells maintain their light scattering characteristics. In general, the cells flow through an optical view chamber where a photoelectric measuring process records the light absorbed or type of light scattered by each cell at selected angles. A first ingredient of the multipurpose reagent system is a non-quaternary ammonium salt. Preferably, neither di- nor tri-ammonium salts should be used. A variety of mono- ammonium salts, particularly the halogenated salts, can be used from about three to about seven grams per liter, and preferably at about 5 grams per liter. Examples of such non- quaternary ammonium salts include NH 4 X, where X is a halogen. Such a non-quaternary ammonium salt is NH 4 Cl. A second ingredient of the multipurpose reagent system is a short-chain aliphatic aldehyde. Preferably, such aliphatic aldehydes have from one to four carbons. Exemplary aldehydes include formaldehyde and the polymer paraformaldehyde. In proper ratios and concentrations, the aldehyde, in conjunction with the non-quaternary mono- ammonium salt, and the buffer, will rapidly and substantially completely lyse red blood cells. In addition, the aldehyde will fix white blood cells and substantially preserve their membrane integrity. Formaldehyde, or comparable aldehyde, is present in amounts from about 0.04% to about 0.10% by volume, and preferably from about 0.08% to about 0.1% by volume. A third ingredient of the multipurpose reagent system is a non-phosphate buffer that is substantially inert to the aldehyde component of the reagent system. Thus, the buffer must not contain a primary amino group. The buffer should also have an effective buffering capacity between pH of about 6.0 to about 7.5, and an Os olarity of about 230 to about 310 mOsm/L. Examples of effective organic buffers are acetate buffer, succinate buffer, maleate buffer, and citrate buffer. Examples of effective biologic buffers are 2- (N-morpholine) 24 ethane sulfonic acid (MES) buffer, 3- (N-morpholine) propane εulfonic acid (MOPS) buffer, and N- (2-hydroxyethyl) piperazine-N' - (2-ethane sulfonic acid) HEPES buffer. An acetate, or other suitable buffer, will be present in amounts from about 10 mM to about 20 mM concentrations, and preferably at about 20 mM concentration. An optional component of the multipurpose blood diluent is a surface active reagent. The preferred surface active agent is saponin, a plant extract that is available in a commercial grade powder isolated from quillaja tree bark as well as other sources. Although the chemical purity of commercial saponin varies from lot to lot, it is more selective towards red cells than are the quaternary ammonium salts. Saponin, or other surface active reagent, is present in amounts from about 10 to about 200 mg/L, and preferably at about 100 mg/L. Saponin, in concert with the other ingredients of the multipurpose reagent system, substantially completely lyses the red blood cells present in whole blood. The erythrocyte fraction (i.e. red blood cells) of normal blood samples will normally be lysed within about 20 seconds at ambient temperatures. However, hard-to-lyse blood samples (such as blood samples from babies, kidney dialysis patients, multiple myloma patients, diabetics, or patients with uremia, for example) require incubating the blood with the reagent system at temperatures of about 38°C to about 40°C for up to about 20 seconds for complete erythrocyte lysis. Incubation of blood samples with the multipurpose reagent system, even at these slightly elevated temperatures, effectively preserves white cell membrane integrity and retains the antigenicity of lymphocyte surface antigens. In contrast, if saponin is used by itself to lyse the red cells, it should be used at a concentration about 10 to 20 times higher than those discussed above. Such concentrations may compromise the integrity of the white cells and require a rapid quenching of the lytic activity of the reagent to 25 preserve white cell morphology. An advantage of the embodiments of this reagent system is that the combined constituents of the multipurpose reagent system serve to gently fix the white cells at the same time that the red cells are being lysed. Therefore, white cell integrity is substantially preserved even at relatively long incubation periods. In fact, even fragile white cells, such as those seen in chronic lymphocytic leukemia patients, are stabilized in the multipurpose reagent system for incubation periods of up to about 20 minutes. An additional, optional ingredient of the multipurpose reagent system is an alkali salt, preferably a monovalent alkali salt of bicarbonate. Although a monovalent alkali salt of bicarbonate is not an essential component of the diluent, it may be added to the diluent to raise its osmolality without reducing the red cell lysability of the reagent system. Many other compounds, such as sodium chloride, potassium chloride or phosphate buffer, diminish the lysability of the reagent system when used to increase the osmolality of the reagent system. Exemplary monovalent alkali salts of bicarbonate are potassium bicarbonate, sodium bicarbonate, lithium bicarbonate and the like. Potassium bicarbonate, or other alkali bicarbonate salt, can be present in amounts from about 0.005% to about 0.015% by weight volume, and preferably at about 0.01% by weight volume. Yet another optional ingredient of the multipurpose reagent system is a platelet anti-clumping agent. For example, an ethylenediaminetetraacetate (EDTA) salt can be added to the reagent system to reduce platelet aggregation in the sample/reagent mixture. Tetrasodium EDTA, or other EDTA salt, is present in amounts from about 20 to about 200 mgs per liter and preferably at about 100 mgs per liter. A further embodiment of the multipurpose reagent system allows for the quantitative analysis of lymphocyte subpopulations. Lymphocyte subclassification is achieved by 26 mixing fluorochrome-conjugated monoclonal antibodies (directed to specific lymphocyte surface antigens) with whole blood samples before adding the multipurpose reagent system, or blood diluent. The concentration of labeled antibody fractions added to a blood sample depends upon the individual antibody preparation, but is commonly about one-half to one- tenth of the volume of the blood for commercial antibody preparations. After the reagent system is added and the red cells are lysed, the lymphocyte-antibody reaction products can be analyzed on an automated flow cytometric system. There is no need to "separate" the lymphocytes from the lysed cells by centrifugation and washing as is common in the art. The disclosed reagent system does not "quench" fluorescent markers, such as fluorescein isothiocyanate (FITC) or phycoerythrin (PE) , which are used to fluorochrome- label antibodies. Lymphocyte subclassification is a diagnostic tool in the fight against many diseases, such as AIDS. The ability to identify surface markers on blood cell populations may be important when coupled with knowledge of surface components and characteristics of subpopulations of lymphocytes and other white cell fractions such as monocytes and neutrophils. 1_ Nucleated Red Blood Cell Differentiation and Reaσent The cell analysis system 60 utilizes an automated method for simultaneous analysis of WBC/Diff and NRBC in a whole blood sample using a unique triple triggering method with lyse reagent, such as the rapid lyse reagent system described above. This method, claimed in U.S. Patent application Serial No. 08/356,932, entitled "Method For Rapid And Simultaneous Analysis Of Nucleated Red Blood Cells", and filed on December 15, 1994 enables the accurate NRBC counts and WBC/Diff data, simultaneously from a whole blood sample 27 containing NRBC. The entire contents of U.S. Serial No. 08/356,932 is hereby incorporated by reference. An important aspect of the NRBC method is that the signals from debris (both fluorescent and non-fluorescent) are blocked by the triple triggering method and the signals which fall below the ALL trigger but above the FL3 trigger can be identified and counted as NRBC. Therefore, accurate NRBC counts, which are essentially free of contamination from fluorescent nuclear debris, are obtained. Fragile blast cells and dead cells (non-viable) may also be detected utilizing the methods of this invention. In the triple trigger method, it is possible to simultaneously count WBC/Diff and NRBC accurately by mixing the blood sample with a blood diluent which rapidly lyses RBC and preserves WBC, and to which has been added a suitable nuclear stain which will stain naked nuclei of the NRBC. Such a diluent is disclosed above. The diluent/sample mixture is then passed, essentially a cell at a time through an illuminated optical flow cell. This causes the cells to scatter the illuminating light and any stained nuclei present to fluoresce. The scattered and fluorescent light signals are detected by known means and, by using the triple triggering method in conjunction with the processing of the detected signals it is possible to identify and quantify WBC, WBC/Diff and NRBC. The triple trigger method is unique in that the simultaneous analysis of WBC/Diff/NRBC can be carried out automatically, accurately, and rapidly without interference from other cellular debris such as RNA from lysed reticulocytes, Howell Jolly Bodies, reticulated platelets, giant platelets, DNA from WBC and Megakaryocytic fragments, parasites, and RBC fragments. The triple trigger method also permits accurate WBC/Diff analysis in a blood sample that contains NRBC by subtracting signals identified as NRBC from the total WBC signals before 28 WBC/Diff analysis is performed. Only one dye is needed for NRBC staining and the WBC/Diff analysis can be performed by the difference of light scattering characteristics of the WBC subclasses. The NRBC method achieves all of the objectives described above by a unique triple triggering method in the three dimensional space of Axial Light Loss (ALL) , Intermediate Angle Scatter (IAS) and Red Fluorescence (FL3). To accomplish this, one or more detectors 380 (Figures 19, 20 and 21) are preferably placed in the forward light path for measuring forward intermediate angle scattering (IAS) 384 and either small angle forward scattering (SAS) or axial light loss (ALL, also known as forward extinction) 382. ALL is generally the decrease in light energy due to a cell passing in front of a laser beam and being detected by a photodiode. The light loss is generally due to scattering and defined as the decrease in light energy reaching a detector in the path of a laser beam due to the passage of a cell through that beam (generally ALL is detected at an angle of from about 0° to about 1°.) Small angle forward scatter (SAS) , in contrast, is light energy that reaches a detector outside (but within a narrow angle of about 1° to 3°) the incident laser beam due to scattering from a cell passing through the beam. A beam stop is generally provided to keep the laser beam from getting into the detector. ALL measuring systems collect light within the incident cone of laser illumination, while small angle scatter systems collect light outside this cone. In ALL measuring systems, the signal of interest is a negative signal subtracted from the steady state laser signal, whereas in small angle forward scatter measurement the signal is a small positive signal imposed on a very low background light level. Intermediate angle forward scattering (IAS) is similar to small angle forward scattering, except the light is scattered at a larger angle from the incident laser beam. More specifically, IAS relates 29 to light scattered in a ring between about 3° and 10° away from the incident or center line of a laser beam. In a preferred embodiment, ALL is collected in the angles less than about 0.3° horizontally and less than about 1.2° vertically from the laser axis, and IAS is collected at angles between about 3° and 10° from the laser axis. Another technical advantage of the disclosed system is that it requires much lower concentration of the dye to effectively and rapidly stain NRBC for accurate detection and counting because of complete lysis of the cytoplasm of NRBC making their nuclei more accessible to the stain. This condition permits high signal to noise (S/N) ratio, greater than 100, in NRBC detection. The concentration of a vital dye required this system to rapidly perform the simultaneous analysis of WBC/Diff/NRBC is only 1 to 2 μg/ml which is at least 50 fold less than that in the previous art. Vital stains (nuclear stains which stain only dead or damaged cells) that can be used in the present invention can be any vital stain with relatively high extinction coefficient and low fluorescence intensity when they are not bound to nucleic acid. The spectral characteristics, i.e. Extinction (EX) max. (n )/Emission (EM) max. (nm) , of the vital dyes must be compatible with the laser light source used in the system. The following characteristics are desired for the vital stains for the disclosed system: High extinction coefficient High quantum yield High binding affinity to nucleic acid Low fluorescence when it is not bound to nucleic acid Light source compatibility of Spectral Characteristics, (e.g. EX max.-488 nm and EM max. - 630 nm with an Argon laser light source.) 30 There are a number of nuclear dyes qualified for use in the disclosed system with appropriate light source. Some of the commercially available dyes that can be used in the disclosed system are YOYO-1, YOYO-3, TOTO-1, TOTO-3, BO-PRO- 1, YO-PRO-1, TO-PRO-1, and many more. It is known to those who are familiar in the art that the dyes with different EX max. can be excited with appropriate light source such as He- Ne, Xenon or Mercury lamps. Qualified dyes which can be used with an Argon laser which are also commercially available are Propidium iodide (PI), ethidium bromide (EBr) , ethidium homodimer-1 (EthD-1), ethidium homodimer-2 (EthD-2) or diethylene triamine (DTA) . In one application of the NRBC method, the vital stain used is PI A portion of a whole blood sample, about 25 microliters, is deposited by means of a sample aspiration probe into the WBC cup 138 which contains about 850 microliters of an isotonic lysing reagent. A lysing reagent described above is used to lyse the erythrocyte fraction of the blood sample and to lyse the cytoplasm of NRBC to expose the nuclei of any NRBC present. This reagent system is characterized in that it embodies a one reagent/one step process that achieves multipurpose goals. This reagent is gentle enough to preserve the morphology of all fragile white cells, and at the same time efficiently lyse all of the red cells. Both of these goals are accomplished even in hemaglobinophathic samples, which may require that the lysing time be extended. No matter what the formulation of the lyse utilized with the triple trigger method, the reagent will additionally contain, or be combined with, a small concentration of a vital nuclear stain which effectively labels any NRBC which might be present in the peripheral blood. Preferably, for use with the herein referenced analyzer, the lysis chemistry will be configured such that the refractive index matches that of a sheath solution to substantially less than 0.1%. 31 The mixture of lyse reagent and sample will normally remain in the WBC cup 138 only for about 11 seconds. There it is lysed and mixed at 42°C ± 3°C. At this point, the contents of the WBC cup are piped directly to an optical flowcell 170 for detection. The measurement process begins as the cells stream passes through the flowcell 170, having been diluted with the addition of lyse so that the cells pass through the laser illuminated volume single file, in a laminar flowing sample stream surrounded by diluent/sheath solution. At this point the presence of a cell is detected by a compound photodiode 380 detecting axial light loss (ALL) and intermediate angle scatter (IAS) , photomultiplier tube which detects red fluorescence, and a unique triple trigger circuit, shown in Figure 2, in the three dimensional feature space of ALL, IAS, and FL3 (red fluorescence) . The triple trigger circuit qualifies signals for digitization using AND/OR logic. A qualified signal must be greater than the IAS trigger, while at the same time it must be greater than either the ALL trigger or the FL3 trigger. The combination of this unique triggering circuit, and the lysing properties which include a balanced fixative, allow the exposed NRBC nuclei to be rapidly stained, and clearly and non ambiguously counted and excluded from the WBC differential cell count without the usual interference from background, both fluorescent and non-fluorescent, such as DNA fragments, RBC stroma, and platelets. When cells, thus triggered, pass through the aforementioned illuminated volume, pulses are generated at detectors 380, 400, 401 and 404. The amplitudes of these pulses are then filtered, amplified, digitized, and stored in list mode in the corresponding five dimensional feature space of ALL, IAS, FL3, PSS (polarized side scatter), and DSS (depolarized side scatter) . The normal counting time through flowcell 170 is 10 seconds. At the flow rate and dilution 32 ratio described above, with a normal patient WBC count of 7000 cells per microliter of blood volume, the resulting event count rate would be 5000. In low count samples, this counting time can be automatically extended in order to improve the statistics of the measurement. At the conclusion of the measurement time, the sample stream is piped to waste, and probe is cleaned and dried and prepared to process a subsequent sample. Algorithms are then applied to the list mode data of the aforementioned feature space of ALL, IAS, FL3 , PSS, and DSS, and the following cell types are enumerated and/or flagged within less than 30 seconds of processing time: CELL TYPES ENUMERATED PERCENTAGES FLAGGED OR ENUMERATED White Cell concentration (WBC) Neutrophil concentration %N Of WBC Lymphocyte concentration %LYMPH of WBC Monocyte concentration %MONO Of WBC Eosinophil concentration % EOS Of WBC Basophil concentration %BASO of WBC NRBC %NRBC of WBC Band concentration (BAND) Blast concentration (BLST) Immature gran. cone. (IG) Varian -lymph cone. (VARL) ALL and IAS signals are detected and collected for the WBC/Diff analysis and FL3 signals from stained NRBC nuclei are collected for NRBC analysis, as will be described below. The triple trigger circuit, shown in Figure 42, qualifies these signals for digitization using AND/OR logic. To be qualified a signal must be greater than the IAS trigger, while at the same time it must be greater than either the ALL trigger or the FL3 trigger. 33 The various components and generated or utilized signals identified in Figure 42 correspond to the following labels: 900 - ALL Voltage Comparator 902 - ALL Signal 904 - ALL Threshold Voltage (Vthl) 906 - ALL Voltage Comparator Output 910 - FL3 Signal 912 - FL3 Threshold Voltage (Vth2) 914 - FL3 Voltage Comparator 916 - FL3 Voltage Comparator Output 918 - IAS Signal 920 - IAS Threshold Voltage (Vth3) 922 - IAS Voltage Comparator 924 - IAS Voltage Comparator Output 926 - OR Gate 928 - OR Gate Output 930 - AND Gate 932 - Valid Trigger Output Real time signals from their respective channels are present at the inputs of the voltage comparators. Voltage comparators 900, 914 and 922 function by comparing the "+ inputs" (902, 910 and 918) to the "- inputs" (904, 912 and 920) to resultant outputs (906, 916, 924) . If the "+ input" is of a higher voltage than the "- input" the output will be high. If the "+ input" is of a lower voltage than the "- input" the output will be low. The threshold voltages are independent voltages which are determined by system parameters. The outputs of comparators 900 and 914 are inputs to OR gate 926 to give resultant OR gate output 928. The OR gate functions by comparing its inputs. The output will be high if either, or both, inputs are high. 34 The output of the OR gate 928 and the output of comparators 922 and 924 are inputs to AND gate 930. The AND gate functions by comparing its inputs to derive its output 932 which is also the valid trigger output. The output will be high only if both inputs are high. The valid trigger output 932 will only be high if the IAS signal 918 is greater than its threshold voltage 920, and either or both, the ALL signal 902 is greater than its threshold voltage 904 or the FL3 signal 910 is greater than its threshold voltage 912. Using the above triggering circuit, the NRBCs form a unique cluster in the aforementioned three dimensional space, see Figures 40A-40C and 41A and 41B, which can be easily counted during the Optical WBC Differential analysis, and exclude non-ambiguously from the WBC count. Thus, a count of NRBC per 100 WBC, and an absolute NRBC per μl of patient blood is reported. Consequently, NRBC are subtracted from total WBC counts permitting accurate total WBC and Differential analysis in the presence of NRBC in a blood sample. Background noise, both fluorescent and non- fluorescent, from DNA fragments, RBC stroma, platelets, Howell-Jolly Bodies, Basophilic Stippling, RNA from lysed reticulocytes and DNA from WBC and Megakaryocytic fragments are substantially eliminated. Stained NRBC nuclei are separated from the various background noise signals via the disclosed triple-triggering process (on ALL, IAS and FL3) and only the FL3+ signals from NRBC nuclei above the FL3 trigger on the ALL vs. FL3 dot plot are counted as NRBC (Figures 40A- 40C and 41A and 41B) . Reticulocyte Method and Reaσent In one aspect of the cell analysis system 60 a stable, aqueous reagent composition is utilized for the detection and enumeration of reticulocytes. This reagent comprises: an 35 unsymmetrical cyanine dye capable of staining reticulocytes, from about 20 mM to about 50 mM of a buffer selected from the group consisting of Imidazole buffer, 4- (2-Hydroxyethyl) -1-peperazineethane-sulfonic acid ("Hepes") buffer, Bis (2-Hydroxyethyl)-1-piperazineethane-sulfonic acid ("Bis-Tris") buffer and Tris Hydroxymethyl Aminomethane ("Tris") buffer; a pH from about 6.0 to about 8.0; an osmolarity adjusted to about 230 to about 340 mOsm/L with a mono, or di, valent alkali salt; and a non-ionic surfactant (from about 5 mg/dl to about 1.0 g/dl depending on the surfactant) which facilitates the membrane permeation and stabilizes the cyanine dyes in an aqueous isotonic solution. Preferably the dyes are cyclic substituted and exhibit enhanced fluorescence upon binding with DNA or RNA. Even more preferably, the reagent comprises from about 0.1 μg/ml to about 0.3 μg/ml of a cyclic substituted, unsymmetrical cyanine dye. The methods for the rapid and continuous detection and enumeration of reticulocytes and CBC differentials, utilizing the present inventive reagent system. Such methods are distinct due to the particular absence of the need to provide for a separate incubation step. The minimal, 10 to 60 second incubation period is all that is necessary. The disclosed method and reagent are the subject of U.S. Patent application Serial Number 08/426,408, entitled "Composition And Method For The Rapid Analysis Of Reticulocytes", filed on April 21, 1995. This application is owned by the assignee of the present invention and the entire contents of that application are herein incorporated by reference. The method allows the enumeration of reticulocytes from a whole blood sample while simultaneously differentiating a separate aliquot of the sample to obtain a complete blood cell ("CBC") analysis. This method comprises, directing one or more aliquots of the sample to various positions within an 36 automated analyzer for analysis and differentiation, while a reticulocyte aliquot of the sample is combined with a staining reagent. The combined reagent/reticulocyte aliquot is then directed to an optical flow cell 170 of the automated analyzer 60. Thereafter the reagent/reticulocyte aliquot is passed through an illuminated sensing zone 300 essentially one cell at a time to cause fluorescence and scattered light events. These events are detected and the number of reticulocytes present in said sample are determined therefrom. The unsymmetrical dyes usable with the reagent system generally have the following characteristics: 1. Absorption Maxima : 488 +20 nm 2. High nucleic acid binding affinity 3. High quantum yield : ≥O.1 4. Molar Extinction Coefficient: >10,000 5. Fluorescence Enhancement upon binding to RNA or DNA: >20 6. Membrane Permeation Rate: <2 minutes Typically, the dyes utilized in the disclosed aqueous reagent and reticulocyte enumerating methods are highly unstable in aqueous environments. However the disclosed reagent formulation provides extended stability and shelf- life to the finished reagent. A preferred embodiment of the reagent system comprises from about 0.05 μg/ml to about 0.5 μg/ml of Sybr 11, a proprietary dye sold by Molecular Probes, Inc. (Eugene, OR), from about 20 mM to about 50 mM Imidazole buffer, and from about 5 mg/dl to about 20 mg/dl of N,N-bis[3-D-Glucon-amidopropyl] cholamide ("BIGCHAP") , from about 0.02 % to about 0.05 5 % Proclin® 300 (5-chloro-2-methyl-4-isothiazoline-3-one + 37 2-methyl-4-isothiazoline-3-one) . The pH is adjusted to from about 6.8 to about 7.2 with IN HCl and the Osmolarity adjusted with NaCl from about 270 to about 310 mOsm/L. A main ingredient of the reagent system is the dye. One such class of dyes are unsymmetrical cyanine dyes such as those disclosed in W094/24213, "CYCLIC-SUBSTITUTED UNSYMMETRIC DYES", and herein incorporated by reference. Additionally, the dyes utilized in this invention exhibit enhanced fluorescence upon binding with DNA or RNA. Such useful dyes must also have high binding affinity to RNA and DNA and a high quantum yield. It is anticipated that a variety of unsymmetrical cyanine dyes which exhibit the characteristics described and claimed herein can be used. Some of the examples of such dyes include, but are not limited to Sybr 11, Sybr 14, Sybr 16, also obtained from Molecular Probes, Inc. (Eugene, OR) ("MPI") . Other unsymmetrical cyanine dyes such as Syto 12, also sourced from MPI, are also useful in practicing the present invention. Syto 12 is believed to be a neutral, unsymmetrical cyanine dye comprising a substituted benzazolium ring system linked to a methine bridge to a pyridinic or quinoline ring system. A further ingredient of the reagent system is a buffer whose pKa is from about 6.0 to about 8.0 and is capable of maintaining the required (for staining RNA or DNA) concentration of the cyanine dye in an aqueous solution in an extended period of time. Such buffers should not react with the cyanine dyes or the non-ionic surfactants used in the practice of this invention to stabilize the dye. Exemplary buffers include Imidazole, Hepes, Bis-Tris, and Tris. Another ingredient of the reagent system is a non-ionic surfactant. Depending upon the surfactant, or combination of non-ionic surfactants, that are use, the concentration should be from about 5 mg/dl to about 1 g/dl. The surfactant (s) appear to enhance the rate of the cyanine dye permeation through the cell membrane (within 30 seconds) . In addition, 38 the solubility and the stability of the cyanine dyes in an isotonic aqueous solution are enhanced by the surfactant. Such surfactant (s) should not, however, precipitate or react with the cyanine dyes or lyse RBCs, even at the low concentrations. Examples of such surfactants are, but are not limited to, BIGCHAP, n-Dodecyl-D-Maltoside, Polyoxypropylene-polyoxyethylene block copolymer ("Pluronic® F127"), n-Tetradecyl-D-Maltoside, Decanoyl-N-methyl-glucamide, n-Dodecyl-D-glucopyranoside and n-Decyl-D-glucopyranoside. Yet another ingredient of the reagent system is a mono-, or di-, valent alkali salt to adjust the osmolarity of the reagent from about 230 mOsm/L to about 340 mOsm/L to prevent the lysis of red cells, including the reticulocytes, or the white cells. Such salts should not react with the either the cyanine dyes or precipitate in solution. Examples of such salts include NaCl, KCl, LiCl, CaCl 2 , MgCl 2 , ZnCl 2 and others. An optional ingredient, is a preservative to prevent microbial growth in the reagent. Such a preservative should not change the light scattering or fluorescent emission properties of the cells, or stained cells. Examples of such preservatives include Proclin® 300, Proclin® 150, sodium azide and others. Generally, however, a method for practicing the present invention comprises the mixing of a whole blood sample with a reagent to stain the RNA of any reticulocytes present, flowing the mixture, essentially one cell at a time, through an illuminated optical flow cell, detecting the light scattered and fluorescence emitted therefrom and determining the amount of reticulocytes present in the sample without subjecting the sample/reagent mixture to a separate incubation step or period. In order to analyze a whole blood sample for the percentage as well as the absolute counts of reticulocytes on 39 the multi-parameter hematology analyzer described above, about 18.75 μl of a whole blood sample is deposited by means of a sample aspiration probe into the RBC cup 134 which contains about 7856 μl of a diluent/sheath solution (an isotonic saline) and the fluids are mixed. The diluted sample is then transported to a sheathed impedance aperture 174 to electronically determine the absolute RBC counts of the sample. In the mean time, about 200 μl of the diluted sample is transferred into Retic cup 136 which contains 600μl of the disclosed reagent, where it is mixed. The prepared (mixed) sample is then transported to the sheathed optical flow cell 170 for detection. The measurement process begins as the cell stream passes through the flow cell essentially one cell at a time, in a laminar flowing sample stream surrounded by a diluent-sheath solution, disclosed hereinafter. At this point, and as shown in the two dimensional feature space of IAS and FLl of the cytogram of Figures 14A and B, the presence of a cell is detected by an intermediate angle scatter photo-diode 380 which detects light in a 3° to 10° cone, and a photomultiplier tube ("PMT") 400 which detects green fluorescence, FLl. When cells pass through the aforementioned illuminated volume, pulses are generated and measured by these detectors. The amplitudes of these pulses are then filtered, amplified, digitized, and stored in list mode in the corresponding two dimensional feature space of IAS and FLl. The cells are counted for 8 seconds. At the flow rate and the dilution ratio described above, with a normal subject RBC counts of 5 millions per microliter of blood volume, the resulting event count rate would be 5950 per second. Algorithms are then applied to the list mode data of the aforementioned feature space of IAS and FLl and the following parameters are measured within 20 seconds of computational time: 40 1. RBC gate: WBCs and platelets are excluded by gating the RBC population, including reticulocytes, but excluding WBCs and platelets. 2. The percent of reticulocytes: The gated RBC population is reanalyzed according to the size of their FLl signals. A log fit is applied to the FLl histogram to define the region which belongs to mature RBCs, and the cells whose FLl signals fall above the region are labeled as reticulocytes. Reticulocyte % is computed by dividing the counts of reticulocytes by the total RBC counts. 3. The absolute reticulocyte counts: Obtained by multiplying the percent of reticulocytes by absolute RBC counts of the sample from the CBC mode. 4. Reticulocyte Maturity Index ("RMI") : RMI is expressed as the percent of reticulocytes whose FLl signals are more than one (1) standard deviation ("S.D.") above the mean fluorescence of a normal reticulocyte population. Such a description is merely for convenience and by no means is the expression of RMI of the present invention limited to only the algorithms discussed herein. 5— Alternate Reticulocyte Stain & Analysis The disclosed alternate class of reticulocyte stains is stable to light at ambient temperature, possesses improved fluorescence enhancement of the bound stain over the unbound stain, exhibits RNA selectivity over DNA, enables improved gating of the reticulocyte cells, provides more rapid permeation of cell membranes, and possesses an optical absorption maximum closely aligned with the emission maximum of an argon laser (about 488nm) . 41 A preferred stain belongs to a class of molecules having the general structural formula: »1 wherein: x = O, S, Se, or C(CH 3 ) 2 2 Rj = alkyl having from 1-6 carbons R 2 = alkyl having from 1-6 carbons R 3 = fused benzene, alkyl (having 1-6 carbons) methoxy or hydrogen R 4 = alkyl having 1-6 carbons, methoxy or hydrogen n = zero or an integer from 1-6 This class of stains will be referred to herein as "2,2'-dyes." The preferred embodiment of the reticulocyte stain shown above is where: Preferably, x is sulphur (S) Preferably, R 3 and R 4 are both hydrogen Preferably, n = 0 and Preferably, Ri and R 2 are both ethyl. This dye is listed in the Koch-light Biochemical Catalogue 1985, and 1988/89 at page 53 in the form of an iodide salt, and named 1,3 ' -diethyl-2,2 ' -quinolylthiacyanine iodide. It is also listed in the Nippon Kankoh-Shikiso Kenkyusho catalogue at page 7. For convenience hereinafter, we shall refer to this specific dye, the particularly 42 preferred embodiment, as "DE22QTC", and to the general class of dyes, as defined above, as "2,2 '-dyes". Generally, these dyes are used in the form of their salts, iodides being particularly convenient. As used in this specification, all references to these dyes should be understood as including such dyes in salt form. In one embodiment a reagent useful for staining RNA- containing material which is comprised of a 2,2 ' -dye which is capable of staining RNA-containing material. Another embodiment a method for staining RNA-containing material wherein an aqueous staining solution of a 2,2'-dye which is capable of staining RNA-containing material is placed in contact with an RNA-containing material for a period of time adequate to enable the staining solution dye to penetrate the RNA-containing material. Another embodiment provides a method for enumeration of reticulocytes in a whole blood sample using flow cytometry wherein an aqueous staining solution of a 2,2 '-dye which is capable of staining RNA-containing material is placed in contact with an RNA-containing material for a period of time adequate to enable the staining solution dye equilibrate with the RNA-containing material. The stained sample is then directed through the optical sensing zone of a flow cytometry instrument and illuminated once within the optical sensing zone with an incident light beam. The fluorescence of the reticulocytes in sample solution are then measured as they pass through the optical sensing zone. An important advantage of the 2,2 '-dyes is that they appear to be more stable in aqueous solution than thiazole orange. This has been examined using samples of DE22QTC, thiazole orange (both at O.lμg/ml in isotonic diluent) and "Retic-COUNT" stored both at 4°C in the dark and in room light at ambient temperature (about 25°C) over a period of 5 days. 43 The 2,2 '-dyes exhibit a significantly greater fluorescence when RNA rather than DNA is the binding substance, on a weight-for-weight basis DE22QTC allows easy gating of red blood cells away from platelets and white cells using a strategy not previously adopted for reticulocyte analysis. The dye, by its significant staining of platelets over the 30 minute period of a typical test and its expected staining of white cells in the same period,provides significant differentiation of both groups of cells from all the red cells in a plot of fluorescence versus forward scatter. The rapid staining is a property not shown by many other dyes; e.g. thiazole orange does not stain platelets significantly over the 30 minute time period although after several hours, staining does occur. DE22QTC, when bound to RNA or DNA, has an absorption maximum of almost precisely 488nm, and a Stokes shift of about 33nm. This dye therefore can be used with maximum advantage with the standard argon ion laser. Moreover, the readily-available optical filters used for fluorescein-based assays can be used and the instrument need not be modified. The 2,2'-dyes can be used in any conventional assay technique which requires the staining of reticulocytes with a fluorescent marker. In particular, these dyes can be used in any assay for which thiazole orange is currently recommended, such as reticulocyte detection and enumeration in an argon ion laser flow cytometer. When these class of dyes are utilized to detect and differentiate reticulocytes an incubation site and associated temperature controls and sample handlers must be provided for within the instrument and operatively connected to the analyzer to maintain the automation of the inventive instrument system disclosed herein. HGB Reaσent 44 The hemoglobin ("HGB") reagent discussed herein is disclosed in U.S. Patent Application, Serial Number 08/212,626, "CYANIDE-FREE REAGENT AND METHOD FOR THE DETERMINATION OF HEMOGLOBIN", filed on March 11, 1994. This application is co-owned by the owner of the present application, and the complete disclosure thereof is incorporated herein by reference. A cyanide-free reagent must be able to quickly lyse the erythrocytes and rapidly complex with the hemoglobin so that a detectable chromogenic structure is formed for detection and measurement. The disclosed reagent is stable for many weeks and is particularly advantageous because the resulting chromogen appears to be free of interference from other blood components and can be measured at wavelengths in the spectral range of automated hematology instruments already in the field. For comparison purposes, the cyan met hemoglobin method typically measures absorbance at 540 nm. A reddish brown chromogen can be formed according to the present invention which has an absorption maximum at about 544 nm. A HGB reagent found to be useful in the present invention is an aqueous solution of a ligand-forming compound such as imidazole and imidazole derivatives. The ligand-forming compound is present at concentrations of 0.1M to 2.0M Imidazole, from the present reagent, ligates with the hemoglobin which is released from the erythrocytes in the sample. Other ligand-forming compounds useful in the present invention include N-hydroxyacetamide, N-hydroxyl amine, pyridine, oxazole, thiazole, pyrazole, pyrimidine, purine, quinoline, and isoquinoline. Anions which can bind the oxidized iron he e include cyanate, fluoride, azide, nitrite, hydroxide, acetate, and formate; acceptable salts of these anions include sodium, potassium, ammonium, and the like. The reagent further contains a surfactant with a strong erythrolytic capability. Lauryl dimethylamine oxide (Ammonix L.O.) [Stepan Chemical Company, Northfield, Illinois], and 45 octylphenoxy polyethoxyethanol (Triton X 100) or other strong detergents may be used as the surfactant component of the lysing reagent. The surfactant should be present at concentrations from about 0.1% to about 1.0% (w/v) . The pH of the reagent should be adjusted to between 11 and 14, preferably 12.5. Monovalent bases such as sodium hydroxide and potassium hydroxide may be utilized for pH adjustment. According to the method for determining HGB (described in more detail later in section 8 E. and Example 2 herein) , the lysing reagent is mixed with a whole blood sample in the ratio of approximately 50 - 1000:1 reagent to blood. The sample and reagent can be rapidly mixed to achieve erythrolysis and conversion of hemoglobin to the chromogen. The sample and reagent mixture may then be presented to an absorbance spectrophotometer where the optical density of the chromogen formed is measured. When the ligand is imidazole the measurement can be made between 540 nm and 550 nm. The total hemoglobin concentration in the sample is related to the optical density of the converted chromogen. 1_ Isotonic Diluen -Sheath Reaσent The cell analysis system 60 of the present invention utilizes a buffered isotonic solution with nonionic surfactant suitable for minimizing surface tension of the sheath stream and for the rapid analysis of red blood cells and platelets. The reagent system can substantially completely reduce bubble formation and enhance a smooth flow of the sheath stream for both impedance and optical flow cells. The diluent-sheath reagent disclosed below also improves the separation of microcytic red blood cells from platelets, while concurrently substantially preserving the morphology of both red blood cell and platelet populations for accurate and precise measurement of counts and volume. 46 In one embodiment from about 10 mM to about 50 mM of a buffered isotonic salt solution whose pKa is from about 6.0 to about 8.0 , is capable of maintaining the pH of the reagent within a pH range of from about 7.0 to about 7.6, a monovalent salt of EDTA from about 0.1 gram per liter to about 0.4 gram per liter, to prevent platelet clumps is present, a monovalent salt sufficient to adjust Osmolarity of the reagent from about 270 mOsm/L to about 320 mOsm/L is also utilized, as is a nonionic surfactant which reduces surface tension, prevent bubble formation and enhance the separation of microcytic red blood cells from platelets, selected from the group n-Dodecyl -D-Maltoside, n-Tetradecyl -D-Maltoside, Decanoyl-N-methyl-glucamide, n-Dodecyl -D-glucopyranoside and n-Decyl -D-glucopyranoside, and finally a preservative is present to prevent microbial growth and deionized water. In a preferred embodiment, the reagent comprises from about 2.45 grams per liter sodium phosphate, dibasic, about 0.40 grams per liter potassium phosphate, monobasic, about 0.20 grams of disodium EDTA per liter, about 8.05 grams of sodium chloride per liter, about 0.40 grams of potassium chloride per liter, about 0.012 grams per liter of n-Dodecyl -D-Maltoside and about 0.03 grams per liter of proclin 300, pH adjusted to 7.4 and osmolarity adjusted to 315 mOsm/L. In the most preferred embodiment, 17.5 microliter of a blood sample is rapidly mixed with 7400 microliter of the diluent sheath reagent (1:420 dilution), and 0.5 microliters of the diluted sample is passed through a hydrodynamically focused (sheathed) impedance transducer for 12 seconds for red blood cell counts and volume measurement as well as platelet counts and 2.5 microliters of the diluted sample is passed through a sheathed optical flow cell for 6 seconds for accurate and precise platelet count determination. Noise signals from fragments of fragile abnormal cells are excluded from the optical platelet counts by bracketing the platelet population accurately by the platelet algorithm of the cell 47 analysis system 60. Typical examples of red blood cell and platelet distribution of normal and abnormal blood samples of the cell analysis system 60 are presented in Figures 45A-45F and Figures 46-47. £L- Analyzer Module £_. Automated Sample Transport The analyzer 64 may be provided with an autoloader (not shown) for automatically transporting sample tubes to the analyzer 64 for processing. Such an autoloader may include a holder which retains up to about 100 sample tubes of various sizes. A presenter which sequentially presents the sample tubes to the analyzer 64 for aspiration is operatively connected with the autoloader. A mixer which mixes the sample just before sample aspiration may also operatively associated with the autoloader. A bar code reader for reading the bar code label on each tube can also operatively be associated with the autoloader and operatively connected to the system controller to input sample information into the system controller. Automated Sample Processing and Measurement Figure 3 illustrates a top view of one embodiment of an automated sample processing area 110 for use in the cell analysis system 60 shown in Figure 1. The processing area 110 is part of the analyzer 64 portion of the cell analysis system 60. The processing area 110 includes a sample cup area 114 and an incubation area 118. As shown in Figure 3, the incubation area 118 includes a thermostated block 120 for housing reagent modules 122 and subset/phenotyping incubation trays 124. The thermostated block 120 includes a temperature controller (not shown) for 48 heating and/or cooling the incubation trays 124 and reagent modules 122 disposed on the thermostated block 120. The reagent modules 122 include wells 128 for holding a volume of antibody reagent. In the illustrated embodiment, each reagent module 122 has a housing with a reagent well 128, preferably six in number, packaged with a particular panel of reagents. The reagents in each panel are selected so that, for the tests associated with each panel, an approximately equal amount of reagent is used from each well 128. If less than six reagents are required for the test associated with the panel, the excess wells 128 are covered by a plug (not shown) . Each reagent module 122 is also fitted with a memory, such as a non-volatile RAM and the like, to store module ID and usage information. The reagent modules 122 are preferably keyed so that they may be seated in an opening (not shown) , located in the thermostated block 120, in a predefined orientation. This allows the central processing unit (CPU) of the analyzer 64 to store the location and, from the usage information, the volume of the contents of each well 128 in each reagent module 122. The subset/phenotyping incubation trays 124 are, in the illustrated embodiment, substantially rectangular in shape, and have several rows of incubation sites 132 formed thereon. Each incubation site 132 is capable of holding a blood sample and antibody mixture that is incubated in preparation for immuno/phenotype testing. The subset/phenotyping trays 124 are removably seated in openings (not shown) in the thermostated block 120 such that their temperatures are controlled by the temperature controller of the thermostated block 120. The sample cup area 114 includes a row of sample cups. In a preferred embodiment, these cups include an "RBC" cup 134, a "RETIC" cup 136, a "WBC" cup 138, a "transfer" cup 140, an "HGB" cup 142, and "wash" cup 144. Each sample cup is open at the top for accepting a fluid. The bottoms of the 49 RBC cup 134, RETIC cup 136, WBC cup 138, and HGB cup 142 are connected to a tubing network 182 (shown in Figure 5) for transporting samples to the measurement flowcells/transducers. It is also possible to deposit fluids, such as diluent, reagent, lyse, and the like, into the cups via the tubing network 182. This may be accomplished by connecting the tubing network 182 to ports (not shown) formed in the walls of the various cups. The positioning of these ports and their respective inside diameters allows mixing to take place as a result of the fluid motion caused by the delivery mechanism, which is preferably a dilution syringe coupled to the tubing network 182. RBCs are lysed in the WBC cup 138 using, for example, the fast lyse, multipurpose reagent system discussed previously. Accordingly, the WBC cup 138 includes a temperature controller or heater for warming the fast lyse and sample mixture, preferably to about 40°C. Additionally, the WBC cup 138 includes a vortexer 610 (Figure 37) for providing motor-driven vortex mixing of the lyse and whole blood combination. For the sake of clarity, an exemplary embodiment of the sample preparation is discussed with reference to Figures 37 through 39. One embodiment illustrated in Figure 37 provides an apparatus 610. The apparatus 10 generally includes a mixing apparatus 612, a fluid dispenser 614 and a mix controller 616. The mixing apparatus is further described and claimed in U.S. Patent application, Serial No. 08/356,412, filed on December 15, 1994, the entire contains thereof hereby incorporated by reference. The mixing apparatus 612 is operatively associated with the fluid dispenser 614 such that the fluid dispenser 614 introduces a first fluid, such as a whole blood sample, a cell suspension and the like, to the mixing apparatus 612. 50 The fluid dispenser 614 is electrically connected with the mix controller 616 by conductor 618 so that the mix controller 616 monitors and coordinates operation of the fluid dispenser 614. The mix controller 616 is electrically connected with a source 620 of electrical energy by conduit 622 for supplying the mix controller 616 with electrical energy. In an exemplary embodiment, the fluid dispenser 614 is a pipettor operatively associated with a suitable source of fluid to be prepared by the apparatus 610. The mix controller 616 may be a computer having memory containing and running appropriate routines to control operation of the apparatus 610. The illustrated embodiment of the mixing apparatus 612 comprises a first or inner housing 624, a second or outer housing 626 and a joining member 627. The inner housing 624 and the outer housing 626 are substantially cylindrical and include open ends to facilitate introduction of fluid from the fluid dispenser 614 into an interior 628 of the inner housing 624. The inner housing 624 and the outer housing 626 are disposed substantially coaxially with the inner housing 624 being disposed substantially within the outer housing 626. The joining member 627, illustrated in Figures 37 and 39, substantially surrounds and operatively connects the open ends of the inner member 624 and the outer member 626. The joining member 627 includes a first substantially annular projection 630 which mates with a substantially annular notch 632 on the inner member 624 adjacent its open end and a second substantially annular projection 634 which mates with a substantially annular notch 636 on the outer member 626 adjacent its open end. To facilitate retention of the projection 630 within the notch 632, an O-ring 638 is provided that substantially surrounds an outer diameter surface of the substantially annular projection 630. The O- ring 638 performs essentially as a spring clamp for 51 substantially securing the projection 630 within the notch 632. The O-ring 38 maintains the open end of the inner housing 624 substantially stationary with respect to the open end of the outer housing 626 during operation of the apparatus 610. The inner housing 624 includes structures for introducing fluid into and removing fluid from the interior 628 of the inner housing 624. Specifically, the inner housing 624 includes a fluid inlet 642 and a fluid outlet 644. In one embodiment, the fluid inlet 642 and the fluid outlet 644 may be made from stainless steel tubing. In another embodiment, the fluid inlet 642 may comprise a conduit, such as a coil and the like, disposed adjacent the inner housing 624 such that thermal energy can be transferred from the inner housing 624 to the conduit thereby applying thermal energy to the fluid prior to introduction to the interior 628 of the inner housing 624. The fluid inlet 642, in an exemplary embodiment, is offset axially about 1.43 inches from a distal end of the inner housing 624. The fluid outlet 644 is disposed substantially centrally on a proximal end 646 of the inner housing 624. To facilitate movement of fluid from the interior 628 of the inner housing 624 into the fluid outlet 644, the proximal end 646 is inclined or sloped from an axial wall of the inner housing toward the fluid outlet 644. The fluid inlet 642 is fluidly connected by a suitable conduit 648 to a source 650 of second fluid, such as a lysing solution, diluent or the like, to be introduced into the interior 628 of the inner housing 624. The source 650 may include a mechanism, such as a syringe pump and the like, to positively move fluid from the source 650 through the conduit 648 to the fluid inlet 642 and the interior 628 of the inner housing 624. The fluid outlet 644 is fluidly connected by a suitable conduit 652 to a tank 654. The tank 654 may be another portion of an analytical instrument with which the 52 apparatus 610 is operatively associated. In other embodiments, the tank 654 may retain fluid from the interior 628 of the inner housing 624 until needed for further processing. In some embodiments, it may be desirable to maintain fluid within the interior 628 of the inner housing 624 at a desired temperature. This fluid may be from the fluid dispenser 614, from the source 650 or a combination of fluids from the fluid dispenser 614 and the source 650. To do this, a heating element 656 is operatively associated with the inner housing 624. In the illustrated embodiment, the heating element 656 is an electrical heating element. The heating element 656, in the illustrated embodiment, substantially surrounds and contacts a portion of an outer diameter surface of the inner housing 624. In this way, thermal energy generated by the heating element 656 is transferred to the inner housing 624 and from there to the contents, i.e. fluid, disposed in the interior 628 of the inner housing 624. The heating element 656 is electrically connected by conductor 658 to a heater controller 660. The heater controller 660 applies appropriate electrical energy to the heating element 656 such that the desired amount of thermal energy is generated by the heating element 656 and applied to the inner housing 624. To monitor temperature associated with the heating element 656 and the inner housing 624, a sensor 664 is provided operatively thermally connected with the heating element 656 and the inner housing 624. In an exemplary embodiment, a recess is formed on the inner housing 624 to accept the sensor 664 such that an outer profile of the inner housing 624 is substantially constant and smooth. In one embodiment, the sensor 664 is a resistance temperature detector 53 The heater controller 660 generally operates by comparing an electrical signal indicative of temperature associated with the inner housing 624 with a reference signal and using a result of the comparison to drive the heating element 656. The inner housing 624 not only can maintain a fluid in the interior 628 at a desired thermal energy level, but also can combine or mix fluids, such as a first fluid from the fluid dispenser 614 and a second fluid from the source 650, if desired. To facilitate fluid combination, a proximal end of the inner housing 624 is operatively connected with a prime mover 686 such that the inner housing 624 moves responsive to action of the prime mover 686. A proximal end of the outer housing 626 is fixed to the prime mover 686 by fasteners 687. In an exemplary embodiment, the prime mover 686 is a direct current electric motor, such as model no. LC22-107 available from SKC Shinano Kenshi Corp. of Culver City, California. This embodiment of the prime mover 686 operates at about 3,000 rpm. A linkage assembly 688 operatively or drivingly connects the prime mover 686 with the inner housing 624. The linkage assembly 688 comprises a drive member 690 (Figure 38) and a bearing 692. A shaft 696 on the drive member 690 is coupled with the bearing 692 by appropriate means, such as a lock washer retained about a groove in the shaft 696. The bearing 692 is coupled with the proximal end of the inner housing 624 by an O-ring 694 which provides a relatively soft, elastomeric cushioned mechanical coupling of bearing 692 to the inner housing 624. The O-ring 694 also elastomerically compensates for angular centerline displacement caused by movement (e.g. eccentric) only at the proximal end of the inner housing 624. As shown in Figure 38, the shaft 696 is offset from a midline of the drive member 690. The drive member 690 includes a bore 698 for accepting a drive shaft, which is rotatable, associated with the prime mover 686 such that movement of the drive shaft of the prime 54 mover 686 causes complementary movement of the drive member 690. Another bore 700, disposed substantially orthogonally to the bore 698, is provided in the drive member 690 for accepting a fastener which can bear against the drive shaft of the prime mover 686 such that the drive member 690 moves conjointly with the prime mover 686 drive shaft. The inner housing 624 moves responsive to operation of the prime mover 686. The movement of the inner housing 624 is not identical to the rotary motion of the drive shaft of the prime mover 686. The motion of the inner housing 624 is defined, in part, by the offset disposition of the shaft 696 and the juncture between the open end of the inner housing 624 and the open end of the outer housing 626 provided by the joining member 627. Accordingly, the open ends of the inner housing 624 and the outer housing 626 remain substantially stationary with relative movement corresponding to flexibility provided by the elastomeric nature of the joining member 627. However, the proximal end of the inner housing 624 is free to move conjointly with the shaft 696 on the drive member, which moves responsive to movement of the drive shaft of the prime mover 686. Because the shaft 696 is disposed offset on the drive member 690, movement of the shaft 696 generally follows a substantially eccentric path. Thus, the inner housing 624 generally "vibrates" responsive to operation of the prime mover 686. It is to be noted that the inner housing 624 does not rotate freely with respect to the outer housing 626 responsive to the prime mover 686. To control operation of the prime mover 686, and thereby to control motion of the inner housing 624, a controller 702 is provided. Specifically, the controller 702 is electrically connected with the prime mover 686 by conductor 704. A sensor 706 is operatively associated with the inner housing 624 and electrically connected with the controller 702 by conductor 708 to provide the controller 702 with feedback indicative of movement of the inner housing 624. 55 The controller 702 is electrically connected with the mix controller 616 by conductor 701 and with source 620 by conductor 703. Thus, the controller 702 and the mix controller 616 are able to positively regulate operation of the prime mover 686 to cause intended movement of the inner housing 624. To provide a magnetic field for interaction with the sensor 706 in this embodiment, a magnet 710 (Figure 38) is provided with the drive member 690. In one embodiment, the magnet 710 is retained within a recess 712 in the drive member 690 by suitable means, such as an adhesive like an epoxy cement. The magnet 710 is oriented within the recess 712 such that a south pole of the magnet 710 faces the sensor 706. Thus, as the drive member 690 moves responsive to the operation of the prime mover 686, the magnet 710 generates a periodic electrical signal in the sensor 706. The electrical signal is substantially periodic with a frequency which is substantially equal to a rotational frequency of the drive shaft of the prime mover 686. An example of operation of the apparatus 610 will now be given. It is to be noted that the following discussion is for illustrative purposes only. It is assumed, for the sake of clarity, that the apparatus 610 is at rest (i.e. nothing is energized) . An operator accesses the mix controller 616 to begin operation of the apparatus 610. A suitable first fluid, such as whole blood, a biological sample and the like, is made available to the fluid dispenser 614. A suitable second fluid, such as a blood diluent, a lyse and the like, is made available at the source 650. The mix controller 616 issues an electrical signal to the heater controller 660 via conductor 662 such that the heater controller 660 electrically connects the source 620 of electrical energy to the heating element 656. The electrical energy from the source 620 passes along conductors 668 and 56 658 to the heating element 656. The electrical energy is converted into thermal energy by the heating element 656. The thermal energy in the heating element 656 is transferred to the inner housing 624. In one embodiment, the heating element 656 is supplied with electrical energy until the sensor 664 detects that the temperature associated with the inner housing 624 is about 43 degrees Celsius (± 1.5 degrees Celsius) . By using a temperature level of less than about 45 degrees Celsius, in the case where the first fluid is whole blood, some blood cell surface antigens do not substantially denature and some blood proteins do not substantially coagulate. If sufficient blood cell surface antigens were to denature or if sufficient blood proteins were to coagulate, then those substances could coat portions of the apparatus 610 and the associated instrument. The coatings could dislodge variably and compromise operation of the apparatus 610 and the associated instrument. The heater controller 660 maintains the desired temperature associated with the inner housing 624 by regulating electrical energy flow from the source 620 of electrical energy to the heating element 656. Accordingly, the heater controller 660, and thus the heating element 656, may operate substantially continuously during operation of the apparatus 610 or the instrument with which the apparatus 610 is associated. Once the inner housing 624 has the desired temperature associated with it, the mix controller 616 sends an electrical signal to the controller 702 along conductor 701. Responsive to this electrical signal, the controller 702 electrically connects the prime mover 686 with the source 620 of electrical energy thereby energizing the prime mover 686. The prime mover 686 moves or vibrates the inner housing 624. A predetermined volume of the second fluid, such as about 1275 microliter ("μl") of lyse, is moved from the source 650 into the conduit 648 by a suitable mechanism, such 57 as a syringe pump and the like. The second fluid flows through the fluid inlet 642 in the inner housing 624 toward the interior 628 of the inner housing 624. It is to be noted that, if desired, the prime mover 686 may be energized either before or after the predetermined volume of the second fluid is disposed within the interior 628 of the inner housing 624. The predetermined volume of second fluid moves conjointly with the inner housing 624 responsive to action of the prime mover 686 for a first predetermined time period, which may be on the order of about 5 seconds. After the first predetermined time period, the second fluid has substantially the same thermal energy as the inner housing 624. The mix controller 616 sends an electrical signal to the fluid dispenser 614 along conductor 618. The fluid dispenser 614 acts to introduce a predetermined volume of first fluid, such as about 37.5 μl of whole blood, into the interior 628 of the inner housing 624. In one embodiment, the fluid dispenser 614 may be a pipettor having a discharge nozzle which may be moved toward the opening 640 in the joining member 627. Once the discharge nozzle is in appropriate position with respect to the opening, the predetermined volume of first fluid is moved into the interior 628 of the inner housing 624. Once the predetermined amount of first fluid is introduced into the interior 628 of the inner housing 624, the first fluid and the second fluid are moved within the inner housing 624 responsive to action of the prime mover 686 for a second predetermined time period which may be about 11 seconds. The prime mover 686 operates preferably at a frequency which is not equal to a resonant frequency associated with the apparatus 610. In an exemplary embodiment, where the first fluid is whole blood and the second fluid is lyse, as described above, the first fluid and the second fluid substantially completely mix due to fluid movement within the inner housing 624 responsive to the prime mover 686. The ratio of first fluid to second fluid is about 1 to about 35. The red cells in the whole blood are relatively rapidly lysed and the white cells are relatively rapidly fixed, i.e. substantially preserving white cell morphology. Because the second fluid and the inner housing 624 are at substantially the same thermal energy level, the first fluid also reaches substantially the same thermal energy level after the second predetermined time period. After the first and second fluids have been moved in the interior 628 of the inner housing 624 for the desired time period, operation of the prime mover 686 ceases. The mixture of the first fluid and the second fluid are moved through the fluid outlet 644 and conduit 652 toward the tank 654. The mixture is moved by an appropriate mechanism, such as a syringe pump, operatively associated with the fluid outlet 644. The mixture can be further processes or retained in the tank 654 until needed. The apparatus 610 is ready for further operation. Figure 4 is a more detailed illustration of the sample processing area 110 shown in Figure 3. As shown in Figure 4, the sample processing area 110 includes a vent/aspirate probe assembly 148 and an incubation probe assembly 152. The vent/aspirate probe assembly 148 (shown in Figure 4A) includes a vent needle 154, an aspiration probe 156, a drive assembly 158 for moving the aspiration probe assembly 148 along a slide assembly 160, a drive assembly 159 for moving the vent needle 154 along the same slide assembly 160, and a vertical drive assembly 161. The slide assembly 160 is positioned above the sample cups so that the vent needle 154 and aspiration probe 156 can be positioned directly over the sample tube and sample cups. The aspiration probe drive assembly 158 moves the aspiration probe 156 over the sample cups or sample tube so that the probe 156 can enter the sample tube or sample cups 59 to aspirate or deposit fluid. When the aspiration probe 156 is making its approach to a pre-evacuated container or other sealed sample tube (not shown) , the vent drive assembly 159 first moves the vent needle 154 over the sample tube. A piston assembly (not shown) moves the vent/aspirate probe assembly 148 downward so the vent needle 154 pierces the cap of the sample tube. While the vent needle 154 remains inserted in the cap, the vertical drive assembly 161 causes the aspiration probe 156 to slide through the vent needle 154 into the sample tube to aspirate the sample. Preferably, the cell analysis system 60 has the flexibility to aspirate fluid from a variety of sample tube sizes and to adapt to varying tube closures. Accordingly, the vertical drive assembly 161 is provided with a switch that senses when the aspiration probe 156 reaches the bottom of the tube and stops further downward motion of the aspiration probe 156. The vertical drive assembly 161 then raises the aspiration probe 156 and begins blood aspiration. The incubation probe assembly 152 (shown in figure 4B) can include an incubation probe 160, a first incubation probe drive assembly 164 for moving a second drive assembly 168 along a first slide assembly 166, and a second incubation probe drive assembly 168 for moving a vertical drive assembly 169 and the incubation probe 160 along a second slide assembly 170. This allows the incubation probe 160 to be moved in a diagonal direction and positioned directly above the required sample processing cups in the sample processing area 110. The incubation probe 160 can also be positioned above any of the incubation sites 132 on the subset/phenotyping trays 124, any of the six reagent wells 128 in each of the reagent modules 122, or the incubation wash cup 144. The vertical drive assembly 169 moves the incubation probe 160 vertically so that the incubation probe 160 can 60 enter the sample cups, the incubation sites 132, or the reagent wells 128 to aspirate or deliver fluids. Figure 5 further illustrates the analyzer's sample processing. As shown in Figure 5, several of the sample processing cups 132, 134, 136, 138, 140 and 142 are connected to the flowcells/transducers 170, 174, 178 via a network of transport tubing 182. The RBC cup 134, RETIC cup 136, and WBC cup 138 are each in fluid communication with the impedance transducer 174 and the optical flowcell 170. The HGB cup 142 is in fluid communication with the HGB transducer 178. Figures 6A, 6B, and 6C illustrate the incubation probe 160 during deposition, cleaning, and aspiration respectively. The probe 160 is constructed of a central tube 184 and an outer tube 186. The incubation probe 160 aspirates and deposits fluids through the central tube 184. The incubation probe 160 may be used to clean the sample cups and/or incubation sites by spraying cleaning fluid through an annular region formed between the central tube 184 and the outer tube 186 while aspirating through the central tube 184. In the disclosed embodiment, the analyzer module 64 is supplied with diluent, monoclonal antibody (MAb) reagents if necessary, several lysing reagents, and reticulocyte stain. The diluent, lysing reagents, and reticulocyte stain are supplied through reservoirs 192 and 196 (shown in Figures 7, 8 and 9) coupled to the analyzer 64. The reservoirs 192 for diluent and lysing reagents are also coupled to bulk storage containers 193. When the flow script request the filling of a reservoir, the level sensing switch (not shown) in the reservoirs 192 checks for a full condition in the reservoir, and if the instrument controller determines that the reservoir can tolerate the filling sequence at this time, a pneumatic control line 189 switches from applying a positive pressure to applying a vacuum of about 15 inches of mercury. This vacuum causes fluid to flow from the bulk storage 61 container 193 into the reservoir 192 until the level sensing switch senses that the reservoir 192 is full, at which time the pneumatic control line 189 returns to a positive pressure and fluid flow from the bulk storage container 193 to the reservoir 192 ceases. The Mab reagents can be supplied by disposable, pre-packaged reagent modules 122 (shown in Figures 3 and 4) . The analyzer 64 is provided with fluid sensors (not shown) for determining when one of the bulk containers is empty. These sensors detect air bubbles drawn into the tubing between the bulk storage containers 193 and the reservoirs 192. The analyzer 64 informs the data station module 68 which, in turn, signals the operator about the empty container. The operator can then replace the empty container with a full one and indicate via the user interface to the data station 68 that the container has been replaced. Until the container is replaced, the analyzer 64 will not aspirate additional samples from the sample tubes, although processing of samples already begun will continue with the sufficient reagent remaining in the reservoirs. The aspiration and dispensation by the aspiration probe 156 and the incubation probe 160 are effected by a series of piston pumps 190. Figures 7 and 8 illustrate how the aspiration probe 156 and incubation probe 160 are connected to piston pumps 190 and the reagent reservoirs 192. The volume and flow rate of these fluid transfers are controlled by the analyzer 64 and the data station 198. As shown in Figure 7, the aspiration probe 156 is coupled to a diluent reservoir 192 via a valve 194 and piston pump 190. Figure 8 illustrates the incubation probe 160 coupled to a diluent reservoir 192 via a valve 200 and a piston pump 190. Preferably, the piston pumps 190 are rotatable, reversible pumps capable of aspirating a predetermined volume of fluid for each piston rotation. Each piston pump 190 62 aspirates fluid as its piston is rotated in one direction, and deposits fluid when its piston is rotated in another direction. Suitable piston pumps are disclosed in U.S. Patents 4,941,809; 5,015,157; 5,020,980; and 5,044,889. The entire disclosure of each of the above-identified patents is incorporated herein by reference. Figure 9 illustrates how the reticulocyte stain reservoir 196 is connected to the reticulocyte cup 136 via valves 202 and 203 and a reticulocyte stain syringe 191. Diluent may also be measured and delivered to the sample cups via diluent syringes (not shown) and the tubing network 182. The diluent syringes and the reticulocyte stain syringe 191 are substantially similar to the delivery syringes 204, 206, 208, shown in Figures 10A, 10B, 11A, 11B, and 12. The diluent syringes may be connected to the tubing network 182. Figures 10A, 10B, 11A, 11B, and 12 illustrate how samples that are ready for measurement are delivered from the sample cups to the flowcells/transducers 170, 174, 178. Figure 10A illustrates bulk transfer of sample from a sample cup 216 to the proximity of impedance transducer 174 via pump 220. Figure 10B illustrates metered delivery of the sample by the RBC delivery syringe 204 to the impedance transducer 174. The sample cup 216 is connected to the RBC syringe 204, the impedance transducer 174 and a peristaltic pump 220 by tubing 182. A first valve 210 is placed in the tubing 182 downstream of the sample cup 216, and a second valve 212 is placed in the tubing 182 upstream of the peristaltic pump 220. The flow rate and general operation of the RBC syringe 204 are controlled automatically by the analyzer's electronics and software. Bulk transfer of sample from the sample cup 216 to the proximity of the impedance transducer 174 occurs when the first and second valves 210, 212 are open, as shown in Figure 10A, and the peristaltic pump 220 is driven. Metered delivery of the sample from the RBC syringe 204 to the 63 impedance transducer 174 occurs when the first and second valves 210, 212 are closed, as shown in Figure 10B, and the plunger 224 of the RBC syringe 204 is moved a predetermined distance at a specified rate. Figure 11A illustrates the bulk transfer of sample from a sample cup 230 to the proximity of the optical flowcell 170 via pump 232. Pump 232 may be substantially similar to pump 220. Figure 11B illustrates the metered delivery of the sample by the WBC delivery syringe 206 to the optical flowcell 170. The sample cup 230 is connected to the WBC syringe 206, the optical flowcell 170 and a peristaltic pump 232 by tubing 182. A first valve 236 is placed in the tubing 182 downstream of the sample cup 230, and a second valve 238 is placed in the tubing 182 upstream of the peristaltic pump 232. As shown in Figure 11A, bulk transfer of sample from the sample cup 230 to the proximity of the optical transducer 170 occurs when the first and second valves 236, 238 are open and pump 232 is driven, thereby displacing a volume of sample to the proximity of the optical flowcell 170. Metered delivery of the sample by the WBC syringe 206 to the optical flowcell 170 occurs when the first and second valves 236, 238 are closed, as shown in Figure 11B, and the plunger 240 of the WBC syringe 206 is moved a predetermined distance at a specified rate. Figure 12 illustrates the bulk transfer of a sample from a HGB sample cup 142 to the HGB transducer 178. The HGB sample cup 142 is connected to the HGB transducer 178 and a pump 246 by tubing 182. The pump 246 may be substantially similar to the pump 220. A valve 248 is placed in the tubing 182 downstream of the HGB sample cup 142. Bulk transfer of sample from the HGB sample cup 142 to the HGB transducer 178 occurs when the valve 248 is opened and the peristaltic pump 246 is activated. 64 ς__ Optical Flpwςeu Transducer Within the optical flowcell 170,individual cells are isolated within a flowing stream of fluid so that the optical properties of each cell may be detected and converted into meaningful information. Figures 15 and 16 illustrate a flowcell 170 for use with the cell analysis system 60. In one embodiment (as illustrated in Figure 43), the optical flowcell 170 is a clear quartz block with a thin elongated, rectangular inner flow chamber 300 (Figure 16) of cross sectional dimensions of about 160 μ by 400 μ. A substantially conical channel at an angle of about 30 degrees converges into the flow chamber 300 at one end thereof. A diluted sample stream is injected from nozzle 270 positioned at the center of a moving sheath stream 304 into the flow chamber 300 in such a way that the sample portion of the stream is focused to a very small cross sectional dimension, approximately 5μ x 80μ, normal to the stream flow axis and confined to the center of flow chamber 300. This process is known as hydro-dynamic, or fluid focusing. At a predetermined position along the focused stream axis, a laser beam is directed into flow chamber 300 from a direction orthoganal to the flowing sample stream. In the region where the laser beam intersects the focused sample stream, the laser beam is also focused optically, as described below in section 8. F. , to an approximately 17μ dimension in a direction parallel to the stream flow axis. Thus, a sample illuminated volume is created in the center of the flow chamber 300 in the region where both the stream and the laser beam are focused, bounded in two dimensions by the stream extent, and on a third dimension by the laser beam extent. This illuminated volume, with the dimensions of approximately 5μ x 80μ x 17μ is the sensing region of the flow cell 170. Each cell is detected as it passes through this region and 65 the data collected and processed by the controller and the results are reported. See Figure 43. Exemplary details of the nozzle 270 are discussed below with reference to Figures 31 through 36. As shown in Figure 32, embodiments disclosed herein relate to a fluid nozzle 270 and a method for introducing a fluid 812, the fluid 812 involved is the fluid used in the analytical instrument. In one employment, illustrated in Figure 31, the fluid nozzle 270 is operatively associated with a conduit or a fluid 812 flow guide 814 and a flow cell 170 that detects an item of interest, such as a cell, a particle and the like, present in the fluid 812. In the illustrated embodiment, the flow guide 814 comprises a conduit formed from a suitable material, such as a polymer like acrylic, including a bore 818 for accepting the fluid nozzle 270. The fluid nozzle 270 is substantially centered with respect to the flow guide 814 to facilitate direction of fluid 812 from the fluid nozzle 270 to the bore 818. A conduit 820 is fluidly connected with the bore 818 such that a desired fluid 844 from a suitable source may be deposited in the bore 818 through the conduit 820. The flow cell 170, as described above may be an optical flow cell that measures the item of interest in the fluid 812 as the fluid 812 flows from the fluid nozzle 270 through the flow cell 170. The flow cell 170 may be used, in some embodiments, to perform a white blood cell differential analysis, platelet analysis and/or reticulocyte analysis. In these embodiments, preparatory steps for each analysis may be performed in processing paths, which may be separate, and the analysis may be performed in a single flow cell 170. The construction of the fluid nozzle 270 is illustrated more clearly in Figures 32 and 33. The fluid nozzle 270 generally comprises a manifold 822 and a plurality of conduits fluidly connected with the manifold 822. The exact number of conduits may be chosen to facilitate a particular 66 employment of the fluid nozzle 270. Specifically, in an exemplary embodiment, a first conduit 262, a second conduit 264 and a third conduit 266 are fluidly connected with one portion of the manifold 822. The conduits 262, 264 and 266 may be used as fluid 812 inputs. Thus, the conduits 262, 264 and 266 may be fluidly connected with suitable sources of desired fluid 812. In a particular embodiment, the manifold 822 is made from a suitable polymer, such as acrylic and the like, and has an axial length of about 0.7 inches. The conduits 262, 264 and 266 are made from a suitable metal, such as 316 stainless steel and the like. The conduit 262 may have an axial length of about 1.14 inches, an inner diameter of about 0.023 inches and an outer diameter of about 0.0625 inches. The conduits 264 and 266 may have an axial length of about 0.5 inches, an inner diameter of about 0.019 inches and an outer diameter of about 0.0625 inches. The outer diameter surfaces of the conduits 262, 264 and 266 may be coated with an adhesive, such as an epoxy and the like, and inserted into complementary bores 830, 832 and 834, respectively, formed in the manifold 822. In the illustrated embodiment, the conduits 262, 264 and 266 are offset axially and circumferentially on the manifold 822. The conduit 266 is offset axially about 0.07 inches from an end 831 of the manifold 822. The conduit 264 is offset about 0.26 inches from the end 831 and the conduit 266 is offset about 0.45 inches axially from the end 831. Circumferentially, the conduit 262 is offset about 60 degrees from the conduit 264 and the conduit 266 is offset about 60 degrees from the conduit 264. Thus, the conduit 262 is offset about 120 degrees from the conduit 266. The manifold 822 fluidly connects the conduits 262, 264 and 266 with conduits 272, 274 and 276, respectively, which are also operatively associated with the manifold 822. The manifold 822 can allow one of the conduits 272, 274 and 276 67 to be dedicated to a particular fluid or test run by the instrument with which the nozzle 270 is associated. The conduits 272, 274 and 276 are disposed substantially coaxially and substantially centrally with respect to the flow guide 814. The disposition of the conduits 272, 274 and 276 with respect to the fluid guide 814 and the flow cell 170 may be chosen to provide intended positional accuracy of the flow of fluid 812 from the nozzle 270 to the flow cell 170. The manifold 822 includes a bore 42 for accepting the substantially coaxial disposition of the conduits 272, 274 and 276. The manifold 822 allows fluid 812 in conduits 262, 264 and 266 to flow through the manifold 822 and into conduits 272, 274 and 276, respectively. The conduits 272, 274 and 276 are substantially linear over their entire length. However, in some embodiments, to preserve the coaxial disposition of the conduits 272, 274 and 276, a spacer, not shown, may be provided radially between conduits 272 and 274 and between conduits 274 and 276. The spacer is configured, such as by providing outer diameter surface reliefs, channels and the like, so as not to interfere with fluid 812 movement in the conduits 272, 274 and 276. While the illustrated embodiment shows distal ends of the conduits 272, 274 and 276 being mutually axially offset, this is not necessary. In an exemplary embodiment, the conduit 272 is made from a suitable metal, such as 304 stainless steel, #3 (full hard) temper hypodermic needle tubing and the like. The conduit 272 has an axial length of about 2.55 inches, an inner diameter of about 0.013 inches and an outer diameter of about 0.025 inches. The conduit 274 is also made from a suitable metal, such as 304 stainless steel, #3 (full hard) temper hypodermic needle tubing and the like. The conduit 274 has an inner diameter of about 0.038 inches, an outer diameter of about 0.050 inches and an axial length of about 2.26 inches. The conduit 276 is made from a suitable metal, such as 304 68 stainless steel hypodermic needle tubing and the like. The conduit 276 has an inner diameter of about 0.062 inches, an outer diameter of about 0.078 inches and an axial length of about 1.97 inches. In one embodiment, the flow guide 814 includes a substantially tapered portion having an inner diameter of about 0.25 inches, at point "A", and an inner diameter of about 0.118 inches, at point "B" . Both points A and B are labeled in Figure 31. A relation between relevant conduit 272, 274 and 276 dimensions and corresponding dimensions of the flow guide 814 may be predetermined to provide desired fluid focusing of fluid 812, to reduce a probability of contact between the flow guide 814 and the fluid 812, to optimize flow cell 170, e.g. optics, operation, etc. In some embodiments, the dimensional relation may be related to the flow rate differential. Specifically, in an exemplary embodiment, a latitudinal cross section of relevant portions of the flow guide 814 is proportional to a related flow rate differential. In an exemplary embodiment, the tapered portion defines a slope of about 60 degrees. A fluid-conveying portion of the flow cell 170 adjacent a distal end of the fluid nozzle 270 defines a slope of about 30 degrees with an inner diameter of about 0.118 inches. The dimensions may be chosen to produce intended positional accuracy of the flow of fluid 812 with respect to the flow cell 170. With the construction of the fluid nozzle 270 being thusly disclosed in detail, a method of introducing fluid with the fluid nozzle 270 will now be discussed in detail. A source of fluid 812, such as blood, a blood component and the like, to be processed by the flow cell 170 is fluidly connected with one of the conduits 262, 264 or 266 such that fluid 812 flows from the source to the selected conduit 262, 264 or 266. The other conduits 262, 264 or 266 which are not fluidly connected with source of fluid 812 are not supplied 69 with fluid 812. The fluid 812 contains an item of interest, such as a particle, a cell and the like, detectable by the flow cell 170. A source of another fluid 844, such as water, buffer solution, diluent or other fluid that does not adversely react with the fluid 812, and the like, is fluidly connected with the conduit 820 such that the another fluid 844 flows from the source to the conduit 820 and the flow guide 814. The fluid 844 flowing from the conduit 820 into the flow guide 814 surrounds a portion of the conduits 272, 274 and 276, as shown in Figures 34 through 36. The offset dispositions of the conduits 272, 274 and 276 permits reduction of fluid 844 flow discontinuities. A gradual reduction in latitudinal cross section of the fluid flow path through the flow guide 814 permits a reduction of the likelihood of fluid diffusion within the flow guide 814. If desired, as fluid 812 flows from one of the conduits 272, 274 or 276, the other two conduits 272, 274 or 276 may be cleaned or "back-flushed" with fluid 844 by applying an appropriate relatively reduced pressure source, for example, to the conduits 272, 274 or 276 being cleaned. Alternatively, after fluid 812 has been sequentially introduced through each of the conduits 272, 274 and 276, all of the conduits 272, 274 and 276 can be simultaneously cleaned by passing an appropriate fluid through the conduits. Thus, because all of the conduits 272, 274 and 276 can be cleaned substantially simultaneously, through put of the flow cell 170 can be increased by reducing down time needed to clean the nozzle 270 while also providing for rapid introduction of fluid 812. This also correspondingly can increase the through put of the analytical instrument with which the flow cell 170 is associated. In an exemplary embodiment, the flow rate of fluid 844 is larger than the flow rate of fluid 812. For instance, in one embodiment, the flow rate of fluid 812 is about 2.5 μl 70 per second and the flow rate of the fluid 844 is about 300 μl per second. This flow rate differential fluidly directs or focuses the flow of fluid 812 toward the flow cell 170. In general, the flow rate differential can be predetermined such that detection of the item of interest in the fluid 812 by the flow cell 170 is facilitated. The fluid focusing provided by the flow rate differential is substantially similar irrespective of the conduit 272, 274 or 276 chosen to introduce the fluid 812 as fluid 812 introduced from either conduit 272, 274 or 276 is fluidly focused toward substantially the same position with respect to the flow cell 170. This allows fluids 812 from each of the conduits 272, 274 and 276, and tests performed by the instrument with which the fluid nozzle 270 is associated, to share the same flow cell 170. Accordingly, each of the conduits 272, 274 and 276 may be fluidly connected with a separate source of fluid 812 such that the likelihood that fluid 812 from one source might encounter fluid 812 from another source is reduced. Thus, the probability of fluid 812 cross over and/or fluid 812 contamination can be reduced. The fluids 812 from each of the conduits 272, 274 and 276 can be processed by the flow cell 170 in substantially parallel fashion, thereby improving throughput of the fluid nozzle 270 and the instrument with which the nozzle 270 is associated. This ability of the fluid nozzle 270 has been verified empirically. In one experiment, illustrated in Figures 34 through 272, an exemplary embodiment of the fluid nozzle 270 was analyzed by a finite element method to reveal the fluid properties associated with the nozzle 270. In this embodiment, the conduit 272 has an inner diameter of about 0.013 inches. The distal end of the conduit 274 is offset proximally about 0.29 inches from the distal end of the conduit 272. The conduits 272 and 274 define a substantially annular fluid flow path having an inner diameter of about 0.025 inches and an outer diameter of about 0.037 inches. 71 The distal end of the conduit 276 is offset proximally about 0.29 inches from a distal end of the conduit 274. The conduits 274 and 276 define a substantially annular fluid flow path having an inner diameter of about 0.049 inches and an outer diameter of about 0.061 inches. The finite element analysis was performed using a FIDAP computer program, version 6.01, available from Fluid Dynamics International of Evanston, Illinois. Steady-state axisymmetric models of fluid flow through the conduits 272, 274 and 276 and steady-state three dimensional models of fluid flow through the flow cell 170 were analyzed to show that the position of the fluidly focused fluid 812 with respect to the flow cell 170 is independent of the conduit 272, 274 or 276 used to introduce fluid 812. In all cases, the fluid flow rate of the fluid 844 is about 300 μl per second and the fluid flow rate of the fluid 812 through the chosen conduit 272, 274 or 276 is substantially within the range of about 2.5 μl per second to about 2.0 μl per second. The analyses assumed Newtonian fluid properties with no slip boundary conditions on the solid surfaces. In one example, to simulate white blood cell differential analysis, platelet analysis, and reticulocyte analysis, three separate fluid analyses were performed. The white blood differential analysis fluid 812 is introduced through the conduit 272, as shown in Figure 34, at a fluid flow rate of about 2.5 μl per second. As shown in Figure 35, the platelet analysis fluid 812 is introduced through the conduit 274 also at a fluid flow rate of about 2.5 μl per second. The reticulocyte analysis fluid 812 is directed through the conduit 276, as shown in Figure 36, at a rate of about 2.0 μl per second. Upon comparison of Figures 34 through 272, the fluid flow pathlines from the respective conduits 272, 274 and 276 resulting from the fluid analyses demonstrate that no contamination of a flow of fluid 812 by a prior flow of fluid 812 occurs and that the position of the 72 fluidly focused fluid 812 with respect to the flow cell 170 is independent of which conduit 272, 274 or 276 is selected. The independence of the position of the fluidly focused fluid 812 with respect to the flow cell 170 with respect to the selection of the conduit 272, 274 or 276 is also verified experimentally by optically measuring flow of fluid 812 containing 7 μm diameter beads sequentially through each of the conduits 272, 274 and 276. The fluid 812 containing the beads is introduced at a fluid flow rate of about 2 μl per second. fc C.V., INDEX MATCHED ALL IAS DSS Conduit 272 4.7 3.2 2.6 4.3 3.1 2.2 Conduit 274 5.0 3.6 2.0 4.6 4.2 2.6 Conduit 276 4.3 3.1 2.4 5.1 2.8 2.7 As is evident from the above coefficients of variation, the coefficient of variation (CV) for three measured optical properties (ALL: axial light loss; IAS: intermediate angle scatter; and DSS: depolarized side scatter) are substantially similar for all of the conduits 272, 274 and 276. This similarity in optical response verifies that the fluid nozzle 270 can be used for multiple fluid 812 item of interest measurements prior to any cleaning step, thereby increasing the through put or analytical capacity of the flow cell 170 and any instrument associated with the flow cell 170. The number of fluid 812 measurements or fluid 812 introductions that may occur prior to cleaning corresponds to the number of 73 conduits provided with the fluid nozzle 270. Irrespective of the number of conduits involved, the embodiments described herein allow for substantially simultaneous cleaning of substantially all of the conduits. If the fluid 812 were to have sufficient propensity to interact with or stick to a portion of the conduits 272, 274 and 276, then remnants of a first fluid in the conduit 272, 274 or 276 may encounter (i.e. carry over) a second fluid passed through the same conduit 272, 274 or 276. Similar concerns are present with the conduits 262, 264 and 28. These concerns may compromise accuracy of the flow cell 170. To address these concerns, it is possible to dedicate a specific conduit 272, 274 or 276 to a specific fluid 812 or test performed by the flow cell 170. The number of conduits 272, 274 and 276 so dedicated may be dependent upon the properties of the fluids 812 being introduced by the fluid nozzle 270. By substantially isolating at least one of the conduits 272, 274 and 276, carry over of one fluid 812 to another fluid 812 can be reduced. For instance, one conduit 272, 274 or 276 could be dedicated to a test that uses a fluid 812 containing a relatively bright fluorescent marker, such as auromine O and the like, and another conduit 272, 274 or 276 could be dedicated to a test that uses a fluid containing a relatively dim fluorescent marker. Once the fluids exit the conduits 272, 274 or 276, the volume and flow of fluid 844 through the fluid guide 814 is sufficient to reduce the probability of fluid 812 diffusion while fluidly focusing the fluid 812 toward a common flow cell 170. Thus, the two tests can be performed substantially sequentially by the same flow cell 170 without substantially compromising accuracy or sensitivity of the flow cell 170. Upon moving upward into the rectangular cross-section of flow cell 170, the velocity rapidly increases, which hydrodynamically focuses the sample stream to a central core measuring approximately 5μ x 80μ in cross-section. The small 74 5μ dimension, which is in the direction of focus of the wide- angle condenser lens illustrated in Figure 22, assures minimum defocusing and therefore equal brightness of fluorescent cells located at different positions within the stream. In addition, because the width of the flow chamber 300 is much larger than the sample stream, the flow chamber 300 should not clog readily, yet it still gives resolution comparable to that provided by a smaller sensing region. A focusing lens (shown in Figure 19) focuses a laser beam on the flow chamber 300, and detectors (shown in Figures 20 and 21) detect the light scattering and/or fluorescence properties of cells that pass through the flow chamber 300. These features are described in further detail in section 8.F. of this disclosure. D_ Impedance Transducer The cell analysis system 60 may use an impedance transducer 174 to count red blood cells and platelets. Figure 17 illustrates a preferred embodiment of an impedance transducer 174 that performs impedance-based cell counting and sizing, and makes use of hydrodynamic focusing. The impedance cell counting is based on the detection of changes in electrical resistance produced by a particle as it passes through a small orifice 314. Conduction is provided by an electrolyte fluid (such as buffered saline and the like) in two chambers 310, 312 of the impedance transducer 174. A sample introduction nozzle 316 and hydrodynamic focusing direct cells to the orifice 314 of the impedance transducer 174. As each cell passes through the orifice 314, the electrical resistance of the path through the chambers 310, 312 and the orifice 314 increases. A current source 317 connected to two electrodes described below disposed in the chambers 310, 312 on either side of the orifice 314 causes this increase in resistance to be manifested as a electrical 75 voltage pulse. The sample introduction nozzle 316 doubles as the upstream side electrode. The secondary electrode 318, is located downstream of the orifice 314. The number of pulses is indicative of cell count, while the amplitude of each pulse is related to cell volume. Volume histograms are created by plotting frequency distributions of pulse amplitudes. These histograms are used to obtain RBC and PLT parameters such as MCV (mean cell volume) and RDW (red cell distribution width) . The impedance transducer 174 is preferably made from a material that is non-conductive and transparent, such as acrylic, a similar polymer or the like. The secondary electrode 318 in the transducer 174 is preferably platinum because electrolysis at this polarity creates corrosive gasses which may dissolve some other electrode materials. Other materials having similar corrosion resistance may be used for the electrode 318. The volume of the chamber 310 on the upstream side of the transducer 174 may be reduced without affecting the operation of the transducer 174 for the disclosed applications. The sample introduction nozzle 316 is preferably placed within about 1.5 mm from the orifice 314. The distance between the nozzle 316 and the orifice 314 should be maintained during operation, as well as a relatively high sheath velocity (about 10 m/sec through the orifice) . About 30% of the cells that flow through a non- hydrodynamically focused impedance transducer pass close to the edges of the flowcell' s orifice rather than going through its center. This can clog the orifice and cause distorted measurements. Hydrodynamic focusing may be utilized in the impedance transducer 174 of the cell analysis system 60 to reduce clogging and improve measurement accuracy. Hydrodynamic focusing is accomplished in the impedance transducer 174 by the following procedure. The RBC delivery syringe 204 (shown in Figures 10A and 10B) delivers the 76 sample to the nozzle 316 of the impedance transducer 174 at a rate of about 0.333 μl/sec. As the flowing sample exits the impedance transducer nozzle 316, it is accelerated to a velocity of about 10 m/sec by an RBC sheath flow 315. Since the sample volumetric flow rate, which is preferably substantially constant at about 0.333 μl/sec, is the product of the velocity and the cross-sectional area, this area decreases as the sample accelerates. In a preferred embodiment, the acceleration to 10 m/sec causes the diameter of the sample stream to decrease to about 6.5 μm. The impedance transducer 174 is provided with a waste tube 314a located immediately downstream of the orifice 314 to "catch" red cells as they leave the orifice. If the red cells are not disposed of after exiting the orifice 314, they may return to the vicinity of the orifice, and thereby generate signals which distort the platelet measurements and to a lesser degree distort the red cell measurement. To assist in capturing measured cells, a secondary flow (via port E) is provided solely to propel cells down the waste tube 314a. The impedance transducer 174 is also provided with several ports (A, B, C, D and E) . Port A provides a vent for venting air (or other gases) from the upstream side of the orifice 314. Port B provides an inlet for injecting air into the chamber 310 in order to drain the upstream side of the transducer 174. Port D provides the drain for the upstream side of the transducer, along with a sheath inlet port. Port C provides an inlet for injecting air into the chamber 312 in order to drain the downstream side of the transducer 174. Port C also provides a vent for venting gas from the downstream side of the transducer 174. Port E provides a drain and an inlet for the secondary flow. Port G provides an outlet for waste. Port H, although not used in the present embodiment, may be used to provide a tangential entry 77 point for flowing additional fluids into the upstream side of the transducer 174. £_. HGB Transducer The HGB transducer 178 measures the optical absorption of cells in a blood sample to determine the levels of HGB in the blood sample. A HGB transducer 178 is shown in Figure 18, along with a block diagram of circuitry for detecting and analyzing signals from the HGB transducer 178. In one embodiment, HGB concentration is measured in grams per deciliter, and is proportional to the amount of light absorbed by a sample in the green wavelength region (approximately 540 nm) . The HGB transducer 178 generates an electrical signal that is related to the light absorption of the liquid in the HGB transducer chamber 338. Light absorption is measured in the HGB transducer 178 for a prepared sample containing hemoglobin and for a clear reference solution. The difference in electrical signal generated by the transducer during these two measurements is approximately proportional to the hemoglobin content of the prepared sample. The HGB transducer chamber 338, which may be transparent, is positioned between a light source 322, such as a light emitting diode and the like, and a detector 326, such as a photo diode, a phototransistor and the like (Figure 18) . An interference filter 326, preferably rated at about 540 nm, is placed between the HGB transducer chamber 338 and the detector 324. The detector 324 output current, which is approximately proportional to the light energy received, is amplified by a current-to-voltage amplifier 332. The analog signal processing of the HGB signals is discussed in section 8.F. of this disclosure in connection with the electronic systems. 78 Whole blood is mixed in the HGB cup 142 by the velocity of the incoming HGB lysing reagent to a dilution ratio of preferably about 190:1. A pump 246, which may be peristaltic, is used to draw a sample from the HGB cup 142, through a tubing network 182 connected to the HGB cup 142, and into the HGB transducer chamber 338. The HGB cup 142 is rinsed by flushing HGB lysing reagent to reduce any carryover of a sample with subsequent samples. HGB reagent is placed directly into the HGB transducer to provide the HGB reference reading. £_ OPtiCS Bench A plan view of the optics bench 350 is shown in Figure 19. The optics bench 350 is mounted on the analyzer module 64 and includes a laser light source 352, mirrors 354, 356, lenses 358, 360, a flowcell 170 (fused-silica in an exemplary embodiment), and several detectors 400, 402, 404. The laser beam 368 is directed by a rear mirror 354, a front mirror 356, a beam adjuster 370, shaped and focussed by a pair of cylindrical lenses 358 and a laser focusing lens 360. The laser 352 is preferably a vertically polarized 488 nm air-cooled argon laser (Uniphase 2114B-125LAB, or equivalent) operating in the TEM» B (transverse electromagnetic) mode with light feedback. In this mode, the light intensity has a gaussian distribution and is in phase. The laser beam 368 is held at about 10 mW by the light feedback system within the laser circuitry. The optical elements between the laser 352 and the optical flowcell 170 are constructed so that the gaussian focal beam waist at the flow chamber 300 of the optical flowcell 170 is substantially elliptical and measures about 17μ high by about 64μ wide.The beam waist is defined as the position along the laser beam axis where the cross-sectional beam dimension, in 79 a given direction normal to the axis, is minimum. In the preferred embodiment shown in Figure 19, the optical system is characterized by two orthogonal planes of symmetry, a vertical plane and a horizontal plane, each of these planes containing the laser beam optical axis. Therefore, at any position along the beam axis, the beam extent is defined by two orthogonal dimensions, a vertical dimension, and a horizontal dimension. The vertical dimension is defined as the linear distance, in the vertical plane measured normal to the optical axis, between the points where the intensity is l/e2 times the maximum intensity which occurs at the center of the beam. The corresponding horizontal dimension is defined identically except that it lies in the horizontal plane. This beam configuration is accomplished by a pair of cylindrical lenses 358 which act as a vertical beam expander. Preferably the upstream lens has a focal length of approximately -18.8 mm, and the downstream lens has a focal length of about +75.4 mm. The lenses 358 are positioned slightly off the confocal condition so that a coincident vertical and horizontal waist occurs at the flow chamber 300. Preferably, the focusing lens 360 is spherical with a focal length of about 79.5 mm. A beam fine-adjust mechanism 370 is positioned between laser focusing lens 360 and flowcell 170. This mechanism consists of a pair of small 10° wedges with an adjustable air space which is used to produce a fine lateral displacement of the laser beam relative to the sample stream. These wedges are oriented with the entrance and exit surfaces normal to the laser beam axis. The air space can be adjusted by means of a 32 pitch screw in a direction parallel to the laser axis. The air space to lateral beam displacement ratio is 10.5/1 when using BK7 glass as the wedge material. One complete turn of the 32 pitch screw thus moves the incident laser beam laterally ±75μ relative to the sample stream, without producing any change in the incidence angle of 80 illumination. The lateral beam displacement resolution is something less than ±lμ. This system, in conjunction with the design of the forward and side angle collection optics, allows easy control for optimally aligning the laser beam to the sample stream without affecting the alignment of the subsequent optics. The flow chamber 300 of the flowcell 170 preferably has an aspect ratio of about 2.5x. Hydrodynamic focusing within the optical flowcell 170 creates a substantially elliptical sample core stream with an approximately 15x aspect ratio. When the sample flow rate is about 2.0 μl/sec, the resultant sample stream is a substantially elliptical cylinder. The length and width dimensions of the sample stream are approximately 80μ x 5.0μ. The approximately 5μ stream width corresponds to the approximately 80μ horizontal focal waist. This results in a maximum intensity variation within the stream of about 1%. The vertical focal waist of about 17μ results in a pulse width of approximately 2.0 to 3.5 μsec, depending on cell size, whenever a cell passes through the laser beam 368 at the nominal stream velocity of about 8 meters/sec. The detectors 380, 400, 402, and 404 measure the effects of cells passing through the flowcell 170. Preferably, the detectors 380, 400, 402, and 404 are capable of measuring at least seven optical parameters.One or more detectors are preferably placed in the forward light path for measuring forward intermediate angle scattering and either small angle forward scattering or axial light loss (ALL, also known as forward extinction) . ALL is generally the decrease in light energy due to a cell passing in front of a laser beam and being detected by a photodiode. The light loss is generally due to scattering. Preferably, one parameter measured is ALL, defined as the decrease in light energy reaching a detector in the path of a laser beam due to the passage of a cell through that beam. Small angle forward scatter, in 81 contrast, is light energy that reaches a detector outside (but within a narrow angle of 1° to 3°) the incident laser beam due to scattering from a cell passing through the beam. A beam stop is generally provided to keep the laser beam from getting into the detector. ALL measuring systems collect light within the incident cone of laser illumination, while small angle scatter systems collect light outside this cone. In ALL measuring systems, the signal of interest is a negative signal subtracted from the steady state laser signal, whereas in small angle forward scatter measurement the signal is a small positive signal imposed on a very low background light level. Intermediate angle forward scattering (IAS) is similar to small angle forward scattering, except the light is scattered at a larger angle from the incident laser beam. More specifically, IAS relates to light scattered in a ring between about 3 and 10 degrees away from the incident or center line of a laser beam. In a preferred embodiment, ALL is collected in the angles less than about 0.3 degrees horizontally and less than about 1.2 degrees vertically from the laser axis, and IAS is collected at angles between about 3 degrees and 10 degrees from the laser axis. The preferred forward path optical system shown in Figures 19 and 20 includes a spherical plano-convex lens 376 and a two-element photodiode 380 located in the back focal plane of the lens. In this preferred configuration, each point within the two-element photodiode 380 maps to a specific collection angle of light from cells moving through the flow chamber 300, independent of the position of the cells. Thus, the inner element 382 is preferably substantially rectangular, which accordingly maps to the asymmetry of the laser beam divergence, and measures ALL. The outer element 384 is preferably a substantially circular ring and accordingly maps to the range of collection angles of forward scatter desired for measurement of IAS. 82 This alignment of the forward path is independent of the optical flowcell 170 and laser beam fine-alignment. To provide the desired collection geometry, the two-element detector's lateral position is aligned with respect to the collecting lens 376. Changing the optical flowcell 170, or readjusting the incident laser beam 368 by means of element 370, which only repositions the beam without effecting any angular redistribution, has no effect on the angular acceptance of the detector 380, and therefore does not require any corresponding readjustment of the forward path optics. Alternatively, the two-element, single unit detector 380 could be replaced with two separate detectors. In this case, a mirror with a center hole of proper diameter would be placed in the back plane of the lens 376. The mirror would reflect IAS to one of the detectors. A slit, coincident with the center hole of the mirror and shaped to pass only the laser beam, would transmit light for ALL measurement to the second detector located behind the mirror. Either of the above-described schemes is a variation on small-angle collection systems. The described schemes do not require an obscuration bar and its related adjustments. In the preferred first case, both detectors can be incorporated onto one chip. No mirror is required. Incorporation of a neutral density filter 386, as shown in figure 20, is desirable in order to keep the All signal from saturating the inner ALL element 382. Preferably, the filter 386 is provided by coating the inner ALL element 382 with a Neutral Density 2.0 coating (a coating that transmits about 1% of the incident light) . An anti-reflection coating can be coated over the outer IAS element 384. In an exemplary embodiment, as illustrated in Figures 19 and 21, the remaining detectors 400, 402 and 404, are three photomultiplier tubes (PMTs) which detect either side-scatter (light scattered in a cone whose axis is approximately 83 perpendicular to the incident laser beam) or fluorescence (light emitted from the cells at a different wavelength from the incident laser beam). A movable polarizer, 436, placed in the light path of PMT 400 configures PMTs 400 and 401 to detect depolarized side-scatter (DSS) and polarized side scatter (PSS) respectively, while movable filters (430, 432, 434) enable detection of fluorescent emissions at specified wavelengths from the cells. FLl, green fluorescence, is detected between about 515 to 545 nm. FL2, yellow fluorescence, is detected between about 565 to 595 nm. FL3, red fluorescence, is detected between about 615 to 645 nm. Side-scatter and fluorescent emissions are directed to these PMTs by dichroic beam splitters 401 and 403 which transmit and reflect efficiently the required wavelengths to enable efficient detection. Sensitivity is enhanced at PMTs 400, 402, and 404, when measuring fluorescence, by utilizing an immersion collection system as illustrated in figure 22. In this instance, the immersion collection system is one that optically couples the first lens 414 to flow cell 170 by means of a refractive index matching layer 416, enabling collection of light over a wide angle. In a preferred embodiment this collection angle is about 130° at the sample stream, which compares to about 44° in a typical air-spaced condenser system with a Numeric Aperture of 0.5. It can be shown mathematically that the fluorescence energy collected from a fluorescing particle is proportional to (1-cosU) , where U is defined as 1/2 the cone angle of collection. Thus the preferred 130° system collects almost 8 times more energy than the 44° system, a difference which enables fluorescence detection with smaller low-powered lasers and/or weaker fluorescence markers. The system is also color corrected so that a given optical path can be used at substantially different wavelengths without refocussing. This allows a single PMT to detect several wavelengths of 84 light by interposing or removing optical filters 430, 432, 434. As shown in Figures 21, 22 and 24, the illustrated immersion collection system is telocentric such that the cathode surface of a given PMT is conjugate with an objective aperture stop 410 (shown in Figure 22) and located at infinity with respect to the flow chamber 300 of the flow cell 170. This construction reduces the need for precise alignment of the PMTs with respect to each other and the flow chamber 300. As shown in Figure 22, the condenser 412 preferably includes a piano-hemispherical first element 414 optically coupled to the quartz flowcell 170 by an index matching gel layer 416. Generally, the condenser 412 is an optical lens system with aberration correction sufficient for large angle light collection but not sufficient for diffraction limited imaging used in high resolution microscopy. A suitable gel is available from Dow Corning (identification number #02- 3067) . The specifications of a preferred embodiment of the condenser are listed in Table 1. TABLE 1 R L ~> «*> t 12 = 1 . 82 (Si0 2 window) R 2 -> ∞ t 23 = 3 . 913 ( FK5 - flint crown glass #487704 ) R 3 = -3 . 913 d 34 = 0 . 929 (Air space ) R 4 = -54 . 7 t 45 = 5 .14 (FK5 ) R 5 = -9 .753 d 56 = 3 . 348 (Air space ) 85 TABLE 1 (Continued) R 6 = 45.7 t 67 = 2.0 (ΞF5 - dense flint glass #673322) R 7 = 16.853 t 78 = 7.9 (BK7) R 8 = -24.028 d 89 = 0.635 (Air space) R 9 = 35.649 t 9 ιo = 2.0 (SF5) R 10 = 13.014 tion - 6.95 (BK7) R u = -120.59 A = 3.913 + .02 / - .12 B = 1.82 ± .02 C = 0.16 ± .02 D = .929 The PMT optical system is preferably modular and is illustrated in Figures 23 and 24. Each PMT module includes either 1 or 2 PMT's and a slit/field lens assembly 420, which includes a slit 422 and field lenses 424 and 425 (Figures 23 and 24) . The slit 422, which is conjugate with the flow chamber 300, minimizes background light at the cathode of the PMT 400. The field lenses 424 (preferably with focal length of about -12.0 mm) and 425 (preferably with focal length of about 15.0 mm) effect the telocentric configuration discussed above. Optical filters 430, 432, 434 and polarizer 436 are inserted into the light paths of the PMTs to change the wavelength and/or the polarization of the detected light. In addition the following dimensions relate to Figure 24: A = 46.0 B = 20.61 86 RECTIFIED SHEET (RULE 91) • — ISA/EP . ^ 86A C = 22.98 D = + 14.976 E = 13.292 F = 0.522 G = 2.0 H = 6.7 I = 3.8 J = 3.78 K = 22.98 L = F 530 = -12.025 R x = -6.248 Φ = 5.0 t : = 2.0 (BK7) R 2 -> oo Q 2 = 10.0 M = 6.43 It should be mentioned that the system is designed so that a third PMT module can easily be added, which, with the addition of appropriate dichroic mirrors and bandpass filters, would enable as many as 6 PMTs to be incorporated into the system. For example, one could imagine a sophisticated analysis requiring simultaneous measurements of 86A RECTIFIED SHEET (RULE 91) — JSA/EP 87 four fluorescence detectors along with polarized (PSS) and depolarized (DSS) side scatter. In an exemplary embodiment, ALL is measured by a substantially rectangular photodiode and a N.D. 2.0 filter (See: Figure 20). IAS is measured by an outer ring photodiode with no filter. PSS is measured by a Hamamatzu R928 PMT (402) with no filter. DSS is measured by an R928 PMT (400) and a horizontal polarizer (436) . FLl is measured by an R928 (400) PMT and a 530/30 filter (a bandpass filter centered at about 530 nm with a passband of about 30 nm, 430). FL2 is measured by an R928 PMT 402 and a 580/30 bandpass filter (432) . FL3 is measured by an R928 PMT (404) and a 630/30 bandpass filter (434) . i Pneumatic Unit In a preferred embodiment of the cell analysis system 60, the pneumatic unit 72 is a separate unit having a dedicated power supply. This construction reduces weight, size and power consumption of the analyzer module 64 and data station module 68. The pneumatic unit 72 includes a pressure pump and a vacuum pump. It provides a regulated pressure of approximately 8 1/2 psi, another pressure from about 12-15 psi, a higher pressure of about 40 psi, and a vacuum of about 15 inches of mercury. The vacuum pressures are controlled by the analyzer software present in a suitable memory, such as a RAM, a ROM, an EPROM, a SRAM and the like. _Q_ Data Station/Computer The data station module 68 is preferably a 80386 or 80486- based PC compatible computer including a display terminal, disk drive, hard-disk, keyboard, pointing device, and LAN 87 connection. In an exemplary embodiment, the display terminal is color, the disk drive is 3.5 inch, the hard disk has at least 540 megabytes of memory and the keyboard is PC-style. The data station 68 may be provided with memories, such as RAM's, ROM's, SRAM's, EPROM's and the like, containing sufficient software algorithms to manipulate measured data, calculate parameters, and display results in a variety of formats, including histograms, scattergrams, and other multidimensional plots. The data station 68 of the cell analysis system 60 has memories and other devices which apply algorithms for various cellular analyses. These algorithms are used to analyze clusters of data points generated by the analysis module 64 to yield information of clinical relevance. The disclosed integrated hematology/immunology instrument provides a single platform on which such software may be implemented, thereby providing an instrument that not only automates hematology and immunology sample processing and measurement, but also automates data analysis. The data station 68 also provides data repositories which are collections of related sample records. Figure 28 illustrates a preferred set of data repositories, including data logs, patient histories, quality control (QC) files, standard reference particle files, paired duplicates files, Bull's algorithm (X-B) batches, moving average files, and calibration files. _]__ Electronic Systems Electronic systems are found in the analyzer module 64, data station module 68, and pneumatic unit 72. The analyzer 64 provides the hardware platform for data acquisition and fluidics and motion control. In an exemplary embodiment, the data station 68 is a general purpose computer that serves as a user interface and processes, displays and stores the 88 89 acquired data. The pneumatic unit 72 controls the vacuum and pressure sources. In a preferred embodiment, the three modules are physically separate, and each unit is powered from a separate AC outlet. The data station 68 and the pneumatic unit 72 communicate with the analyzer 64 through independent serial communication channels 76, 84. Figure 25 is a block diagram illustrating some electronic hardware components of the analyzer 64. These components include a central processing module 500 (CPM) , a data acquisition subsystem 502, and a motion control subsystem 504. The CPM 500 controls the data acquisition subsystem 502, the motion control subsystem 504, and communication functions. A preferred embodiment of the CPM 500 includes the following features: *Motorola 68302 Integral Multiprotocol Processor clocked at 20 MHz *1 MB Dynamic RAM expandable in steps of 1 MB up to 4 MB ♦ 128KB EPROM *2KB Non-Volatile RAM *DMA Controller for fast 16-Bit transfers of acquired pulse data from A/D Converters to CPM RAM *Buffered 8-Bit bus for data acquisition control and diagnostics functions *Two Motor Processing Module (MPM) Serial Links *One peripheral serial link *One Pneumatic Unit Serial Link *One HDLC serial link *Direct Memory Access (DMA) channel dedicated to HDLC serial link *One RS-232 port for bar code reader *One RS-232 port for diagnostics terminal 89 90 Figure 26 is a block diagram illustrating details of the data acquisition subsystem 502 shown in Figure 25. Cell or sample characteristics are converted to electrical signals at the HGB transducer 178, the impedance transducer 174, and the optical flowcell 170. The impedance transducer 174 and the optical flowcell 170 generally produce electrical pulses as their output signals, and the HGB transducer 176 outputs a low frequency signal. The output of each flowcell/transducer is processed separately by the data acquisition subsystem 502. The output signals from the impedance transducer 174 and the optical flowcell 170 are generated by several detectors 510. These detectors consist of the PMTs and photodiodes of the optical bench 350 or the electrical circuitry of the impedance transducer 174. Each detector output is fed through a preamplifier module 512 and a signal processing module 514 to an analog to digital converter (ADC) module 516. The signal processing modules 514 include circuitry for the measurement of pulse attributes such as pulse height and the like. The ADC converter 516 is a multiplexed converter that changes analog outputs from the signal processing module 514 to digital values that represent these pulse attributes. The digital values are then transferred to the CPM 500 via direct memory access (DMA) 518. The CPM 500 processes the information and then sends the data to the data station 68 through the high level data link control (HDLC, a communications protocol) data link 76. The data acquisition subsystem 502 also generates the analog voltages required for various parameter settings, such as trigger levels, gating levels, laser output power, and others. The outputs from the HGB transducer 178 are fed through a HGB-detector/analog-multiplexer board 328 directly to the ADC module 516. In general, the HGB board 328 includes a transresistance amplifier 332 and a current source 334 (Figure 18) . The HGB board 328 and its components are 90 91 discussed in more detail under section 8.F. of this disclosure. A. ADC Module The ADC module 516 contains an analog-to-digital converter. The ADC module 516 is multiplexed to measure analog voltages from the signal processing modules 514 and auxiliary voltages within the ADC module 516 itself. The digital representation of each voltage measurement has an associated identifying tag. In a stream of data, the tag indicates the specific measured value which follows. All tags are 7 bits long, allowing for a maximum of 128 different parameters. The signal processing modules 514 contain one peak-hold circuit assigned to each output signal from the preamplifiers 512. A peak-hold circuit receives an electrical pulse as its input signal and generates a steady voltage equal to the maximum voltage detected during the pulse. A programmable tag sequencer in the ADC module 516 points to one of these peak-hold circuits at a time, routing the value to be measured (the steady output voltage) to the ADC module, which performs the conversion of that particular signal from its analog form (voltage) to a digital value. After sufficient time has been allowed for this conversion, the tag sequencer points to the next peak-hold circuit holding a value to be measured. When each conversion is finished, the corresponding tag identifying the measured signal is attached to the data. In this way, the tag sequencer time-shares the ADC module by assigning a time slot to each input. The results of these conversions are transferred to the main memory on the CPM 500 via the DMA 518. DMA is utilized to transfer data at high rates without CPU intervention. 91 92 E.L. Impedance Transducer Preamplifier The preamplifier 512 contains a low-noise programmable constant current source. This constant current is divided between two paths. One current path flows through the electrodes in the impedance transducer; the other flows into the preamplifier 512. Since the sum of both currents is constant, a change in the current through the electrodes (caused by cell passage through the impedance transducer 174) is reflected as a change in the output voltage of the preamplifier 512. £_ Impedance Transducer Signal Processing The output from the impedance transducer preamplifier is routed to two independent paths, each having a 12-bit programmable gain, baseline restorer, pulse detector, and peak hold circuit. One path is for RBC pulse detection, and the other path is for PLT pulse detection. The same pulse is thus screened simultaneously in the following two different criteria. A pulse is detected as valid if its peak value exceeds a given threshold. The data acquisition subsystem 502 recognizes level thresholds and slope thresholds. The slope threshold improves the hardware counter dead time by allowing the counting of two pulses that arrive very close in time. Each type of cell requires its own qualification criteria. RBC pulses should exceed a certain level and slope. A certain negative slope should be exceeded in order to reset the detector for the next pulse. PLT pulses occur in the same sequence with RBC pulses. However, PLTs are distinguishable from RBCs because PLTs are smaller. A pulse is classified as a detected PLT if it exceeds a lower level threshold but does not go above an upper threshold. Additionally, the pulse must exceed a 92 93 predetermined positive slope in order to be considered a valid PLT. A certain negative slope should be exceeded in order to reset the detector for the next pulse. If a pulse satisfies the qualification criteria, a trigger signal is sent to the peak-hold circuit, and subsequent ADC conversion is initiated. Trigger pulses from the impedance transducer 174 are counted in two dedicated 16-bit counters. One counter is for RBCs, and the other counter is for PLTs. Each output path from the impedance transducer preamplifiers includes a baseline restoration circuit to subtract the background DC component from the amplified signals. The offset voltage created by these circuits is monitored, thus providing a tool for diagnostics. Ώ_ Optical Preamplifiers Light emitted from the optical •flowcell 170 is collected at different angles by the detectors 510, which include photodiodes (PD1 and PD2) and photomultipliers (PMTl, PMT2, and PMT3) . These signals have a wide dynamic range, and accordingly a wide range of gain adjustment is provided. For the PMTs, gain adjustment is preferably accomplished by controlling a dynode voltage on the PMT itself (about 200V to about 1100V) . This procedure can adjust the gain over an approximate 105 range. The optical preamplifiers of the PMTs convert the current output from the PMTs to a voltage with fixed gain. The gain of each photodiode (PD) is programmable at its preamplifier in power-of-2 steps. The PD preamplifiers convert the PD output current to voltage. E_, Optical Signal Processing The optical preamplifier outputs are routed to five independent paths or channels. Each channel include its own 93 94 baseline restorer, pulse detector, peak hold circuit, and 12- bit programmable gain (post peak-capture) . An "optical" pulse is detected as valid if its peak value exceeds a predetermined programmable threshold. A valid pulse generates a digital trigger pulse. The trigger pulse can be programmed to be one of several selected logical combinations of channels (PDl, PD2, PMTl, PMT2, PMT3) . Each channel has its own programmable lower threshold. The trigger pulse initiates the peak-capture and subsequent ADC conversion of the captured peak values for the five channels. The trigger may be qualified by requiring a gating criteria. For example, the trigger may be invalidated if the signal on PDl, PD2, or PMT2 exceeds a predetermined gate threshold. A baseline restorer circuit is provided for subtracting the DC component from the pulse signals, thereby reducing any DC background offsets. The response time of these circuits is slower than the width of the average pulse. The offset voltage created by these circuits is monitored, providing a tool for diagnostics. Trigger pulses from the optical flowcell 170 are counted in two dedicated 16-bit counters. One counter is for the gated cells (those that have not been rejected by the gating criteria) , and the other counter is for the total number of cells that meet the lower threshold requirement. ∑_ HGB Signal Processing Figure 18 is a block diagram of a simplified hemoglobin (HGB) measuring system. The concentration of hemoglobin contained in the prepared sample is measured, for example, in grams per deciliter. This concentration is proportional to the absorbance of the light by the sample in the green (about 540 nanometers) wavelength region. 94 95 The light path consists of a current controlled light emitting diode 322, a transducer chamber 338, a filter 326 (about 540 nm) , and a photodiode 324. The output current from the photodiode, which is proportional to the light energy received, is amplified by the transresistance amplifier 332. The output of the transresistance amplifier 332 is sent to the ADC module 516. The difference between voltages developed when measuring a clear reference solution in the transducer chamber 338 and when measuring the prepared sample containing hemoglobin is representative of hemoglobin concentration. Q_ Time Stamp The signal processing module 514 uses a 16-bit counter (not shown) to generate a time stamp with an approximately 0.5ms resolution. The time stamp value is stored with the data from each automatic sequence iteration which resulted in valid data acquired in the ADC module 516. _ Motion Control Figure 27 is a block diagram illustrating an exemplary embodiment of the motion control subsystem 504. The flow sequences and automated sample processing operations of the analyzer 64 are controlled through the motion control subsystem 504. As illustrated, the motion control subsystem 504 includes a motor processing module 520 (MPM) , a valve control module 522 (VCM) , a fluid sensor module 524 (FSM) , and a digital input module 526 (DIM) . The MPMs 520 communicate with the CPM 500 through two independent serial links 530, 532 (500 KB) , and each MPM 520 preferably controls up to 12 stepper motors 534. The VCMs 522 control all valves in the analyzer 64. The DIMs 526 monitor all digital inputs (switches, 95 96 optical sensors, and magnetic sensors) . The FSM 524 monitors all fluid sensors. The VCMs 522, DIMS 526, and the FSM 524 are intelligent modules that preferably communicate with the CPM 500 through a half-duplex, differential serial peripheral bus. Additional peripheral modules can be added to this bus. _Z_ Software Software controls the major operations of the cell analysis system 60, including the analyzer flow sequences, the timing and sequence of events, gathering data, and converting measured data into meaningful results. The software is resident on suitable memories, such as RAM's, ROM's, EPROM's, SRAM's and the like, found in the system 60. The software components are preferably partitioned into the six domains (represented by circles) shown in Figure 2. The operator interface domain 90 regulates user interaction with the data station 68 including all operator controlled input devices attached to the data station, definition and generation of all data station displays, and definition of all printed output. The data station operating software 92 controls sample processing, data management, security, communications with the analyzer module and laboratory information systems (LIS), and generation of printed outputs. The algorithm software 96 may include any desired combination of applied mathematics. The algorithms are applied in the analysis of sample data, the conversion of list mode data into graphic and numeric results, and the statistical analysis of groupings of numeric results. These algorithms preferably include clustering techniques for identifying discrete cell types or conditions. The analyzer operating software (AOS) 98 controls the analyzer module's electronics (hardware), data collection, 96 97 and communications to the data station module. The timing and scheduling of all analyzer activities, including the analyzer flow sequences, is also controlled by the AOS 98. The flow sequence (FSQ) software 100 controls the mechanical components responsible for moving fluids through the analyzer module 64, including the execution of automated sample processing protocols and integrated hematology and immunology testing. The firmware 102 includes a network of EPROM resident device controllers for various hardware modules of the analyzer 64 and pneumatic unit 72. The operator interface (01) , data station operating software (DSOS) , and algorithms use the data station module 68 as their platform. The AOS 98, FSQ software 100, and firmware 102 reside in and use the analyzer module 64 as their platform. The preferred software is a multitasking, multithreaded application. The AOS 98 resides in the CPM 500 and is the main controller of the detailed operation of the analyzer 64. It communicates with several slave microcontrollers responsible for stepper motor timing, analog-digital conversion, vacuum/pressure closed loop monitor/control, valve control, and digital sensor inputs. In addition, it is responsible for data, status and control communication with the data station 68 to which it is connected. The AOS 98 is preferably executed on a Motorola 68302 CPU chip. Its firmware is stored in external EPRO (s) , and the downloaded AOS and flow sequences are stored in on-board RAM. An embodiment of AOS operation is shown in figures 29 and 30. The AOS 98 includes multitasking features for implementing the flow sequences. The AOS downloads flow sequences from the data station, storing them in its memory. The AOS executes the flow sequences required for the desired sample tests upon direction from the data station 68. 97 98 Each flow sequence requires tasks of multiple analyzer components in accordance with a schedule. Figures 13A-13F are timing diagrams of an exemplary flow sequence for integrating and automating hematology and immunology sample preparation and measurement on a single unit. The upper-most horizontal axis, as viewed, represents time in seconds, and the left-most vertical axis lists sample processing and measurement components of the analyzer 64. The grids of the diagram describe the activities of the analyzer components. Each of the components listed along the left vertical axis in Figures 13A-13F performs a specific set of tasks in the flow sequence. When a component has completed its task, it begins to look for its next instruction without waiting for downstream components to finish work on the current sample. The AOS maintains a collection of count-related hardware set points and parameters. One set is provided for each count type (CBC WBC, CBC OPLT, etc.). In addition, one set is provided for diagnostic purposes. The AOS accommodates the download of any of these sets from the data station 68. In addition, any set may be activated (i.e. used to configure the hardware) under command from either the data station 68 or flow sequence software. In addition to the count-related hardware set points and parameters, the AOS maintains a collection of event count- independent parameters. The AOS accommodates the modification of any of these parameters from the data station 68. In contrast to the count-related parameters, the AOS loads these values directly. To commence a flow sequence, the AOS 98 determines that a sample is available for aspiration. This is based either on operator activation of a pushbutton or a command from an autoloader mechanism. All the information known by the analyzer 64 about the sample is sent to the data station 68. The data station 68 responds with information about the required measurements to be performed on the sample. Based 98 99 upon this response, and in conjunction with the state of the analyzer 64 (i.e. reagents, incubations, flow sequence aspiration enable/disable flags) , the AOS determines whether or not to proceed with sample aspiration. Whether or not an aspiration occurs, the AOS informs the data station 68 of the status of the sample. When a flow sequence requires incubation, the AOS provides the flow sequence with the ability to "allocate" an unused site 132 in the sample processing area 110 for an incubation. The sample type (and therefore the appropriate flow sequence to run at the completion of incubation) is specified as part of the allocation process. When the incubation is started, the AOS starts an incubation timer associated with a particular incubation site 132. A sample identifier, sample type, and incubation time are also associated with each incubation site 132. The AOS updates the active incubation timers periodically and recognizes the completion of incubation intervals. When complete, the AOS continues the execution of the flow sequence for that test. The AOS reports the total incubation time of each incubated sample and the incubation site number (position) as part of the data accumulated for each test on each sample. After the incubated sample has been processed and the incubation site has been cleaned and dried, the flow sequence notifies the AOS that the site is again available for allocation. The AOS 98 inhibits aspiration of samples to the incubation area 118 when the appropriate incubation trays 124 are not present. Any changes in the incubation trays 124 or reagent modules 122 are relayed to the data station 68. Whenever an aspiration is disallowed, the AOS sends an advisory message to the data station 68. Upon data station request, the AOS supplies the current incubation status of all sites in the analyzer 64. This information includes incubation time, site status (clean/dirty) and site usage counts. 99 100 The flow sequence interpreter 100 is capable of running multiple flow sequences simultaneously. The flow sequence interpreter allows flow sequences to coordinate their activities through the setting and testing of various "flags." Flow sequence logic makes decisions based upon the state of flags which are set and cleared by other flow sequences running concurrently. The flow sequence interpreter supports fixed or variable sample event count times. Variable event count times may be set through either software or hardware set points. Variable event count times are preferably provided with an upper limit as defined by the flow sequences. The flow sequence interpreter allows flow sequences to initiate event count and data collection intervals. Data generated during the data collection interval is automatically sent to the data station 68 by the AOS. The data sent to the data station 68 preferably includes at least the sample identifier, hardware counters, list mode data, and incubation time (if any) . Count types preferably include: - CBC: complete blood count including all hematology measurements except those related to reticulocytes. - RETICS - SUBSET/PHENOTYPE The AOS allows the analyzer 64 to overlap counting activity on the flowcells/transducers 170, 174, 178. Thus, multiplexing and piplining the analyzer activity maximizes instrument throughput. The analyzer 64 may be connected to external containers for waste (not shown) or bulk reagent storage (193) . AOS monitors sensors that detect when the waste container becomes full or a bulk reagent storage container 193 becomes empty. 100 101 Further aspiration of samples is inhibited by the AOS 98 until the condition is remedied. The AOS reads and modifies the non-volatile serial access memory in each antibody reagent module 122. At least the following information is stored in each antibody reagent module memory: lot number expiration date test type (panel number) - module number number of wells used in module usages of module initialized flag redundancy/error control The antibody reagent modules 122 are read as part of normal analyzer initialization. Thereafter, any operation that affects the status of the module 122 is recorded in the module' s memory. The AOS 98 communicates with the motor processor modules 520 which are responsible for controlling the analyzer stepper motors 534. The AOS resets the motor processor modules 520 at initialization. The AOS keeps track of the position of each motor in the analyzer 64 and verifies this information with the controlling motor processor module 520. Position discrepancies are reported to the data station 68. Upon successful completion of power-on self tests, the analyzer 64 accepts AOS operating software downloaded from the data station 68. At the completion of the software download, a start address is supplied from the data station 68 specifying the address at which to begin execution. 13. Sample Processing Examples h_ General Sample Processing 101 102 The following paragraphs discuss in detail exemplary operation of the cell analysis system 60. Further understanding of details of the system 60 may be gained by reference to this discussion. While specific examples are discussed for the sake of clarity of understanding, it is to be remembered that the system 60 may perform other method steps without departing from the intended scope of the claims. The automated sample processing protocol of the cell analysis system 60 can be considered in three phases — sample preparation, sample measurement, and sample analysis. The particular protocol for each of these phases is test dependent. For example, the preparation, measurement, and analysis for the WBC differential is different from that for platelets, reticulocytes, lymphocyte subsets, etc. General steps, however, are common to each phase. In the first phase, automated sample preparation, the analyzer 64 aspirates a volume of the sample, transports the sample to designated cups, and mixes the sample with diluent and/or reagent as required to prepare the sample for measurement. The preparation may only involve diluting the sample, and the diluting means may also be the lysis for removing RBCs. Sometimes, as in the reticulocyte test, the preparation phase involves two steps, a first step predilution with a diluent/sheath reagent, and a second step dilution adding a known volume of fluorescent stain. In other tests, such as the lymphocyte subset test, the preparation phase may involve many steps and require an extended incubation with a reagent. When this occurs, aspiration probe assembly 148 places a volume of the sample into transfer cup 140 and returns to a position ready to aspirate a subsequent patient sample. The remaining steps in the preparation process are executed by the incubation probe assembly 152. These steps may include further dividing the sample into one or more portions in incubation sites 132, 102 103 adding a specific Mab reagent to each portion, and incubating. Most of these steps, performed by incubation probe 152 may occur while the vent/aspiration probe assembly 148 is occupied with the processing of subsequent samples. After incubation is complete, incubation probe assembly 152 completes the preparation phase by mixing the incubated sample portion with a lysis reagent to remove the red cells so that the sample portion is ready to be pipelined to the optical flowcell for measurement. The second phase, the measurement phase, begins when the sample cups contain a sample that is ready for measurement. The sample is then routed through a tubing network 182 connected from the bottom of the sample cups to the desired measurement transducer 170, 174, 178. After leaving the transducer, the samples are sent to waste containers (not shown) . The signals are sensed by the appropriate detectors for each test, then amplified, processed, digitized, and stored in a list mode file corresponding to the particular test. The third, the analysis phase begins with the list mode data. Algorithms are applied to the data which map the various particles or cell types into the feature space with axes corresponding to the detectors appropriate for each test, thereby identifying unique population clusters, and enumerating the cells within each cluster. The final output may be graphic and/or numeric, and may be a measure or function of cell volume, hemoglobin content, population type, or some other cellular characteristic. The output is usually quantified in both absolute terms and in percentages. For example populations of cell subtypes are given as percentages of parent cells and also enumerated as events per microliter of patient blood. Whenever incubated samples are analyzed, the analysis of the conventional hematology tests is done first. When the incubated sample measurement is complete, 103 104 the incubated sample analysis takes place and the combined patient analysis is completed. The testing protocol for the sample preparation and measurement phases of sample processing are implemented automatically by means of flow sequences, which vary in complexity. In tests involving extended incubation, the flow sequence integrates the incubation and non-incubation testing so that whenever a sample is incubating, the analyzer 64 is allowed to proceed with subsequent tests. When the incubating sample is ready for measurement, processing of further samples is interrupted and the incubated sample undergoes measurement and analysis. £L. Hemoglobin Sample Processing A greater understanding of this discussion may be had with reference to Figures 5 and 12. For example, a portion of patient sample 166, about 18.75 microliters in volume, is deposited into the HGB cup 142 by means of the aspiration probe 156, where it is mixed with a large volume of HGB lyse reagent with a resulting dilution of about 200:1. After about 20 seconds of lysing time, the cup contains only diluted hemoglobin, which is transferred for measurement through line 182 to the hemoglobin transducer 178 by means of peristaltic pump 246. The optical transmittance of the hemoglobin sample in the transducer chamber 338 is measured by means of the LED source 122 and photodiode 324. The transmittance, represented by T, is amplified, processed, digitized, and stored. It is then converted to absorption in the analysis phase by means of an algorithm A=log(l/T), which is further converted to hemoglobin concentration, HGB, in grams per deciliter of patient sample, by means of a previously determined calibrator. The hemoglobin test, in combination with the RBC impedance test results, enables 104 105 determination of the following measured and calculated paramete HGB = (hemoglobin concentration) MCH = HGBxlO/RBC (mean cell hemoglobin) MCHC = HGBxlOO/HCT (mean cell hemoglobin concentration) where RBC is the red blood cell count (RBCs per μl) and HCT is the hematocrit (volume fraction, in percent, of the blood sample that consists of red blood cells) , both of which are measured in the impedance transducer 174. £_ RBC and Platelet Sample Processing The reader should refer to Figures 4 and 5. A portion of patient sample 166, about 18.75 microliters in volume, is deposited into cup 134 by means of aspiration probe 156, where it is mixed with a volume of diluent/sheath reagent with a resulting dilution of about 420:1. The diluent/sheath reagent is appropriate both as a sheath carrier in the laminar flow systems in impedance flowcell 174 and optical flowcell 170 and as a sample diluent so that the RBCs and Platelets travel in single file in each transducer. The formulation includes a surfactant which enables unambiguous distinction of small red cells from large platelets. After mixing in the RBC cup 134 is complete, the diluted sample is transferred to impedance transducer 174 (Figures 10A and 10B) by pump 220, valves 210 and 212, and syringe assembly 204, 224. Platelets are sized and counted in impedance transducer 174 (Figure 17). Platelets are also transferred to and counted in the optical transducer 170 (Figure 16) . Because of the smaller illuminated volume and lower noise in the optical transducer, the optical platelet count has superior performance. The platelet count from the optical transducer 170 is reported as patient data, with the 105 106 impedance count being used as a diagnostic tool for monitoring instrument performance. The impedance transducer 174 is used for reporting the platelet size parameters. A lower threshold is set which distinguishes platelets from noise, and an upper threshold is set which distinguishes platelets from RBCs. Pulse amplitudes are filtered, amplified, digitized and stored as list mode events. From this data algorithms are applied for calculating the following platelet size parameters, and displaying the platelet histogram: Platelet count (PLT) Mean platelet volume (MPV) Platelet distribution width (PDW) Plateletcrit (PCT = MPV x PLT) Platelet concentration (Used for instrument diagnostic purposes) The diluted sample from the RBC cup 134 is also transferred to the optical transducer by valves 236 and 238, pump 232, and syringe 240, 206. The platelets are determined in two dimensional feature space using the PSS (polarized side scatter) and IAS (intermediate angle scatter) optical parameters. The pulses from detectors 384 and 402 are processed, digitized, and stored in list mode files for processing by algorithms. The sample flow rate for measuring platelets is about 2.5 microliters per second, and the counting time through the flowcell is about 6 seconds for normal patients. This counting time is extended automatically for low count samples to improve the count statistics. The count reported from the optical transducer is platelet concentration (PLT) . The impedance transducer 174 is also used for determining RBC size and count parameters. The upper threshold used for detecting platelets in the impedance transducer 174 is also 106 107 the lower threshold for the RBC count. The pulses above this threshold are processed, digitized, and stored in the RBC list mode file. Algorithms are applied for calculating the following RBC parameters and displaying the RBC histogram: Red cell concentration (RBC) Mean cell volume (MCV) Red cell distribution width (RDW) Hematocrit (HCT) . WBC Differential Sample Processing Referring to Figures 4 and 5, a portion of patient sample 166, about 37.5 microliters, is deposited by means of sample aspiration probe 156 into WBC cup 138 which contains about 850 microliters of WBC lyse. The lyse is a one reagent/one step process that achieves multipurpose goals. It is gentle enough to preserve the morphology of fragile white cells and at the same time efficiently lyse substantially all of the red cells. Both of these goals are accomplished even in hemaglobinophathic samples, which may require that the lysing time be extended beyond 11 seconds. Additionally, in the preferred embodiment, the lyse contains a small concentration of a vital nuclear stain which effectively labels any nucleated red blood cells (NRBCs) which might be present in the peripheral blood. The lysis chemistry has been predetermined such that the refractive index matches that of the sheath to substantially less than about 0.1%. The mixture of lyse and sample normally remains in cup 138 for about 11 seconds, where it is lysed and agitated at an elevated temperature. In a preferred embodiment, the lysing temperature is controlled at 42°C ± 3°. At this point, the contents of cup 138 are piped directly to optical flowcell 170. 107 108 Referring to Figures 19 and 20, the measurement process begins as the cell stream passes through the optical transducer 170, having been diluted with the addition of lyse so that the cells pass through the laser illumination in single file, in a laminar flowing sample stream surrounded by diluent/sheath 304 (illustrated in Figure 16). The illuminated volume is bounded in the two dimensions normal to the flow axis by the hydrodynamically focused cell stream, and in a dimension parallel to the flow axis by the vertical beam waist of the laser beam which is about 17 microns. The sample flow rate during this test is about 2.5 microliters per second, and the corresponding illuminated sensing volume of the WBC and NRBC cells approximates an elliptical cylinder with dimensions of about 80μ x 5μ x 17 μ The approximately 17μ dimension is measured along the axis of the cylinder. The presence of a cell in the illuminated region is detected by photodiodes 382 and 384, photomultiplier tube 404, and a unique triple threshold trigger circuit that operates in three feature space dimensions. That is, it processes the three parameters of ALL (axial light loss) , IAS (intermediate scatter) , and FL3 (red fluorescence) and qualifies signals for digitization using AND/OR logic. A qualified signal must be greater than the IAS threshold, while at the same time it must be greater than either the ALL threshold or the FL3 threshold. The combination of this unique triggering circuit and the lysing properties (which include a balanced fixative, allowing the NRBC nuclei to be rapidly stained) clearly and non ambiguously counts and excludes NRBCs from the WBC differential cell count. This test counts WBC populations and NRBCs without the usual interference from background signals, both fluorescent and non-fluorescent, such as that emitted from DNA fragments, RBC stroma, and platelets. When cells that meet the triple threshold criteria pass through the illuminated volume, pulses are generated at 108 109 detectors 382, 384, 400, 402, and 404. The amplitudes of these pulses are filtered, amplified, digitized, and stored in list mode in the corresponding five dimensional feature space of ALL, IAS, FL3, PSS (polarized side scatter), and DSS (depolarized side scatter) . The normal counting time through flowcell 170 is about 10 seconds. At the flow rate and dilution ratio described, and with a normal patient WBC count of about 7000 cells per microliter of blood volume, the resulting event count rate would be about 5000. In low count samples, this counting time can be automatically extended in order to improve the statistical accuracy of the measurement. At the conclusion of the measurement time, the sample stream is piped to waste, and probe 156 is cleaned and dried and prepared to process a subsequent sample. Algorithms are applied to the five parameters quantified in the list mode data (ALL, IAS, FL3, PSS, and DSS), and the following cell types are quantitated and/or flagged within less than about 30 seconds of processing time: White Cell concentration (WBC) , Neutrophil concentration (NEU) and percentage(%N) , Lymphocyte concentration (LYMPH) and percentage (%L) , Monocyte concentration (MONO) and percentage (%M) , Eosinophil concentration (EOS) and percentage (%E) , Basophil concentration (BASO) and percentage (%B) , Nucleated Red Blood Cell (NRBC) and percentage of WBC (%NRBC) , Blast concentration (BLST) , Immature Granulocyte concentration (IG) , Variant-lymph concentration (VARL) , and Band concentration (BAND) . Lvmphocvte Subset Sample Processing In a preferred embodiment, sample processing for lymphocyte subset tests involves the following steps as illustrated in figures 3, 4, and 5. Aspiration probe 156 first aspirates a quantity of whole blood sufficient for the subset test and deposits the quantity into transfer cup 140. 109 110 The volume of blood required is about 50N microliters, where N is the number of Mab (monoclonal antibody) pairs required for the test. In the standard panel, N is expected to be 5, and thus the required volume for deposition in cup 140 is about 250 microliters. At this point the aspiration probe 156 is cleaned and then returns to sample station 166 to process subsequent samples while the incubation probe assembly 152 continues the subset sample processing. The incubation probe 160 aspirates the blood from the transfer cup 140 and deposits about 40 microliters in each of 5 sequential cups 132 in incubation trays 124. Then incubation probe 160 is cleaned before moving to the reagent module 122, removing about 20 microliters of the first Mab pair 128, and depositing it into the first corresponding incubation cup 132. After probe 160 is again cleaned, it returns to the reagent module 122 and transfers from the 2nd Mab pair 128 another about 20 microliters of reagent into the 2nd corresponding incubation cup 132. This process continues until each of the required incubation cups contains a mixture of blood and Mab for incubation. At this point incubation probe 160 is cleaned and dried and waits for the first Mab/blood sample incubation to complete. All activity of the sample aspiration assembly 148 is then suspended until the incubated subset samples are processed as follows. Incubation probe 160 deposits about 30 microliters of the first incubated subset 132 into the WBC cup 138 which contains about 670 microliters of WBC lysing reagent. After the incubated sample is lysed and vortexed at approximately 42°C ± 3° for about 11 seconds, the first incubated Mab/blood pair is ready for measurement, whereupon the contents of cup 138 are piped directly to optical flowcell 170. The measurement process begins as the cell stream intersects the laser illuminated volume at flowcell 170. Data is acquired from optical detectors 382, 384, 400, and 110 111 402, via the system electronics and analyzer software and stored in list mode for each Mab/blood reagent mixture. The sample has been diluted so that the cells within the stream pass through the illumination zone of the laser in single file. Each cell is detected by the presence of pulses indicative of four features -- ALL(axial light loss), IAS (intermediate angle scatter), FLl (green fluorescence), and FL2 (orange fluorescence). The amplitude of each pulse is amplified, digitized, and stored in list mode on the appropriate feature space axis. Analysis begins with the application of algorithms to the stored four dimensional data, from which subset percentages are calculated. After the counting time for the first subset measurement is completed, probe 160 is cleaned and dried before returning to the next incubated subset 132 and repeating the process until all subsets have been measured and analyzed. The final analysis, with results in both percentages and absolute counts per microliter of patient blood volume, is a composite of all of the above described subset measurements and the WBC differential hematology measurement. The normal counting time through flowcell 170 is about 10 seconds. In certain low count samples, this counting time will be automatically extended in order to improve the counting statistics of the measurement. After the sample measurement process is completed, sample aspiration assembly 148 is reactivated and ready to continue processing of any subsequent samples. The disclosed automated sample preparation features accommodate numerous antibody panels for use in a variety of immunology and phenotyping tests. For lymphocyte subsets, each panel preferably includes five 2-color antibody sets. Preferably, each antibody set incudes one antibody (Mab) marked with FITC (fluorescein isothyocyanate) and the like, and a second Mab marked with PE (Phycoerithrin) and the like. Ill 112 The antibodies are distinguished by cluster designation (CD) numbers. Illustrating by means of example, at least the following lymphocyte subset Mabs may be included in a panel. Mab Combination Cell Tvoe Enumerated Cell Percentages CD45/CD14+CD13 lymphocytes % of WBC CD3/CD4 T-helper subset % of Ts, lymphs & WBCs CD3/CD8 T-suppressor subset % of Ts, lymphs & WBCs CD3/CD16 Tot. T/Tot. NK cells % of lymphs & WBCs CD5/CD19 Tot. T/Tot. B cells % of lymphs & WBCs A reduced panel is also proposed which could be used for monitoring CD4 positive cells in HIV patients. At least the following Mabs may be included in this panel: Mab Combination Cell T yp e Enumerated CD45/CD14+CD13 lymphocytes CD3/CD4 T-helper subset In certain other phenotyping Mab tests, the number of Mab pairs, N, might be 1, and hence the required sample volume would be about 50 microliters. Any combination of Mab's may be used. For some tests, the volume of Mab reagent required might be based on an estimate of the WBC patient count obtained from the hematology measurements made on the sample. As for example, in extreme cases of leukocytosis or leukopenia, it may be necessary to adjust the ratio of Mab antibody to patient blood to assure adequate antibody binding or to prevent excess free-antibody background. Because the hematology measurements do not require incubation, they proceed through the flowcell transducer well before the lymphocyte subset sample preparations are completed. The data station can therefore calculate an estimated patient count of the hematology results for that sample to enable the 112 113 analyzer 64 to adjust as necessary the Mab to blood ratios in order to carry out these tests. ∑_ Reticulocyte Sample Processing Referring to Figures 4a and 5 for processing reticulocyte tests, after aspiration probe 156 has completed mixing the RBC and Platelet dilutions in the RBC cup 134, the aspiration probe 156 removes about 200 microliters of blood diluted to about 420:1 and places it into the retic cup 136. The retic cup 136 contains about 600 microliters of retic reagent, making the resulting dilution ratio about 1680:1. The reagent of the preferred embodiment contains a fluorescent dye with an excitation maximum near the 488 nm argon laser wavelength and a high quantum yield. The preferred reagent stains both DNA and RNA quickly, and in such a way that a single dimension fluorescence histogram avoids the normal WBC confusion. It is so sensitive that the analyzer 64 will detect two fragments of RNA in a cell. The method is linear to up to about 90% reticulocyte count. After an appropriate incubation period (about 25 seconds with the preferred reagent described previously) or immediately upon mixing, the mixture of diluted blood and retic reagent is transported to optical flowcell 170. This transportation process can be timed to provide sufficient incubation time for the staining of the reticulocytes, i.e., 25 seconds, if separate incubation processes are not necessary. As the population which includes mature red blood cells and reticulocytes passes through the laser illuminated volume at flowcell 170, the scatter and fluorescence properties of the sample are measured by using photodiode 384 and photomultiplier tube 400, which is configured for FLl with a green fluorescence filter 430. The amplitudes of the pulses are filtered, amplified, digitized, and stored as list mode 113 114 data in the two dimensional feature space of IAS and FLl. The measurement time through the flowcell is about 8 seconds with a sample flow rate of about 2 microliters per second. At a patient RBC of about 5,000,000 per microliter of blood, a preferred embodiment measures approximately 50,000 events, which corresponds to 500 reticulocyte events in a patient with a 1% reticulocyte concentration. An algorithm is applied which excludes WBCs and platelets and counts reticulocytes by means of fluorescence positive events superimposed on the negative RBC histogram. This method also characterizes a reticulocyte maturity index, RMI, by means of fluorescence intensity. The time to process a sample which includes both the standard hematology tests and reticulocytes in the preferred embodiment is about 45 seconds. The following parameters are reported for the reticulocyte test: Reticulocyte concentration (RETC) , Reticulocyte percent (%R of RBC) and Reticulocyte maturity index (RMI) . Another method which uses extended incubation of the nuclear stain can also be used to measure reticulocytes by using both incubation probe 160 and aspiration probe 156 in a method similar to that used in lymphocyte subset processing, as discussed above. For the sake of illustration, a number of uses of an embodiment discussed herein are presented. The following discussion is provided for exemplary purposes only and this discussion is not exhaustive. Specifically discussed below are ways of using a disclosed embodiment to perform an integrated blood cell analysis, a hemoglobin analysis, a red blood cell and platelet analysis, a white blood cell differential analysis, a reticulocyte analysis, lymphocyte immunophenotyping analysis, measurement of a T helper set, measurement of a T suppressor subset and measurement of T and B lymphocytes. Appropriate references are made to software, which may be present on a RAM, a ROM, an EPROM, a SRAM or 114 115 other suitable memory device, used in performing the described steps. Source code for the software is presented at Appendix A and Appendix B which appear immediately preceding the claims. The step numbers referred to in the examples are reproduced as "STEP" numbers located at appropriate lines in the source code of the software. Portions of the software may be more readily understood when combined with reference to Figures 44A-44F and 63A-63F. Example 1 -- Integrated Blood Cell Analysis An embodiment of the invention may be used to perform cellular analyses of whole blood samples. One example of such an analysis procedure follows. The steps of the sample processing are controlled by software such as that presented in appendix A. The steps of the data analysis are controlled by software such as that presented in appendix B. 1 - A sample tube containing a whole blood sample is placed by the operator in the sample tube holder. 2 - The vent assembly lowers and pierces the sample tube cap (Step Al) . 3 - The aspiration probe is lowered into the sample tube (Step A2) . 4 - 75 μl of blood is aspirated into the aspiration probe (Step A3) . 5 - The aspiration probe is raised out of the tube, being cleaned while it rises (Step A4) . 6 - A check is performed to ensure the aspiration probe is completely raised (Step A5). 7 - The aspiration probe moves to a point directly over the HGB cup (Step A6) . 8 - The vent assembly rises to withdraw from the sample tube cap (completion of step A7) . 115 116 9 - The aspiration probe is lowered slightly toward the HGB cup (Step A8) . 10 - 18.75 μl of blood is deposited into the HGB cup for HGB analysis (Step A9) . 11 - The aspiration probe moves to a position directly over the WBC cup (Step A10). 12 - 18.75 μl of blood is deposited into the WBC cup for WBC analysis (Step All) . 13 - The aspiration probe moves to a position directly over the RBC cup (Step A12) . 14 - The aspiration probe is lowered into the RBC cup (Step A13) . 15 - A valve supplying diluent to the aspiration probe is opened (Step A14) 16 - 2000 μl of diluent is dispensed through the aspiration probe, along with the remaining 18.75 μl of blood, into the RBC cup for RBC and platelet analysis (Step A15) . 17 - 1000 μl of the blood/diluent mixture is aspirated into the aspiration probe from the RBC cup (Step A16) 18 - The aspiration probe is raised and cleaned (Step A17) . 19 - The aspiration probe is moved to a position directly over the RETIC cup (Step A18) . 20 - The aspiration probe is lowered slightly toward the RETIC cup (Step A19) . 21 - 200 μl of the blood/diluent mixture is dispensed from the aspiration probe into the RETIC cup for reticulocyte analysis (Step A20) . While 600 μl of retic reagent is simultaneously deposited into the RETIC cup from a fixed port. 18 - The vent assembly is returned to its home position (Step A21) . 19 - The aspiration probe is moved to the wash cup (Step A22) . 116 117 20 - The aspiration probe is lowered into the wash cup (Step A23) . 21 - The aspiration probe is flushed (Step A24) . 22 - The aspiration probe is raised (Step A25) . 23 - The aspiration probe is returned to its home position (Step A26) . 24 - The instrument executes the sample processing and data analysis for HGB, WBC, RBC, platelet, and reticulocyte analyses, as described in detail in following examples (top level algorithm file mcCBCAlgorithm.ee) . 25 - The results of the analyses are stored and displayed, such as that illustrated in Figures 45A through 45F. Example 2 -- Hemoglobin (HGB) Analysis An embodiment of the invention may be used to perform hemoglobin analyses of whole blood samples. One example of such an analysis procedure follows. The steps of the sample processing are controlled by software such as that presented in Appendix A. The steps of the data analysis are controlled by software such as that presented in appendix B. 1 - 1590 μl of HGB lyse is dispensed into the HGB cup (step HI) 2 - 18.75 μl of whole blood is deposited into the HGB cup from the aspiration probe, as part of the sequence of Example 1 (step A9) . 3 - 4273 μl of HGB lyse is dispensed into the HGB cup in a manner that causes fluid mixing (step H2). 4 - About 7 seconds are allowed to lapse to allow cell lysing. 5 - The lysed HGB sample is moved though the instrument tubing to facilitate transfer to the HGB transducer (step H3) . 6 - The lysed HGB sample is pumped into the HGB transducer (step H4) . 117 118 7 - The HGB cup is drained and rinsed (step H5) . 8 - The HGB cup is filled with HGB lyse to form the reference sample (step H6) . 9 - The light transmission in the HGB transducer is read (step H7) . The transducer contains the lysed HGB sample, and this step occurs about 15-20 seconds after the mixing of the blood sample and lyse. 10 - The reference sample is moved though the instrument tubing to facilitate transfer to the HGB transducer (step H8) . 11 - The reference sample is forced into the HGB transducer (step H9) . 12 - The syringe pump used to dispense HGB lyse is reset (step H10) . 13 - The HGB cup is drained (step HID . 14 - Backlash is removed from the HGB lyse syringe pump (step H12) . 15 - The optical transmission of the reference sample in the HGB transducer is read (step H13) . 16 - The data from the sample and reference sample are stored in a file for subsequent analysis, described in steps 17-22 and executed by the algorithm file mcRBCAlgorithm.ee. 17 - Analysis variables and flags are initialized (subroutines ParamDefaults and ClassFlagDefaults) . 18 - The HGB data is transferred from a data file to local storage (subroutine GetHGBData) . 19 - Hemoglobin concentration is calculated as HGB = log (ref measurement/sample measurement) * 0.64 * (calibration factors) (subroutine DoHGBAnalysis) . 20 - Calculate cellular HGB parameters (subroutine DoHGBAnalysis) , using parameters RBC (red blood cell concentration) and HCT (hematocrit) determined by RBC analysis described later: Mean Cell Hemoglobin MCH = HGB / RBC * (unit conversion factor) 118 119 Mean Cell Hemoglobin Concentration MCHC = HGB * (unit conversion factor) / HCT 21 - Set HGB flags if any results are abnormal or suspect (subroutine SetHgbFlags) . 22 - Return analysis results and flags for storage (subroutines SendNumResults and SendAlertResults) and display on display device. Example 3 : Red Blood Cell (RBC) and Platelet (PLT) Analysis 17.5 microliter of a blood sample is rapidly mixed with 7400 microliter of the reagent of the present invention (1:420 dilution), and 0.5 microliters of the diluted sample is passed through a hyrodyna ically focused (sheathed) impedance transducer 174 for 12 seconds for red blood cell counts and volume measurement as well as platelet counts. Additionally, 2.5 microliters of the diluted sample is passed through a sheathed optical flow cell 170 for 6 seconds for accurate and precise platelet counts. Noise signals from fragments of fragile abnormal cells are excluded from the optical platelet counts by bracketing the platelet population accurately by a platelet algorithm. An embodiment of the present invention was used to perform red blood cell (RBC) and platelet (PLT) analyses of whole blood samples as described above. One example of such an analysis procedure follows. The steps of the sample processing are controlled by software such as that presented in appendix A. The steps of the data analysis are controlled by software such as that presented in appendix B. 1 - The RBC cup is drained (step RBC1) . 2 - 2.2 ml of RBC diluent is dispensed into the RBC cup with the RBC diluent syringe (step RBC2) . 119 120 3 - 18.75 μl of whole blood and 2000 μl of RBC diluent is dispensed via the aspiration probe into the RBC cup, as described in Example 1 (step A15) . 4 - 3.2 ml of diluent is dispensed into the RBC cup with the RBC diluent syringe (step RBC3 ) . 5 - The blood and diluent mixture is moved to the vicinity of the impedance transducer with the RBC peristaltic pump (step RBC4) . 6 - The RBC delivery syringe is filled (step RBC5) . 7 - Diluent flow is initiated through the optical transducer (step RBC6) . 8 - The blood and diluent mixture is moved to the vicinity of the optical transducer with the optical peristaltic pump (step RBC7) . 9 - The blood and diluent mixture is advanced toward the impedance transducer with the RBC delivery syringe (step RBC8) . 10 - The blood and diluent mixture is sent through the optical transducer at about 52 μl/sec with the optical delivery syringe (step RBC9) . 11 - Flow through the optical transducer is reduced to about 2.5 μl/second (step RBC10) . 12 - The blood and diluent mixture is sent through the impedance transducer at about 0.5 μl/second with the RBC delivery syringe (step RBC11) . 13 - Data is collected from the optical transducer (step RBC12) . A hardware gate is applied to collect only data corresponding to platelets. 14 - Data is collected from the impedance transducer (step RBC13) . A hardware gate is used to collect and separate data relating to platelets (< 35 fL) and data relating to red blood cells (> 30 fL) , based on the magnitude of the impedance spikes. 15 - The RBC cup is drained (step RBC14). 16 - The RBC diluent syringe is reset (step RBC15) . 120 121 17 - The RBC cup is filled with diluent (step RBC16) . 18 - The RBC cup is drained (step RBC17). 19 - Backlash is removed from the RBC diluent syringe (step RBC18) . 20 - RBC lines to the optical transducer are rinsed (step RBC19) . 21 - The impedance transducer is back flushed (step RBC20) . 22 - Other RBC lines are flushed (step RBC21) . 23 - The RBC delivery syringe is reset (step RBC22) . 24 - Backlash is removed from the RBC delivery syringe. 25 - Data from the impedance transducer and optical transducer are saved in a file for use in subsequent RBC analysis (steps 26-34, executed by the algorithm file mcRBCAlgorithm.ee) and platelet analysis (steps 35-50, executed by the algorithm file mcPLTAlgorithm.ee). 26 - Flags and parameters are initialized (subroutines ParamDefaults and ClassFlagDefaults) . 27 - RBC impedance data are retrieved from a file and stored locally (subroutine GetRBCData) . 28 - A 256 bin histogram of RBC impedance values is generated (subroutine mmHist256) . 29 - Bin thresholds are set for the histogram as follows (subroutine BinCut) : a. The histogram mode is determined. b. On either side of the mode, the first bin with a population less than 0.04 times the population of the mode is identified. These limits are termed the discriminants, and only values between them are used for calculating distribution parameters RDW (RBC Distribution Width) and MCV (Mean Cell Volume) . c. To the left (i.e., for lower values of RBC volume) of the lower bin threshold, the first valley or zero count bin, if present, is identified and set as the count 121 122 threshold. Values greater than this threshold are considered to be due to RBCs. 30 - RBC (red blood cell concentration) is calculated (subroutine CalcRedConc) : RBC = (number of events) * (proportion that are RBCs) * (dilution ratio) * (coincidence correction factor) * (calibration factors) / (flow rate * measurement time); where number of events is the number of cells detected by the hardware gate in step 14; proportion that are RBCs is the histogram count to the right of the count threshold divided by the total histogram count. Coincidence correction factor accounts for double cell counting and equals 2 - exp (uncorrected RBC concentration * transducer volume/dilution ratio) 31 - Calculate MCV and RDW (subroutine CalcRedDist) : MCV = (mean of histogram between discriminants) * (0.8 fL per bin) * (calibration factor) RDW = standard deviation of RBC volume/mean cell volume (within discriminants) 32 - Set RBC associated flags to indicate abnormal analysis results (subroutine SetRb Flags) . 33 - Numerical and flag RBC results are returned to the system for storage and display (subroutines SendNumResults and SendAlertResults) . Examples of RBC numerical results are shown in Figures 45A-45F. 34 - A histogram is generated for storage and display of RBC volume values (subroutine MakeDisplayHist) . Examples of RBC volume histograms are shown in Figures 45A-45F and Figure 46. 35 - Flags and parameters are initialized (subroutines ParamDefaults and ClassFlagDefaults) . 36 - Optical and impedance platelet data are retrieved from a file and stored locally (subroutines GetPLTiData and GetPLToData) . Impedance data consists of impedance values 122 123 representing platelet volumes. Optical data consists of polarized side scatter (PSS) and intermediate angle scatter (IAS) optical values. 37 - A 265 bin histogram of impedance platelet data is generated (subroutine mmHist256) . This represents volume values ranging from 0 to 35 fL. 38 - Bin thresholds are set on either side of the histogram mode (subroutine BinCut) , as follows: a. The first bins on either side of the mode whose count is less than 0.04 times the count of the mode are identified. b. A second peak beyond the original threshold is identified, if it exists, along with the valley between such a peak and the mode. c. If a second peak exists and the count in the valley is less than 0.02 times the count of the mode, the threshold is moved to the valley. 39 - PLTi, the platelet concentration based on impedance values (subroutine CalcPLTiConc) : PLTi = (number of events) * (proportion that are platelets) * (dilution ratio) * (calibration factors) / (flow rate * measurement time) ; where number of events is the number of cells detected by the hardware gate in step 14; proportion that are platelets is the histogram count to the right of the left threshold divided by the total histogram count. 40 - Platelet distribution parameters MPV (mean platelet volume) and PDW (platelet distribution width) are calculated (subroutine CalcPLTDist) : MPV = (bin number of mean of histogram values between thresholds) * (0.137 fL per bin) * (calibration factors) PDW = (standard deviation of platelet volume values between thresholds) / (mean platelet volume) 123 124 41 - Impedance associated platelet flags are set to abnormal analysis results (subroutine SetPLTiFlags) . 42 - A noise gate is applied to the optical platelet data at log(PSS) = 8.0 (subroutine PLToNoiseGate) . 43 - Regression band gates are applied to the remaining optical platelet data as follows (subroutine PLToRegressBandGate) : a. A linear regression is calculated for the optical platelet data above the noise gate in the analysis plane log (IAS) vs. log(PSS), along with a standard error estimate for this regression. b. The upper regression band gate is drawn parallel to and at a distance of 2.0 standard errors above the regression line. c. The lower regression band gate is drawn parallel to and at a distance of 2.5 standard errors below the regression line. 44 - The optical platelet data above the noise gate and between the regression band gates is checked for an upper population (subroutine PLToFindUpperPopulation) : a. The remaining points are projected on the regression line of step 43 b. A 256 bin histogram is generated, reduced to 64 bins by averaging, filtered with a 7 pin boxcar filter, and expended to 256 bins by interpolating. c. A mode is identified in the lower 2/3 of the histogram. d. The upper 1/4 of the histogram is searched for a second peak. e. If a second peak in the upper 1/4 exists, the upper population gate is set at the valley between the mode and the second peak. Otherwise, the upper population gate is set at the right edge of the histogram. Cells not previously excluded that are above this gate are the "upper population." 124 125 Cells not previously excluded that are below this gate are the "lower population." f. The upper population is compared to a set of criteria to determine if it includes microcytic RBCs. If so, a warning flag is set. 45 - The optically determined platelet concentration (PLTo) is calculated (subroutine CalcPLToParams) : PLTo = (number of events) * (proportion that are platelets) * (dilution ratio) /(flow rate * measurement time) where number of events is the number of optical events counted by hardware that fall within the square hardware gate in log(IAS) vs. log(PSS) space; proportion that are platelets is the count of the upper population divided by the sum of the counts of the upper and lower populations. 46 - The plateletcrit (PCT, or fraction of whole blood comprised of platelets) is calculated (subroutine CalcPCT) : PCT = PLTo * MPV * (unit conversion factor) 47 - Flags associated with optically determined platelet parameters are set to indicate abnormal results (subroutine SetPLToFlgs) . 48 - Numerical results and flags associated with optically determined platelet parameters are returned to the system for storage and display (subroutine SendNumResults and SendAlertResuls) . Examples of platelet numerical results are shown in Figures 45A-45F, Figures 47 and 48. 49 - A histogram of platelet impedance values is generated for storage and display (subroutine MakeDisplayHist) . Example of platelet impedance histogram is shown in Figure 47. 50 - A scattergram of platelet optical values and gates is generated for storage and display (subroutine SendScatResults) . Examples of platelet scattergrams are shown in Figures 45A-45F, Figures 47 and 48. 125 126 Example 4 -- White Blood Cell (WBC) Differential Analysis An embodiment of the invention may be used to perform white blood cell (WBC) differential analysis of whole blood samples. One example of such an analysis procedure follows. The steps of the sample processing are controlled by software such as that presented in appendix A. The steps of the data analysis are controlled by software such as that presented in appendix B. 1 - The WBC cup motor begins the mixing motion of the cup (step Wl) . 2 - 1275 μl of WBC lyse is dispensed into the WBC cup with the WBC diluent syringe (step W2) . 3 - 37.5 μl of whole blood is deposited into the WBC cup by the aspiration probe (step A9 of Example 1) . 4 - The WBC diluent syringe is reset (step W3) . 5 - The WBC diluent syringe is moved to remove backlash (step W4) . 6 - About 9.4 seconds is allowed to elapse after the mixing of the blood sample and WBC lyse. 7 - Sheath flow is initiated in the optical transducer (step RBC6 of Example 3) . 8 - The blood and lyse mixture is moved to the optical transducer line using the HGB peristaltic pump (step W5) . 9 - The WBC cup is drained and rinsed (step W6) . 10 - A valve realignment allows the WBC sample flow through the optical transducer (step W7) . 11 - WBC sample flow begins through the optical transducer at about 27.6 μl/sec with the optical delivery syringe (step W8) . 12 - The WBC sample flow rate is reduced to about 2.5 μl/second (step W9) . 13 - Optical WBC data is collected by the optical transducer (step W10). 14 - The optical delivery syringe is reset (step Wll) . 126 127 15 - Backlash is removed from the optical delivery syringe (step W12) . 16 - Data from the optical transducer are saved in a file for use in subsequent WBC differential analysis (steps 17 - XX, executed by the algorithm file mcWBCAlgorithm.ee) . 17 - WBC data is retrieved from a file and stored locally (subroutine GetWBCData) . This data consists of axial light loss (ALL) , intermediate angle scatter (IAS) , polarized side scatter (PSS), depolarized side scatter (DSS), and red fluorescence (FL3) values for each detected event. Steps 18 - 22 identify nucleated red blood cells (NRBCs) . 18 - A 256 bin histogram of FL3 values is generated (subroutine mmHist256) . 19 - The events are divided into "high FL3 " or "low FL3" by identifying a valley in the vicinity of log(FL3)=100 (subroutine FindFl3Cells) . An example of this division is illustrated in Figures 49A and 49B. 20 - A histogram of the ALL values of the high FL3 cells is generated (subroutine mmHist256) . An example of this histogram is illustrated in Figures 50A and 50B. 21 - A peak is identified at a value of less than ALL=75, if it exists (subroutine AnalyzeFl3Cells) . If it does not exist, no NRBCs are reported. 22 - If a peak at ALL<75 exists, the events with a PSS value greater than the PSS threshold (about 45) are classified as NRBCs and undergo no further analysis. Steps 23 - 26 identify neutrophils and eosinophils, 23 - A plot of all events on the plane PSS vs. ALL is used to identify the two largest peaks, which are the neutrophil peak and the monocyte peak (subroutine FindMGLine) . 127 128 24 - A line is drawn between the two peaks. Starting at the minimum value along this line, a dividing line is drawn between the granulocytes (above the line) and mononuclear cells (below the line) (subroutine FindMGLine, continued) . An example of the dividing line is illustrated in Figures 51A and 51B. 25 - For the granulocytes (above the line) , a histogram of the values of arctan(DSS/PSS) is generated (subroutine FindNELine) . 26 - The histogram of step 25 is searched for a valley between the angular values of 10 a and 31 a (subroutine FindNELine continued) . Cells with an angular value of arctan(DSS/PSS) greater than this valley are classified as eosinophils, and the cells with angular values less than this valley are classified as neutrophils. An example of this histogram and angular dividing line is illustrated in Figures 52A and 52B. Steps 27 - 28 identify monocytes and stroma. 27 - From the remaining cells, a 256 bin histogram of ALL values is generated (subroutine mmHist256) . 28 - The ALL histogram is searched for two valleys, in the high region (bins 100-160) and in the low region (bins 45- 75) . Cells above the upper valley are classified as monocytes. Cells below the lower valley are classified as stroma (subroutine FindLymphLines) . An example of the ALL histogram and dividing lines is illustrated in Figure 53. Steps 29 - 30 are used to identify lymphocytes. 29 - From the remaining cells, a 256 bin histogram is generated of IAS values (subroutine mmHist256) . 30 - A valley is identified, if it exists, between bins 70 and 110. If such a valley does not exist, a dividing line is 128 129 drawn at a value equal to the mean of the IAS values plus 2.5 times the standard deviation of the IAS values. Cells to the left of this valley or line are classified as lymphocytes. An example of this division is illustrated in Figure 54. Steps 31-32 are used to identify basophils. 31 - From the remaining cells, a 256 bin histogram of ALL values is generated (subroutine mmHist256) . 32 - A valley in the ALL histogram is identified, if it exists, between 1/4 and 3/4 of the distance from the lymphocyte-stroma and lymphocyte-monocyte separation lines determined in step 28. If no such valley exists, a default dividing line is drawn at half of this distance. Cells with ALL values above this line are classified as basophils. Events with ALL values below this line are classified as noise (subroutine FindBasoLines) . An example of this division is illustrated in Figure 55. 33 - Histograms and statistics are generated for each classified population (subroutine DoPopStats) . 34 - Alert flags are set for any abnormal analysis results (subroutine SetFlags) . In particular, this step includes performing a statistical check for the presence of lyse- resistant RBCs and for blasts. A blast alert flag is set if a weighted combination of the following statistics is above a threshold value (about 3.874): 129 13 0 Population Statistic Weighting Factor Monocyte percentage 0.030352 Mean of lymphocyte ALL 0.013182 Mean of monocyte ALL 0.016766 Coefficient of variation of monocyte 0.152739 ALL Coefficient of variation of monocyte -0.041058 IAS Mean of monocyte PSS -0.051015 Coefficient of variation of monocyte 0.028661 PSS Coefficient of variation of -0.02960 lymphocyte and monocyte PSS Mean of all WBC FL3 0.024813 35 - All numerical results and alert flags are returned to the system for storage and display (subroutines SendNumResults and SendFlagResults) . 36 - A scattergram set is generated and sent to the system for storage and display (subroutine SendScatResults) . A typical display will present ALL vs. IAS, DSS vs. PSS, and ALL vs. FL3, as illustrated in Figures 45A-45F. Example 5 -- Reticulocyte Analysis An embodiment of the invention may be used to perform reticulocyte analyses of whole blood samples. One example of such an analysis procedure follows. The steps of the sample 130 131 processing are controlled by software such as that presented in appendix A. The steps of the data analysis are controlled by software such as that presented in appendix B. The scatterplots generated by this analysis is exemplified in figures 14A and 14B. 1 - Analysis begins with an empty RBC cup. 2 - 2200 μl of RBC diluent is dispensed into the RBC cup with the RBC diluent syringe (step RBC2) . 3 - 18.75 μl of whole blood and 2000 μl of RBC diluent is dispensed via the aspiration probe into the RBC cup, as described in Example 1 (step A15) . 4 - 3656 μl of diluent is dispensed into the RBC cup with the RBC diluent syringe (step RBC3). A dilution ratio of about 420:1 is produced. 5 - 500 μl of the blood/diluent mixture is aspirated into the aspiration probe from the RBC cup (Step A16) 6 - The aspiration probe is raised and cleaned (Step A17) . 7 - The aspiration probe is moved to a position directly over the RETIC cup (Step A18) . 8 - The aspiration probe is lowered slightly toward the RETIC cup (Step A19). 9 - 200 μl of the blood/diluent mixture is dispensed from the aspiration probe into the RETIC cup for reticulocyte analysis (Step A20) . 10 - 600 μl of reticulocyte stain is dispensed through a fixed port into the RETIC cup with the reticulocyte diluent syringe (step Rl) . A dilution ratio of about 1680:1 is produced. 11 - The reticulocyte diluent syringe is reset (step R2) . 12 - The reticulocyte sample is transferred to near the optical flowcell with the RBC peristaltic pump (step R3) . 13 - Brief backflow in the WBC sample line to the optical flowcell is initiated to prevent carryover (step R4) . 14 - The RETIC cup is drained (step R5) . 131 132 15 - Reticulocyte sample flow is initiated through the optical flowcell at 78 μl/sec using the optical delivery syringe (step R6) in order to displace fluid line dead volume. 16 - Reticulocyte sample flow through the optical flowcell is reduced to about 2.0 μl/sec (step R7) . 17 - The RETIC cup is filled with diluent to rinse (step R8) . 18 - Reticulocyte data is collected in the optical transducer (step R9) . A hardware gate collects data for each optical event with an intermediate angle scatter (IAS) value greater than a certain threshold value. 19 - The RETIC cup is drained, rinsed, and drained (step RIO) . 20 - The optical delivery syringe is reset (step Rll) . 21 - Reticulocyte sample delivery lines are rinsed (step R12) . 22 - Backlash is removed from the optical delivery syringe (step R13) . 23 - Reticulocyte optical data is stored in a file for subsequent analysis. The analysis of steps 24 - 33 is controlled by the algorithm file mrRETCAlgorithm.ee. 24 - Data is retrieved from a file and stored locally (subroutine GetRETCData) . This data consists of intermediate angle scatter (IAS) and green fluorescence (FLl) values. 25 - A 256 bin histogram of log(IAS) values is generated (subroutine mmHist256) . 26 - A valley is identified between channels 150 and 190, if it exists. Cells with log(IAS) values lower than this valley (or 170, if no valley exists) are considered platelets and removed from further analysis (subroutine FindPLTs) . An example of this histogram and dividing line is illustrated in Figure 56. 27 - From the remaining cells, a 256 bin histogram of log (FLl) values is generated (subroutine mmHist256) . 132 133 28 - A valley is identified, if it exists, in the upper region of this histogram (between bins 175 and 225) . Cells with log (FLl) values greater than this valley (or 200, if no valley exists) are considered WBCs and removed from the analysis (subroutine FindWBCs) . 29 - The log(FLl) histogram is searched for a valley to the right of the major (RBC) peak. If such a valley exists, cells to the right of it are classified as reticulocytes. If no valley exists, a dividing line is put at channel 120 (default reticulocyte cursor) Cells to the right of this dividing line are classified as reticulocytes (subroutine FindRETCs) . Examples of this histogram and the dividing lines are illustrated in Figures 45F and 57. 30 - The reticulocyte maturity index (RMI) is calculated. This value is equal to the percentage of reticulocytes that fall in a "high FLl" region, defined as having log(FLl) histogram bins higher than the lower reticulocyte boundary (as established in step 29) plus a fixed value (about 24) (subroutine GetFionalCounts) . 31 - Numerical results are returned to the system for storage and display (subroutine SendNumResults) . 32 - A scattergram is generated for storage and display (subroutine SendScatResults) . An example of a reticulocyte scattergram is illustrated in Figures 14A and 58. 33 - A histogram of log(FLl) values is generated for display and storage (subroutine SendHistResults) . Examples of reticulocyte histograms are illustrated in Figures 14B, 45F and 59. Example 6 -- Lymphocyte Immunophenotyping Analysis An embodiment of the invention may be used to perform lymphocyte immunophenotyping analysis of whole blood samples. One example of such an analysis procedure follows. The steps of the sample processing are controlled by software such as 133 134 that presented in appendix A. 1. 100 μl of whole blood is aspirated by the aspiration probe and deposited into the transfer cup (subroutine subasp.f) . This volume may be adjusted if necessary to provide enough blood to execute all of the desired immunophenotyping assays for that sample. 2. The incubation probe aspirates about 70 μl from the transfer cup and deposits in the appropriate number of incubation cups (subroutine subprep.f) . 3. Reagents such as antibody reagents for immunophenotyping are aspirated by the incubation probe and deposited in the appropriate incubation cups (subroutine subinc. f) . 4. An appropriate time delay occurs for incubation. 5. About 670 μl of wbc diluent is added to the WBC cup. This and the following sample processing steps (5 through 8) are controlled by software such as that in subroutine subvu. f. 6. Following incubation, about 30 μl of the sample is aspirated by the incubation probe and deposited in the WBC cup. 7. The sample and diluent mixture is mixed by the WBC cup for about 5 seconds. 8. The mixture is sent through the optical transducer for measurement of optical properties. The properties measured may include axial light loss (ALL) , intermediate angle scatter (IAS) , and two fluorescence values (FLl and FL2) . 9. The data is stored for subsequent analysis. General analysis steps may include those listed here. 10. A plot of ALL vs. IAS values is created divided into polar bivariate regions. Such regions are bounded by radii and arcs stemming from an origin. The origin may be varied, but is usually positioned at the maximum ALL limit and the 134 135 zero IAS point. See Figure 60A. 11. A second plot of log(FL2) vs. log(FLl) is created and divided into polar bivariate regions. The origin for this division is usually at (0,0). An illustration of an example of both the ALL vs. IAS plot and the log(FL2) vs. log(FLl) plot is presented in Figures 60A and 60D. 12. Both plots are searched counterclockwise and then radially outward for lymphocyte peaks. Thresholds are set at 1/10 the peak heights. Cells whose associated data points lie within the thresholds are considered lymphocytes. 13. The number of lymphocyte events in each plot is counted and compared to each other and to the hematological lymphocyte count to detect possible errors. See Figures 60B, 60C, 60E and 60F. 14. Statistical analysis may further refine the limits of IAS and ALL values that most specifically identifies lymphocytes. This delineation may form ellipsoids, polygons, or other geometric areas within the ALL vs. IAS analysis space. 15. Analysis of the same sample treated with different antibody reagents may proceed. Cells are considered for analysis only if their IAS and ALL values fall within the limits determined by the lymphocyte identification (steps 10 through 14) . Example 6A -- Measurement of T Helper Subset An embodiment of the invention may be used to measure the fraction of lymphocytes that are T Helper cells, by following a procedure similar to the following: 1. A portion of a whole blood sample is incubated with a reagent mixture including fluorescently labelled antibodies that will bind to CD45 receptors on WBCs and emit fluorescence detectable by one of the two fluorescence 135 13 6 detectors (FLl or FL2) and fluorescently labelled antibodies that will bind to both CD13 and CD14 receptors on WBCs and emit fluorescence detectable by the other of the two fluorescence detectors. In this Example, the CD45 antibody is bound to fluorescein isothiocynate (FITC) and the CD13 and CD14 antibodies are bound to phycoerythrin (PE) . Typical incubation occurs for about 15 minutes at ambient temperature. 2. A second portion of the same whole blood sample is incubated with a reagent mixture including fluorescently labelled antibodies that will bind to CD3 receptors on WBCs and emit fluorescence detectable by one of the two fluorescence detectors (FLl or FL2) and fluorescently labelled antibodies that will bind to CD4 receptors on WBCs and emit fluorescence detectable by the other of the two fluorescence detectors. In this Example, the CD3 antibodies are bound to FITC and the CD4 antibodies are bound to PE. 3. The first incubated blood sample is analyzed in a manner similar to that described in Example 6. This analysis yields a region of IAS and ALL values (the lymphocyte gate) that corresponds to lymphocytes, which are characterized by the presence of CD45 receptors and the absence of CD13 and CD14 receptors. A plot of fluorescence levels corresponding to CD13/CD14 activity and CD45 activity and the resulting designation of lymphocytes is presented in Figure 61A. A plot of the IAS and ALL values for the same cells and the resulting lymphocyte gate is presented in 61B. 4. The purity of the lymphocyte gate procedure may be determined by calculating the fraction of all cells within the lymphocyte gate that demonstrate the presence of CD45 receptors and the absence of CD13 and CD14 receptors, as indicated by the levels of fluorescence detected by the FLl and FL2 detectors. A plot of the fluorescence levels corresponding to CD13/CD14 activity and CD45 activity for cells within the lymphocyte gate is presented in Figure 61C. 136 137 5. The second incubated blood sample is analyzed in a manner similar to that described in steps 1 through 8 of Example 6. Each cell whose values of IAS and ALL fall within the lymphocyte gate is characterized as positive or negative for each of the two antibodies within the reagent mixture (CD3 and CD4) , based on a comparison of the detected levels of FLl and FL2 to fluorescence levels of control cells incubated with an antibody mixture considered to be non- binding and labelled with PE and FITC. The fluorescence levels of the control cells (representing negative reactions) are illustrated in Figure 61D. 6. The fraction of lymphocytes that are T Helper cells is determined as the fraction of cells within the lymphocyte gate that are positive for CD3 and positive for CD4. A plot of the fluorescence levels corresponding to CD3 activity and CD4 activity for cells within the lymphocyte gate, showing the fraction that are positive for both, is presented in Figure 6IE. 7. The concentration of T Helper cells may be determined as the fraction of lymphocytes that are positive for CD3 and positive for CD4 (determined in step 6) times the lymphocyte count determined in the WBC differential analysis described in Example 4. Example 6B -- Measurement of T Suppressor Subset A similar procedure may be used to quantify the lymphocyte subset of T Suppressor cells, characterized by being positive for both CD3 and CD8. 1. A portion of a whole blood sample is incubated with a reagent mixture including fluorescently labelled antibodies that will bind to CD45 receptors on WBCs and fluorescently labelled antibodies that will bind to both CD13 and CD14 receptors on WBCs, as in step 1 of Example 6A. Analysis of 137 138 this incubated sample is executed as described in steps 3 and 4 of Example 6A, yielding a lymphocyte gate. Typical incubation occurs for about 15 minutes at ambient temperature. 2. A second portion of the same whole blood sample is incubated with a reagent mixture including fluorescently labelled antibodies that will bind to CD3 receptors on WBCs and emit fluorescence detectable by one of the two fluorescence detectors (FLl or FL2) and fluorescently labelled antibodies that will bind to CD8 receptors on WBCs and emit fluorescence detectable by the other of the two fluorescence detectors. In this Example, the CD3 antibodies are bound to FITC and the CD8 antibodies are bound to PE. 3. The second incubated blood sample is analyzed in a manner similar to that described in steps 1 through 8 of Example 6. Each cell whose values of IAS and ALL fall within the lymphocyte gate is characterized as positive or negative for each of the two antibodies within the reagent mixture (CD3 and CD8) , based on a comparison of the detected levels of FLl and FL2 to control fluorescence levels. 4. The fraction of lymphocytes that are T Suppressor cells is determined as the fraction of cells within the lymphocyte gate that are positive for CD3 and positive for CD8. A plot of the fluorescence levels corresponding to CD3 activity and CD8 activity for cells within the lymphocyte gate, showing the fraction that are positive for both, is presented in Figure 61F. 5. The concentration of T Suppressor cells may be determined as the fraction of lymphocytes that are positive for CD3 and positive for CD8 (determined in step 5) times the lymphocyte count determined in the WBC differential analysis described in Example 4. 138 139 Example 6C -- Measurement of T and B Lymphocytes The number of T and B lymphocytes may be measured using a procedure similar to that described in Examples 6A and 6B. The first incubated sample, used to establish the lymphocyte gate, is the same mixture of CD45 and CD13/CD14 labelled antibodies as in Examples 6A and 6B. The second portion of the blood sample is incubated with a mixture of CD3 antibodies (labelled with FITC) and CD19 antibodies (labelled with PE) . The fractions of T cells and B cells are determined from the fraction of cells that are CD3 positive and CD19 negative (T cells) and the fraction that are CD3 negative and CD19 positive (B cells) . A plot of the fluorescence levels corresponding to CD3 activity and CD19 activity, indicating the fractions of T cells and B cells, is presented in Figure 61G. The validity of the lymphocyte subset measurements described in these Examples is demonstrated by comparing the analysis results using an embodiment of this invention with results of conventional manual flow cytometry assays. The results of such a comparison, between an embodiment of the current invention (termed BB3) and conventional analyses on a FACScan system by Becton Dickinson Immunocytometry Systems, are presented in Figures 62A-62D. The plots in Figures 62A-62D illustrate the correlation between fractions of lymphocytes that are positive for both CD3 and CD4 (Figure 62A) , positive for both CD3 and CD8 (Figure 62B) , positive for CD19 (Figure 62C) , and positive for CD3 alone (Figure 62D) . Exam le 7 NRBC Analysis Twenty five (25) μl of a whole blood clinical sample, are mixed on-line in the cell analysis instrument system disclosed above, with 675 μl of the multipurpose reagent, 139 140 pre-warmed at 42°C in the WBC cup 138. The sample/reagent are mixed and incubated for 11 seconds. This mixture is then transported to the flow cell 170 which takes approximately 8 and 1/2 seconds for a WBC/Diff/NRBC analysis. Figures 40A-40C and 41A and 41B show the result of this analysis on sample containing 56NRBC/100WBC and 140 NRBC/100 WBC, respectively. 140 141 APPENDIX A 141 142 /** / * /* Copyright 1994 by Abbott Laboratories /* Source Code Control System keywords /* /* NAME: $Source: /tmp/RCS/cbc2.f,v $ /* $Locker: $ /* $State: R4 $ /* $Revision: 1.2 $ /* $Author: rodl $ /* $Date: 94/11/23 09:58:04 $ /* Log: .. See below /* /* LANGUAGE: CD4000 Flow sequence language /* /* DESCRIPTION: /* /* .... $Log: cbc2. f,v $ /* Revision 1.2 94/11/23 09:58:04 rodl /* fixed standard header /* / *_. /*/ BEGIN CBC2 (isretic) IF (isretic == 1) JOIN RETICVU FORK CLNRUP 142 143 JOIN CLNRUP ENDIF IF (isretic == 0 ] JOIN CBS2 FORK CLNHUP JOIN CLNHUP ENDIF /FREEID sampid END /** /* /* Copyright 1994 by Abbott Laboratories /* Source Code Control System keywords /* /* NAME: $Source: /tmp/RCS/cbcr. f,v $ /* $Locker: $ /* $State: Exp $ /* $Revision: 1.9 $ /* $Author: rodl $ /* $Date: 95/04/11 16:07:32 $ /* Log: .. See below /* /* LANGUAGE: CD4000 Flow sequence language /* /* DESCRIPTION: /* /* ... $Log: cbcr. f,v $ /* Revision 1.9 95/04/11 16:07:32 rodl /* Add s at mode variable. /* 143 144 /* Revision 1.8 95/03/13 15:21:12 rodl /* Change timing reference callouts. No functional change. /* /* Revision 1.7 95/03/08 18:15:25 davef /* added isretic parameter to list passed to cbs FSQ /* /* Revision 1.6 94/12/28 19:50:50 rodl /* Return piercing responsibility to cbs.f and add delay to account for longer /* piercing in cbs.f. /* /* Revision 1.5 94/12/14 10:37:42 rodl /* Add delay consistant with delay in autosampler version of cbs to prevent /* aspz crash. /* /* Revision 1.4 94/11/29 11:04:31 rodl /* Adds a delay to allow for the saspiration probe and piercer to visit the /* autosampler in cbs.f. Causes crashes so still needs work. /* /* Revision 1.3 94/11/16 22:04:19 rodl /* Further modularized shell allows for overlap of adjacent sequences. /* /* Revision 1.2 94/11/10 18:08:59 rodl /* Changed to new more maintainable structure. No expected functionality change. Clnrup.fsq forked at sequence end for cleanup. /* /* Revision 1.1 94/09/29 23:16:52 scotts /* Initial revision /* /* Rev 1.5 29 Sep 1994 17:15:20 RODL /* Add delay to allow the piercer lock to unlock before 144 145 piercing. /* /* Rev 1.4 19 Sep 1994 22:39:48 RODL /* Change to open close statements from pats to avoid trouble , and /* change time delay for retinc fork to correct earlier timing mistake. /* /* Rev 1.3 19 Sep 1994 12:14:28 RODL /* Add better piercing. /* /* Rev 1.2 18 Aug 1994 17:42:22 RODL /* Change sampleid callout and remove obsolete variable callouts. /* /* Rev 1.1 17 Aug 1994 11:21:00 RODL /* Remove freeid callout. /* /* Rev 1.0 16 Aug 1994 16:54:52 RODL /* Initial revision. /* /* Rev 1.8.1.3 26 Jan 1994 13:56:52 RODL /* Revised for asp probe manipulation and 30 sec. retic stain. /* /* Rev 1.8 29 Oct 1992 11:36:26 DAVEF /* added inctime parameter /* /* Rev 1.7 16 Sep 1992 21:44:04 RODL /* Remove iprobe positioning from cbcr and put it into cbs. Change to handle /* sample is's better. /* /* Rev 1.6 15 Sep 1992 20:00:20 RODL /* Added .6 sec earlier entrance of retinc. 145 146 /* /* Rev 1.5 18 Aug 1992 08:29:56 RODL /* Changed name of hematology pgm from crc to cbc to conform to /* uniform hardware conditions for all breadboards. /////NOTE Should Add FORK RETINC to cbs.f by passing isretic to cbs. f and /////remove same from CBCR.F /*/ BEGIN CBCR(sampid isopenmode) VAR isxwbc VAR isretic VAR isxlyse / / Assign a sample Id for the tube / / Set variable value ; in this case the sequence does Retics, isretic = 1 isxwbc = 0 isxlyse = 0 / FORK CBS(sampid isxlyse isretic isopenmode) / / WAIT 17.5 // //T=17.5 // /Begin the retic incubation script. FORK RETINC (sampid) JOIN CBS 146 147 FORK CBS2 (sampid isretic isxwbc isopenmode) JOIN CBS2 FORK RETICVU(sampid) FORK CBC2 (isretic) END //** / * /* Copyright 1994 by Abbott Laboratories /* Source Code Control System keywords /* /* NAME: $Source: /tmp/RCS/cbs.f,v $ /* $Locker: $ /* $State: Exp $ /* $Revision: 1.49 $ /* $Author: rodl $ /* SDate: 95/05/18 01:10:07 $ /* Log: .. See below /* /* LANGUAGE: CD4000 Flow sequence language /* /* DESCRIPTION:Special HGB script with 237 as source . /* Converted to proto-type valving and piercer. Adjusted dilution /* to accomodate 25ul @35:1 However, still needs sample durations /* adjusted. Added &65 open well before wbc deposition. Provided /* .7cv for rbc's 1.1 for hgb's.Added ///xx indication for 147 148 untested /* drain valve closures to accommodate overlap. ////// FOR WRAP ///////NOTE ... TRY Remove 135 @t=16.47 ///////NOTE ... TRY V31 OPEN T=5.5 to T= 8.5 (notT=18 TO V^r=21) imp isolator (not 40-43) . ///////NOTE ... Move v33 @ t=38.18 to 7.18 or earlier b4 rbcdilsyr. ///////NOTE ... More oplt bkflsh & t=33.5 to 38 ///////REMOVE . V41 AFTER T=38 ///////NOTE ... RBCPP @ T=34 ///////TRY ... NO V47 USE .. PERHAPS REDUNDANT. ///////NOTE ... V16 65 WELL AHEAD OF APRBP MOVE. /OK AS IS //////CONSIDER MOVING 33 TO WC#1 /DONE//////NOTE ... MT OPT ISO AT BEGINNING NOT END ie at t=14 not t=44. ///////TRY ... REDUCING PIERCER CLEAN 115 T=8 TO T=15. ///////Move ... Ivldrl4 to t=14 for consistent runs ? /* /* ....$Log: cbs.f,v $ /* Revision 1.49 95/05/18 01:10:07 rodl /* Remove problematic dips into hgb and wbc cup. Causes blood to wick onto probe. Must be done more slowly and carefully. /* /* Revision 1.48 95/05/16 12:46:08 rodl /* Raise probe 2mm higher over cups to avoid hitting. /* Reduce probe rise before aspiration from 2mm to .3mm. /* Remove .6 sec delay tp prevent cbcr crashes. /* Reduce depth of rbc cup deposition to avoid scraping cup bottom. /* /* Revision 1.47 95/05/15 12:46:26 rodl /* Remove delay caused by beep routine which was causing crash in Retic mode. 148 149 /* /* Revision 1.46 95/05/09 19:23:12 rodl /* Move wbc reservoir fill routines 3 seconds later in sequence. /* /* Revision 1.45 95/05/04 18:28:33 rodl /* Deposit samples in the wbc and hgb cups from below the cup rim. /* /* Revision 1.44 95/04/20 18:40:43 rodl /* Small fix for wbc fill routines placement. /* /* Revision 1.43 95/04/20 17:11:54 rodl /* New aspz motor. /* /* Revision 1.42 95/04/11 16:13:19 rodl /* Add stat mode functionality. /* /* Revision 1.40 95/04/05 10:23:38 rodl /* Add WBCDILSYR reset to prepare for metered rinse use of wbc syringe. /* /* Revision 1.39 95/03/28 23:52:08 rodl /* Slight mixing reduction in HGB mix to improve cv's. May effect hi wbc's. Must /* be checked. /* /* Revision 1.38 95/03/14 16:50:31 rodl /* Fix bad valve - syringe coordination problem with rbcdilsyr. /* /* Revision 1.37 95/03/13 15:09:05 rodl /* Change timing reference values. No functional change. /* /* Revision 1.36 95/03/10 11:32:50 rodl 149 150 /* fixed marginal timing on retic ASPZ processing /* /* Revision 1.35 95/03/08 18:17:45 davef /* added isretic parameter to list and test before /* signalling autosampler to advance /* /* Revision 1.34 95/03/02 19:11:20 davef /* temporarily removed problematic aspz not up error detection /* , /* /* Revision 1.33 95/02/22 17:16:06 rodl /* Move rbcdilsyr move to 0.7 sec later to retain some mixing motion during /* the blood deposition phase from the initial deposition of diluent. /* /* Revision 1.32 95/02/07 21:59:49 rodl /* Change dilution factor in response to new lyse formulation. /* /* Revision 1.31 95/02/07 20:43:49 rodl /* Reduce HGB mix in response to new lyse formulation.Also remove needless v235 /* callouts at sequence end. /* /* Revision 1.30 95/01/27 11:21:03 rodl /* Power aspy HIGH MED instead of HIGH LOW. /* /* Revision 1.29 95/01/26 21:11:31 rodl /* Add syringe calc's for hgb and wbc dil syringes . No fub nctional change since previous version. /* /* Revision 1.28 95/01/26 13:36:29 rodl /* Does well with HGB normals and gives reasonable <2% cv 150 151 w/120k wbc samples. /* /* Revision 1.27 95/01/18 22:01:15 rodl /* Shorten hgb vacuum draw and peripump draw to prevent taking upper half of hgb /* mix because of concern for hi wbc samples in hgb. HGB cv=.6% rbc cv .7% wbc /* cv=1.8% §3600 events (1.6% poisson) . /* /* Revision 1.26 95/01/12 12:37:23 rodl /* Increase the mixing rate (fill rate) of the HGB cup to improve unlysed wbc /* residues from confounding the HGB count with high WBC samples (>100k) . /* /* Revision 1.25 95/01/12 00:50:36 rodl /* Adds more vigorous mixing to HGB cup intended to improve hhhgb precision /* for hi white samples. Got about 4% cv's with 150 k samples (hi whites) for /* the hgb precision. With low whites the precision seems under 1%. /* /* Revision 1.24 95/01/11 21:27:18 rodl /* Add .1 seconds more delay between expected time up and asp probe check time. /* /* Revision 1.23 94/12/28 19:22:36 rodl /* Add a longer pierce accomodation at sequence beginning , causing the vent /* head to come foward before the asp. probe. Add new wbc address better centering the probe in the wbc cup. Turn of the vortexer at blood deposit. Replace cln /* prba with a dry version clnprdry at several probe moves. Close needless 135 151 152 /* open @t=18 , update time utility,though still 1 sec behind. /* /* Revision 1.22 94/12/21 18:01:39 rodl /* Add vy journey 1 sec before asp journey. Since all shells reference cbs begin /* the shells must accomodate the new timing.Still need to change shells. /* /* Revision 1.21 94/12/21 17:33:07 rodl /* New 190:1 HGB dilution 420:1 rbc dilution 35:1 WBC dilution with fairly /* comparable cv's though the jury's still out on that.WBC uses 37.5 microliters /* of blood consisting of 2 depositions. HGB and RBC get nominally 1 each. /* /* Revision 1.20 94/12/20 20:54:18 rodl /* Removed useless v345 callouts (piercer drains) whic h waste vacuum. /* /* Revision 1.19 94/12/20 17:20:25 rodl /* First autosampler sequence with reasonalbe wrap capability. /* /* Revision 1.18 94/12/20 12:13:36 rodl /* Drain rbc cup @ t=-35 not t=~5 , vl36 on @t-=17 due to lvldr27 move ahead. /* /* Revision 1.17 94/12/15 14:47:49 rodl /* Change timing slightly to allow for better piercing. Still needs a bit more /* allowance for hard to pierce tubes. Mechanical soln's also may help. /* 152 153 /* Revision 1.16 94/12/14 23:30:23 rodl /* Remove lvldr27 from here to add it to cbs2 because of wrap concerns. /* /* Revision 1.15 94/12/13 12:49:53 rodl /* Turn off vortexer during wbc blood deposition since vortex is too thin /* to be certain that blood will not reach wall. /* /* Revision 1.14 94/11/29 19:41:41 rodl /* Correct tinne utility to account for aspy delay. /* /* Revision 1.13 94/11/23 19:16:27 rodl /* Allow for autosampler use . Works ok but needs piercing help. Also the extra lyse is automato ically evoked removing the need for cbsel.f. /* /* Revision 1.11 94/11/10 18:24:22 rodl /* Truncate sequence at wbc analysis end to handoff to clnhup.f for clean.New ructure provides better maintainance of component flowscripts such as this one. /* /* Revision 1.10 94/11/04 00:23:24 rodl /* Improve rbc transfer.Works with calib of -1 on 3 machines tested. /* /* Revision 1.9 94/11/03 12:35:27 rodl /* Add a short vacuum draw to remove bubbles for hgb r transfer. /* /* Revision 1.8 94/11/03 09:18:17 rodl /* Add more optical isolator drain @ sequence beginning. /* /* Revision 1.7 94/11/02 23:58:06 rodl /* Add more emptying of isolation cups. 153 154 /* /* Revision 1.6 94/10/26 16:18:25 rodl /* Provide .3 sec more time for the hgb syr outlet valve to open before move. /* /* Revision 1.5 94/10/25 23:43:05 rodl /* Keep v212 open .4 sec longer than v232 to reduce sensitivity to valve closing time differences. May want to decrease the delay in the future between their closures. /* /* Revision 1.4 94/10/19 22:24:23 rodl /* Drain opt. isolator longer and impedance isolator longer.Increase duration of wc #1 empty by 1 second. Carry out the hgb sample earlier and for longer duration. /* /* Revision 1.3 94/10/17 19:05:43 rodl /* Add aspiration sense ter limit check at probe rise to prevent bent probes. . /* /* Revision 1.2 94/10/13 18:23:20 rodl /* Cg hange addresses of all three cups to a little furteher back. /* /* Revision 1.1 94/09/29 23:16:54 scotts /* Initial revision /* /* /* Rev 1.10 28 Sep 1994 13:30:06 RODL /* Unlock piercer before pierce at second lowering of piercer. /* /* Rev 1.9 28 Sep 1994 13:24:14 RODL /* Change the aspz moves to "TO" commands not "BY" commands. /* /* Rev 1.8 27 Sep 1994 13:19:22 RODL 154 155 /* Extend vll3 piercer lock mechanism to t=6.0. /* /* Rev 1.7 21 Sep 1994 19:40:36 RODL /* Adds "beep" at the end of aspiration. /* /* Rev 1.6 19 Sep 1994 14:55:42 RODL /* Add pat for 0 at end. /* /* Rev 1.5 30 Aug 1994 20:54:28 RODL /* Add ramp callout before ASPZ motor move, no functional change. /* /* Rev 1.3 24 Aug 1994 21:31:40 RODL /* Add note at top for future test. /* /* Rev 1.2 24 Aug 1994 16:56:20 RODL /* Remove v432 callout(dill ras vac) at T=17. /* /* Rev 1.1 18 Aug 1994 17:30:08 RODL /* Removed Iprobe moves, replaced aspz to moves with by moves. /* /* Rev 1.0 16 Aug 1994 16:55:24 RODL /* Initial revision. /* /* Rev 1.1.1.35.1.57 03 Aug 1994 14:05:24 RODL /* Alter several commands including the vy cone address (by 4 steps)and /* remove commented out commands and change from ul ref to step reference /* on rbcpp move. /* /* Rev 1.1.1.35.1.53 18 May 1994 13:25:08 RODL /* Move hgb sample transfer from 11.9 to 15.9 to allow more time for 155 15 6 /* the sample to react and settle. /* /* Rev 1.1.1.35.1.51 21 Apr 1994 10:42:18 RODL /* Add rbcdilsyr sample drawback during rbc sample transfer to /* ensure the fluid at the "T" does not influence the concentration /* of the transfered sample. /* /* Rev 1.1.1.35.1.48 29 Mar 1994 19:09:48 RODL /* Slow rbcdilsyr dilution thru probe & .040"line to 300s/s. /* /* Rev 1.1.1.35.1.47 29 Mar 1994 18:10:32 RODL /* Use 400s/s aprbp deposition speed with .040 dia teflon tubing. Dilutions /* more stable , though still outliers in rbc delivery. /* /* Rev 1.1.1.35.1.46 23 Mar 1994 19:50:24 RODL /* Ramp aprbp aspiration with 200 s/s to avoid cavitation. /* Rev 1.1.1.35.1.43 16 Mar 1994 17:12:36 RODL /* /* FOR USE WITH N.O. VALVE TO ATMOSPHERE AT ASP PROBE PUMP SOURCE. /* Rev 1.1.1.25 12 Apr 1993 14:55:40 RODL /* /* / * /*/ BEGIN CBS (sampid isxlyse isretic isopenmode) // //T=0.00 // 156 157 /Begin Vortexing the hotpot. /Open the pressurization valves for diluent res ' s & dil 2 res output. /Open the vacuum supply for all waste cups. OPEN 136 335 336 337 431 434 /Begin Vortexing the hotpot. /Move piercer and aspirator out to autosampler. /Signal user that the sequence has been started with two "beeps" . STEP Wl PAT FOR 0.7 133 118 336 337 346 113 323 IF (isopenmode == 1) OPEN 112 448 WAIT 0.2 CLOSE 448 WAIT 0.2 OPEN 448 WAIT 0.2 CLOSE 448 ENDIF / // //T=0.00 // IF (isopenmode == 0) RAMP VY SLOW400 MOVE VY BY 370 / (370 steps θ 400s/s = 0.93sec) ENDIF // /Now that piercer is out over tube begin piercing. PAT FOR 2.1 133 118 336 337 346 113 323 // 157 158 //T=0.70 // /For nonstat samples now that piercer is out over tube begin piercing. /The asp assy is now ready from previous run to begin aspiration. IF (isopenmode == 0) / / STEP Al OPEN 111 /The asp assy is now ready from previous run to begin aspiration. RAMP ASPY SLOW400 MOVE ASPY BY 370/ (370 steps @ 400s/s = 0.93sec) / ENDIF /Ensure the wbcdilsyr outlet valve has opened. WAIT 0.1 // //T=0.80 // RAMP WBCDILSYR FAST400/SLOW750 STEP W2 MOVE WBCDILSYR BY 842 / .726 S/UL w/ 2.5cc syr Θ400 s/sec. /with 2 ea 18.75ul deposition volume with 35:1 dil ratio= 18.75ulx34x2=1275ul /1275 X .726 = 926 STEPS @400s/s = 2.3 sec. / PAT FOR 0.4 133 118 336 337 346 113 323 // //T=2.80 // 158 159 /Raise the probe off the bottom of the tube since contact between the two /just occured signaling the sequence to start. / IF (isopenmode == 1) RAMP ASPZ SLOW400/FAST350 POWER HIGH MED ASPZ MOVE ASPZ BY 2 / ENDIF /Piercing the cap of the sample has been moved to cbc to allow piercless /fork of cbs in prime. /Wait for the piercer to pierce plug. PAT FOR 0.4 133 118 336 337 345 346 113 323 // //T=3.20 // ///Lower the aspirate probe until it touches bottom /221STP @ 400S/S =.55 sec. // IF (isopenmode == 0) POWER HIGH LOW ASPZ RAMP ASPZ SLOW1389 STEP A2 MOVE ASPZ BY -707///221 UNTIL ASPLIM /WAS TO -221 //IF NOT ASPLIM //AWAIT ASPZ / ENDIF / PAT FOR 0.2 133 118 336 337 346 113 323 // 159 160 ///T=3.60 // // /Aspirate 75 ul of blood using four rotations of the asp. probe pump /@ 48 steps per rotation, 4X48 =192 /Run piston pump #1 (APRBP) Aspirate 75 ul whole blood. PAT FOR 0.5 133 136 118 336 337 346 113 323 // //T=3.80 // WAIT 0.3 POWER HIGH LOW APRBP RAMP APRBP SLOW200 STEP A3 MOVE APRBP BY -192 PAT FOR 0.3 133 136 118 336 337 346 113 323 // //T=4.30 // / PAT FOR 0.3 133 136 118 336 337 346 113 323 // //T=4.60 // / / ////Raise slightly from bottom for aspiration. //MOVE ASPZ BY -4 / / PAT FOR 0.3 133 136 118 336 113 323 // //T=4.90 // 160 161 / / PAT FOR 0.7 136 118 336 113 323 // //T=5.20 // /Raise aspiration probe to home position. Different heights caused by /different tube depths require a .4 pat command instead of an await. /Clean the ASP probe as we rise and then move to the HGB cup. /Raise vent probe mechanism. /Do maintence drain of hgb cup to removed collected diluent. /Opening 148 for .5 seconds turns on the "beep". PAT FOR 0.5 136 118 148 336 113 323 // //T=5.90 // /Eventually we need to signal the user that the sample has been aspirated. /This is pending a fix in AOS. FORK BEEP FORK CLNPRBA RAMP ASPZ SLOW1389 STEP A4 MOVE ASPZ TO 0 / / PAT FOR 0.3 113 136 118 336 323 // //T=6.40 // / /Move the ASP probe to the hgb cup. .0052"/step /525 stp @ 750s/s =.7sec 161 162 PAT FOR 0.5 113 118 323 // //T=6.70 // / / Verify that the aspiration probe is fully up (up-check up-chuck) / ///IF NOT ASPZ STEP A5 ///PRINTF "ASP NOT UP " /// AIM 152 / / Send our "parent" a signal indicating abnormal exit. This signal / means that the parent should not continue processing. / /// EVENT PARENT 1 /// TERMINATE ///ENDIF PRINTF "ASP IS UP " POWER HIGH MED ASPY RAMP ASPY FAST400/520 stp θ 400 s/sec =1.3sec STEP A6 MOVE ASPY TO -520 / / / /Begin WBC lyse deposit\ 760UL into wbc cup @ 2.90 stp/ul=2204 stps. /Open valves to allow HGB lyse flow. /Add a little more time here (1 sec) to return from the autosampler. PAT FOR 1.2 113 136 118 337 346 323 // 162 163 //T=7.20 // /Raise the piercer for closed mode and lower the tilt for open mode. STEP A7 CLOSE 111 112 / /Drain rbc cup to ensure dry /Asp probe arrives at hgb cup @t=8.0 /ASPY Arrives at hgb cup. /Mix WBC cup. PAT FOR 0.3 132 113 136 118 337 346 /243 // //T=8.40 // / / wait 0.2 // //T=8.60 // /Lower asp probe partially while moving to hgb cup 615 stp @.0064"/stp=.75sec RAMP ASPZ SLOW1389 STEP A8 MOVE ASPZ TO -500 / PAT FOR 0.3 113 132 136 138 241 118 337 346 /243 // //T=8.70 // / /Mark time to allow for HGB lyse deposit. PAT FOR 0.4 113 132 136 241 138 118 337 346 // 163 164 //T=9.00 // WAIT 0.1 /6.2012 ul/step for 225:1 dilution of 19ul = 698 stp X 6.2012=19 x 225=4273ul RAMP HGBDILSYR SLOW200/FAST400 STEP HI MOVE HGBDILSYR BY 150 /200.0UL/550UL=3.6ML with 5ml syringe.is .197S/UL /144:1 S25UL IN 3575UL LYSE.6.14 UL/STP => 582 steps total.259steps then 323. / /Mix WBC cup. /Deposit 18.75 ul whole blood into hgb cup.48steps @ 750 s/s= .07 sec. PAT FOR 0.2 113 132 136 241 138 118 // //T=9.40 // RAMP APRBP SLOW400 STEP A9 MOVE APRBP BY 48 / /Use pat command as time mark ie valve pattern does not change. /Refill coarse diluent supply reservoir. (#2) /Mix WBC cup. /Move vent mechanism to wash cup.1.3" @ .0052"/step =250 steps 400s/s=0.4sec. /Move ASPY to wbc cup.729-514=215s@750s/s=> .52SEC PAT FOR 0.2 113 132 136 241 138 118 // 164 165 //T=9.6 // / POWER HIGH MED VY RAMP VY SLOW400/FAST350 MOVE VY TO -258 /RAMP ASPZ SLOW1389 /MOVE ASPZ TO -500 /AWAIT ASPZ RAMP ASPY SLOW400 STEP A10 MOVE ASPY TO -740/-785 / /Use pat command as time mark ie valve pattern does not change. PAT FOR 0.5 113 138 132 136 241 /118 // //T=9.8 // RAMP HGBDILSYR SLOW300/FAST400 STEP H2 MOVE HGBDILSYR BY 109/518// /25UL X 143 = 3575UL @ PAT FOR 0.2 132 136 241 138 /118 // //T=10.3 // /RAMP ASPZ SLOW1389 /MOVE ASPZ TO -625 / /Deposit 25 ul whole blood into wbc cup.48steps @ 400 s/s= .24 sec. PAT FOR 0.3 132 136 146 241 138 /118 // //T=10.5 165 166 / / RAMP APRBP SLOW400 STEP Al l MOVE APRBP BY 96 /96stp @ 400s/s = .24 sec RAMP HGBDILSYR FAST350/SLOW300/FAST400/SLOW750 STEP H3 MOVE HGBDILSYR BY 362/284/ 323/647//250. OUL/.9 sec @400s/s 580.OUL/ (WAS 996UL=1285 stps @WAS 1.3 S/UL IS 3.07UL/STP PAT FOR 0.1 132 136 146 241 138 118 // //T=10.8 // RAMP RBCDILSYR FAST200 STEP RBC1 MOVE RBCDILSYR BY 2000.0UL/363s @ 200s/s.=1.8 sec. / /Close v3 at end of lyse dilution. /Begin RBC diluent delivery of 7980 ul@.1814s/ul=1447 steps Θ750 s/s= 1.93sec /Mix wbc soln. /Move ASP Probe to RBC cup /400s/s for 317 steps=.0.793sec PAT FOR 0.3 132 136 146 241 118 // //T=10.9 // /RAMP ASPZ SLOW1389 /MOVE ASPZ TO -500 /AWAIT ASPZ RAMP ASPY SLOW 00 /SLOW750 STEP A12 MOVE ASPY TO -1323 /{1323-729=594) /459 was750 =1.5 was.79 sec / PAT FOR 0.3 132 136 146 241 118 // //T=11.2 166 167 // PAT FOR 0.4 132 136 146 241 118 // //T=11.5 // /RAMP RBCDILSYR FAST200 /MOVE RBCDILSYR BY 2000.0UL/was 1.11 SEC@350s/s. /399 Steps @200s/s=2.0 sec. / PAT FOR 0.5 136 146 118 // //T=11.9 // /.1814 stp/ul(3990)= 724stps @ 750s/s = .965sec /Reset wbc lyse delivery syringe. lδOOstp @ 400S/S= 4.52 sec. /Mix WBC cup. /Lower asp probe into RBC cup. /Do partial drain of Impedance Isolator. PAT FOR 0.3 241 136 137 146 118 // //T=12.4 // RAMP WBCDILSYR SLOW400 STEP W3 MOVE WBCDILSYR TO -900 WAIT 0.1 // //T=12.5 // RAMP ASPZ SLOW1389 STEP A13 MOVE ASPZ TO -780 / PAT FOR 0.2 241 136 137 146 118 // 167 168 //T=12.7 // / /Wash vent cone. /Draw wash flow from vent probe top. /Mix WBC cup. STEP A14 PAT FOR 0.5 136 137 241 144 118 335 337 317 421 // //T=12.9 // RAMP RBCDILSYR SLOW300 /slow400 STEP A15 MOVE RBCDILSYR BY 2200.0ul/399 steps § 300s/s=l.33sec / / / /Pressurize hgb reservoir. /Raise aspz up from the rbc cup. 700 steps @ 750s/s= .93 sec /Draw wash flow from vent probe top. /Mix WBC cup. PAT FOR 0.4 241 136 137 144 118 335 337 317 421 425 // //T=13.4 // / PAT FOR 0.2 241 136 137 14 ' 4 118 335 337 317 421 425 // //T=13.8 // / /Close rbcdilsyr-aspprobe connection valve . /Empty waste cup 2. /Close all serviced valves. /Stop flow to flush cup for cone wash, continue drain. /Mix WBC cup. 168 169 PAT FOR 0.3 136 137 144 118 337 421 425 // //T=14.0 // / / PAT FOR 0.2 136 137 146 118 337 421 425 // //T=14.3 // AWAIT RBCDILSYR RAMP RBCDILSYR SLOW400 STEP RBC2 MOVE RBCDILSYR BY 3200.OUL /@1814 s/ul 580 steps @ 400s/s=1.45 sec / /Open rbcdilsyr-res supply line for refill of syr. PAT FOR 0.2 137 146 118 337 421 425 // //T=14.5 // / PAT FOR 0.2 137 136 146 118 337 // //T=14.7 // / /Refill wbc lyse reservoir. /Mix WBC cup. /Feed hgb sample to transducer. PAT FOR 0.5 136 137 146 118 337 // //T=14.9 // FORK LVLH5S 169 170 /FORK LVLW25S /FORK LVLW5S / / /Empty waste cup #1. /Lower vent cone onto wash site. PAT FOR 0.2 136 137 146 118 346 113 // //T=15.4 // /FORK LVLW25S /FORK LVLW5S FORK MTWC15 / /Continue to feed hgb xducer. / PAT FOR 0.3 136 137 146 118 113 // //T=15.6 // /FORK CLNPRBA / /Mix WBC cup. /Allow for time mark to move aspy. /Move aspy (aspiration probe) to the wash cup. (1323-404=990)/750 =1.32sec PAT FOR 0.2 136 137 146 118 113 // //T=15.9 // / PAT FOR 0.4 136 137 118 434 113 // //T=16.1 // 170 171 PAT FOR 0.4 136 137 118 434 113 / // //T=16.5 // / /Mix WBC cup. PAT FOR 0.6 136 137 335 434 113 // //T=16.9 // /Close 21 to allow for earlier beginning of retinc. /Mix WBC cup. PAT FOR 0.2 136 118 335 434 113 // //T=17.5 // FORK LVLW25S FORK LVLW5S / /Do drawback of small rbc dil ammount to wc to clear "T". PAT FOR 0.2 243 335 434 113 136 118 // //T=17.7 // / The following variable induced lysing extension is complicated by the / need to perform this with the retinc sequence which requires the / aspiration probe be at an elevation consistant with the deposit of / rbc dilution into the retic cup. IF (isxlyse == 1) 171 172 PAT FOR 1.0 335 246 331 113 136 // //T=17.9 // /Feed rbc to rbc xducer via peri-pump.Begin flows in RBC xducer. /Raise asp. assy via cylinder. /Mix WBC cup. /Drain hgb cup. / PAT FOR 33.0 335 246 331 111 113 136 // //T=18.9 // RAMP ASPZ SLOW1389 MOVE ASPZ TO -156 FORK CLNPRBA ENDIF / /Feed rbc to rbc xducer via peri-pump.Begin flows in RBC xducer. /Raise asp. assy via cylinder. /Mix WBC cup. /Drain hgb cup. /Keep piercer unlock on during rise. PAT FOR 0.7 335 246 331 247 212 232 113 136 118 // //T=17.9 (51.9) // RAMP RBCPP SLOW400 STEP RBC3 MOVE RBCPP BY 1517 /4100. Oul/3500.Oul/.37step/ul =2.7ul/step 1295 stp @400s/s=3.25sec / 172 173 / /Signal the autosampler that it may advance to the next sample. This is in /order to pipeline autosampler shift/mix operations with the count flow /sequence / IF (isretic == 0) EVENT MIXHOLD 1 ENDIF /Mix WBC cup. PAT FOR 0.3 335 246 331 323 247 212 232 113 136 118 RAMP ASPZ SLOW1389 STEP A17 MOVE ASPZ TO 0/775 steps ©1389 s/s = .6sec or 156 steps @1389s/s=.ll sec. // //T=18.6 (52.6) // / / /Remove backlash from wbcdilsyr. /Pressurize open diluent res #1. /Empty waste cup 1 /Open wash cup inlet valve. /Mix WBC cup. PAT FOR 0.4 113 345 346 335 246 331 247 212 323 232 136 137 118 231 233 // //T=18.9 (52.9) // FORK CLNPRDRY RAMP RBCDELSYR SLOW400/72.57s/ul @ 400S/S STEP RBC4 MOVE RBCDELSYR BY -500 / 5.5 ul 1.0 sec. @400 s/s. 173 174 / / /Drain vent cone after wash. /Move vent probe to manual sample site.130 stps @ 150 s/s=.86 sec. PAT FOR 0.6 345 346 335 246 331 247 212 323 232 136 137 118 113 111 // //T=19.3 (52.3) // / /Begin diluent flows in optical xducer. /Close wash cup inlet valve. /Empty optical flowcell isolator. STEP RBC5 PAT FOR 0.2 136 241 246 247 232 212 331 335 323 314 316 345 113 111 // //T=19.9 // / / PAT FOR 0.3 136 241 246 247 232 212 331 335 323 314 316 345 113 111 // //T=20.1 // PAT FOR 0.2 136 241 246 247 232 212 331 335 323 314 316 345 113 111 // //T=20.4 // / PAT FOR 0.3 136 241 246 247 232 212 331 335 323 314 316 345 113 111 174 175 // //T=20.6 // /Maintain rbc xducer flows. /Refill dil res. #2. PAT FOR 0.4 136 241 246 247 212 232 331 335 323 327 314 316 345 113 // //T=20.9 // / / PAT FOR 0.3 136 241 246 247 331 335 323 327 314 316 345 113 // //T=21.3 // PAT FOR 0.3 136 241 246 247 331 335 323 327 314 316 345 113 / // //T=21.6 // WAIT 0.3 // //T=21.9 // / END / * /* Copyright 1994 by Abbott Laboratories /* Source Code Control System keywords 175 176 /* /* NAME: $Source: /tmp/RCS/cbs2. f,v $ /* SLocker: $ /* $State: Exp $ /* $Revision: 1.49 $ /* $Author: rodl $ /* $Date: 95/05/18 01:13:58 $ /* Log: .. See below /* /* LANGUAGE: CD4000 Flow sequence language /* /* DESCRIPTION:SPECIAL HGB w/237 connected to hgb syringe node. /* Analysis portion of the hematology sequence. Follows cbs. f. /* Allows for overlap of the two. /* /* ....$Log: cbs2.f,v $ /* Revision 1.49 95/05/18 01:13:58 rodl /* Increase WBC OPLT and HGB transfers. Do better wbc cup drain and wc#2 drain. /* Reduce wbc cup rinse. Be more discerning about rbc cup drain from T=-25-30. /* /* Revision 1.48 95/05/11 15:37:04 rodl /* Increase WBC transfer by 15% because we have plenty of wbc mix. /* /* Revision 1.47 95/04/20 17:30:08 rodl /* New aspz motor. /* /* Revision 1.45 95/04/11 16:14:06 rodl /* Add stat mode functionality. /* 176 177 /* Revision 1.43 95/04/05 10:35:56 rodl /* Add metered rinse and adjust syringe travel to account for dual syringe. /* /* Revision 1.42 95/03/28 23:47:44 rodl /* Remove some useless 235 opens to guard against leaky HGBPP's. Move rbcdilsyr /* move to earlier for pressurized backlash removal. Also return to old hgbpp move duration (one step less) . /* /* Revision 1.41 95/03/15 14:14:39 rodl /* Remove some last second rinse from rbc cup w/o effecting carryover. /* /* Revision 1.40 95/03/15 11:34:24 rodl /* Open valve for rbcdilsyr backlash removal. /* /* Revision 1.39 95/03/13 15:10:29 rodl /* Change timing reference values , no functional change. /* /* Revision 1.38 95/03/10 11:33:28 rodl /* added signal to autosampler to advance. Not yet as early /* as it can eventually be. /* /* Revision 1.37 95/03/07 17:30:42 rodl /* Move optdelsyr move ending further from pattern statement by 70ms. to /* prevent crashes on 203. /* /* Revision 1.36 95/03/06 15:51:30 rodl /* Increase time between OPTDELSYR move and pattern statement to prevent valeve /* closure and subsequent outliarε. /* /* Revision 1.35 95/03/02 19:14:22 davef 177 178 /* temporarily removed problematic aspz not up error detection /* /* Revision 1.34 95/02/22 17:14:02 rodl /* Add another diluent reservoir #2 fill routine to cover occasional shortfalls /* on some machines. LVLDR24 appears at t=~33 to t=~37. /* /* Revision 1.33 95/02/16 11:41:35 rodl /* Make slight improvments to HGB precision. Got .6% cv. ave. /* /* Revision 1.32 95/02/15 20:48:14 rodl /* New hybred stepper is accomodated adding dynamic range. /* /* Revision 1.31 95/02/07 23:29:07 rodl /* For use with .030 id HGB line to v237. Does good job of filling and rinsing the hgb cup. /* /* Revision 1.30 95/02/07 21:59:02 rodl /* Change count statement to reflect 200:1 dilution for HGB. /* /* Revision 1.29 95/01/26 13:38:27 rodl /* Requires plumbing change to implement v237 as hgb reference supply. Gives <2% HGB cv's with 150 k wbc samples. use with ver 1.28 cbs.f. /* /* Revision 1.28 95/01/12 00:53:37 rodl /* Adds the 222:1 dilution ratio to the hgb count statement to be used with ver. /* 1.25 and above cbs.f. /* /* Revision 1.27 95/01/11 21:23:18 rodl /* Move asp probe zero monitor checks to reduce failures due to close timing in /* the information transfer. Added .2 sec delay between 178 17 9 previous check tand new check time. /* /* Revision 1.26 95/01/05 00:32:02 rodl /* Remove the optical reds carryover from the wbc channel count.10 to 20 events /* still seem to linger but so far all efforts to reduce carryover further /* resulted in wbc and rbc precision degradation. /* /* Revision 1.25 95/01/04 21:27:08 rodl /* Return to a more leisurely asp probe prime at sequence end. /* /* Revision 1.24 94/12/28 19:37:26 rodl /* Update time utility . /* /* Revision 1.23 94/12/21 17:36:39 rodl /* New dilution callouts for use with rl.21 cbs.f with deposition pumps set to /* 18.75 microliter depositions. /* /* Revision 1.22 94/12/20 17:21:08 rodl /* First autosampler sequence with reasonable wrap capability. Crashes @ t=15 ob /* the second run. /* /* Revision 1.21 94/12/20 12:32:47 rodl /* Forgot to mention last version add rbc cup drain at T= midd 30's. /* /* Revision 1.20 94/12/20 12:26:55 rodl /* Add washcup dil just after conewash instead of just at probe prime. Move all probe priming to a couple seconds earlier to allow aspy to wrap @t=30.3 or so. /* 179 180 /* Revision 1.19 94/12/15 14:49:23 rodl /* Lower the probe @ the wash cup to ensure priming of the probe without so much /* reagent use. /* /* Revision 1.18 94/12/14 23:33:41 rodl /* Restrict aspy and aspz moves to streamline lvldr27's run b4 probe prime to /* better accomodate wrap. /* /* Revision 1.17 94/12/13 12:48:04 rodl /* Add wbc cup drain before t=30 and remove it aftert=30. Change time callouts /* to reflect change in cbs.f's allowance for reachout to autosampler. /* /* Revision 1.16 94/11/30 19:10:51 rodl /* Put a 0.1 sec delar between the terminate command and the aspy move @t=29 /* /* Revision 1.15 94/11/29 10:35:47 rodl /* Raise asp probe earlier to allow for more graceful terminate option @ t=29.:wq /* /* Revision 1.13 94/11/16 22:20:37 rodl /* Places variable count ,optical delivery syringe and pattern times to /* allow manipulation of cbs2.f from the various shells while still /* /* Revision 1.12 94/11/10 18:26:25 rodl /* Truncate cbs2 sequence at wbc analysis end to handoff to clnhup for clean. /* /* New structure provides better maintainance of component 180 181 flowscripts. /* /* Revision 1.11 94/11/04 00:25:24 rodl /* Remove recently added hgb sample and ref SETUP statements. /* Caused the machine to report 0's for all hgb's. /* /* Revision 1.10 94/11/03 13:12:17 rodl /* Add setup commands for both hgb ref and sample. Don,t know h why it workrd b4 /* /* Revision 1.9 94/11/03 11:08:01 rodl /* Add vacuum draw of bubbles past "T" at HGB node before HGBPP transfer. Reduce /* transfer as a result. Improves outliar problem. /* /* Revision 1.8 94/11/03 00:02:28 rodl /* Add isolator drain time for extended counts.: /* /* Revision 1.7 94/10/26 16:43:48 rodl /* Add more margin between valve open and hgb syringe move. /* /* Revision 1.6 94/10/25 23:39:26 rodl /* Increase the advance for the rbcdels syringe to displace the deadvolume in the larger .013" id sample nozzle in the imp. transducer. This sequence must accompany a hardware change of the sample nozzle on the imp xducer.Also increased the duration of the pa /* /* Revision 1.5 94/10/19 22:38:18 rodl /* Add lvldr27 at sequence end. Improve margin on hgb cup clean and reference transfer to transducer. Tried to allow margin for hotter or colder conditions. /* /* Revision 1.4 94/10/17 16:35:18 rodl /* added READY command when ready 181 182 /* /* Revision 1.3 94/10/11 16:12:58 rodl /* Add auto-extended optical platelet and fill all reservoirs at sequence end. /* /* Revision 1.1 94/09/29 23:16:56 scotts /* Initial revision /* /* /* Rev 1.11 21 Sep 1994 19:45:18 RODL /* Remove a mistaken string on line 1. /* /* Rev 1.10 21 Sep 1994 19:33:32 RODL /* Add "ready" acommand at wrap point. /* /* Rev 1.9 21 Sep 1994 10:01:56 RODL /* Reset rbcdel syringe with slow400 ramp instead of fast400 ramp. /* /* Rev 1.8 19 Sep 1994 22:36:54 RODL /* Change aspz moves from "BY" to "TO" to provide allowance for moves /* made in retinc. /* /* Rev 1.7 15 Sep 1994 15:30:52 RODL /* Change oplt transfer slightly to remove backflow. Slow down the wbc /* peripump from 400 s/s to 350 s/s to accomodate the draw to the oplt channel /* during transfer. Close 234 at the same time 227 is closed to parallel /* wbc transfer. Improves oplt count. Not sure if it is any improvment or /* degredation on WBC count. /* 182 183 /* Rev 1.6 14 Sep 1994 09:33:16 RODL /* Add note for future reference re. purge of wbc nozzle node. /* /* Rev 1.5 25 Aug 1994 20:36:24 RODL /* Add optical shutter and filter lift motion with vl38 open @T=30-43. /* Also add to a previously marginal wc2 empty by adding 1 sec more empty /* @ t=21.4. /* /* Rev 1.4 24 Aug 1994 21:32:26 RODL /* Reduce hgb cup rinse at beginning to allow drain before rinse. /* /* Rev 1.3 24 Aug 1994 10:16:58 RODL /* Add new filter slide motion callouts for wbc count sequence. /* /* Rev 1.2 18 Aug 1994 17:32:24 RODL /* Replaced aspz to moves with by moves. /* /* Rev 1.1 17 Aug 1994 10:32:12 RODL /* Remove obsolete valve callouts. /* /* Rev 1.0 16 Aug 1994 16:54:12 RODL /* Initial revision. /* ///// FOR WRAP . , carryover.etc //NOTE ... Move HGBDILSYR slack takeup to earlier t=-32. //NOTE ... Remove rbc cup drain @ cbs.f's beginning and add @ cbs2.f's @-t=35? //NOTE ... vl46 open @ t=34 is useless remove and confirm. //NOTE ... change hgbdil move @ T=33 to allow unpressurized 183 184 node @ syringe. //NOTE ... Add hgbpp move @ T=43-48 to remove lysed 35:1 from nozzle. //NOTE ... Reduce hgb dil use by reducing rinse ref mix and increasing rinse slightly. //NOTE ... Remove all 336,337, 325 326 calls,MTWC's take that responsibility. //NOTE ... Removal of 226 & 226 after t=30 is necessary for rap but just "* //taking them out ruins precision must be finessed. //NOTE ... Remove all 43* valve callouts , lvl ' s take that responsibility. //NOTE ... RBC cup rinse could be carried out @T=21-34 rinsing line to 41,43. //NOTE DONE... T42 should be closed @ t=48.18 , 48.68 for wrap //NOTE done... T41 43 Should be closed at t=37.69 , t=44.18 for wrap. ///NOTE ... OPTPP moves by 800ul Θ44.5 is this necessary? ///note ... Optical delivery node can be pressurized to 15psi at T=~18 ////////////during optdel reset. / * /*/ BEGIN CBS2 (sampid isretic isxwbc isopenmode) VAR isopen VAR isautosamp // //T=22.0 // / /Feed wbc & platlets to xducer for 2 sec 184 185 /Advance rbc sample flow for 2.13 sec @ 72.567 stp/ul /Drain hgb cup. PAT FOR 1.0 136 135 246 247 231 234 225 227 213 217 331 335 323 327 316 // //T=22.0 // RAMP HGBPP SLOW400 RAMP OPTPP SLOW400 /Transfer wbc sample /Transfer oplt sample STEP 4 MOVE HGBPP BY 1080/720/4054.OUL /1781.0ul / 2.2 sec @ 300s/s =600 steps @.37stp/ulWAS 1000 STEP RBC6 MOVE OPTPP BY 1081/800/4054.OUL /1781.0ul / 2.2 sec & 300s/s =600 steps @.37stp/ulWAS 1000 /Advance rbc sample. RAMP RBCDELSYR SLOW400 STEP RBC7 MOVE RBCDELSYR BY 1700/ 72.57s/ul β 400S for 4.25 sec.= 23.4 ul. / / / /Raise probe /Prep vacuum in w.c.3 /Return piercer to home. PAT FOR 0.4 135 138 335 336 246 331 247 225 227 231 234 213 217 323 327 316 435 //T=22.6 // RAMP VY SLOW400 STEP A21 MOVE VY TO 0 185 186 FORK LVLDR27 / /Rinse HGB cup once after drain and before ref. sample fill. PAT FOR 0.3 135 138 335 336 246 331 247 225 227 231 234 213 217 323 327 316 435 / / /Drain HGB cup finally after rinse before ref. sample fill. PAT FOR 0.3 135 138 335 336 246 331 247 225 227 231 234 213 217 323 327 316 435 // //T=23.0 // / /Start aperature current. /Fill hgb cup for ref transfer. (could be more rinse here) /Continue to drain hgb cup PAT FOR 0.2 135 246 247 231 234 225 227 213 217 331 335 327 314 316 435 // //T=23.3 // / / SETUP RBCPLT / /Do vacuum draw of HGB ref sample past the "T" to the HGB transducer /to reduce the chance of bubbles entering the HGB flowcell. PAT FOR 0.2 242 135 246 247 231 225 213 217 331 335 327 314 316 435 // //T=23.5 // DISABLE 186 187 / /Begin advancing platlet sample to optical flowcell /Advance plalet sample @ 52ul/sec w/500ul syringe 14.5stp/ul, /53 ul 614.5 stp/UL = 768 stp.@750s/s =1.02sec. /Close valves associated w/ wbc-platlet transfer. PAT FOR 0.3 135 246 247 236 226 225 213 335 331 327 314 316 // //T=23.7 // SETUP PLT POWER HIGH LOW OPTDELSYR RAMP OPTDELSYR SLOW1389 STEP RBC8 MOVE OPTDELSYR BY 2600/100. OUL / @26.85st/ul==> 2600steps / /Empty waste cup 3 for 4 sec. /Begin drain of rbc cup and wbc cup. /Add hgb lyse to HGB cup for transfer to xducer. STEP 5 PAT FOR 0.4 235 231 233 246 247 236 225 226 335 331 327 314 316 // //T=24.0 // FORK MTWC33 / RAMP HGBPP SLOW300/FAST350/FAST400 STEP H4 MOVE HGBPP BY 900/1140/2400.Oul/2702.Oul / 2.5 sec @400 s/s =1000steps/WAS 4054 @ 750 for 2 sec. RAMP ASPY SLOW400 STEP A22 MOVE ASPY TO -408 / PAT FOR 0.3 231 235 233 246 247 236 225 226 335 331 327 314 187 188 316 // //T=24.4 // /Continue to add hgb lyse for transfer to xducer. PAT FOR 0.6 235 246 247 236 225 226 216 331 335 327 316 314 435 // //T=24.7 // // /Continue with high flow RBC advance /Continue with high flow wbc advance /Continue with rbc cup drain /Continue with wbc cup rinse & drain. /Continue to add hgb lyse for transfer to xducer. PAT FOR 0.4 133 235 243 246 247 236 225 226 216 331 335 327 314 316 435 // //T=25.3 // / / /Begin 2.5 ul/sec flow 26.854 stps/ul=67.2 stps/sec. AWAIT OPTDELSYR // //T=25.57 // RAMP OPTDELSYR FAST67_2 /2.5 ul/sec POWER MED LOW OPTDELSYR STEP RBC9 MOVE OPTDELSYR BY 2222/ Here 2222 steps represents the maximum the variable /count can extend. The AOS activated HALT command reacts to the hard 188 189 /counter to limit the count to the time and or count constraints indicated /in the count statement.67.2 s/sec.=2.5 ul /sec. / / /End advance flow & change succeeding flow to .5 ul/sec. for rbcdelsyr. / . 5 ul/sec for 13.5 sec =6.75 ul @ 58.6 steps/ul.=396steps. / was for .333ul/sec.4.5ul @58.6s/ul=263.7 steps PAT FOR 0.3 137 235 246 247 236 225 226 216 331 335 327 314 316 // //T=25.7 // RAMP RBCDELSYR M36_3 STEP RBC10 MOVE RBCDELSYR BY 530/ 72.57s/ul= 7.3ul@36.3 s/s=14.6 sec ends @ 37.3 / / PAT FOR 0.3 235 137 246 247 236 225 226 216 331 335 327 314 316 // //T=26.0 // / PAT FOR 0.4 235 137 246 247 236 225 226 216 331 335 327 314 316 // //T=26.3 // /Mix wbc cup rinse. /Add wbc lyse to wbc cup while draining ,to rinse for .5 sec. /Begin Oplt gather data. PAT FOR 0.5 133 235 135 246 247 236 225 226 118 216 331 327 189 190 314 316 // //T=26.7 // RAMP WBCDILSYR SLOW400 MOVE WBCDILSYR BY 570 / STEP RBC11 COUNT PLT MINTIME 6.0 MAXTIME 32.0 DIL 420.0 RATE 2.5 UNTIL 2000 SAMPLEID sampid REAG 0 / / /Stop filling wbc cup. /Fill rbc cup. /Begin RBC gather data. /Allow 216 to provide vacuum to wc#2 to drain rbc cup. STEP RBC12 PAT FOR 0.3 133 135 243 246 247 225 226 236 118 216 331 327 314 316 // //T=27.2 // ///COUNT HGBSAMP MINTIME 0.7 MAXTIME 0.7 DIL 222.0 RATE 0.0 UNTIL 0 /// SAMPLEID sampid REAG 0 /Allow 216 to provide vacuum to wc#2 to drain rbc cup. /Transfer WC2 ' s vacuum supply responsibility to wc#l via v216 by closing v335. CLOSE 335 / STEP RBC13 COUNT RBCPLT MINTIME 11.8 MAXTIME 11.8 DIL 420.0 RATE 0.5 UNTIL 0 SAMPLEID sampid REAG 0 190 191 / /Move ASP prb down into wash cup. RAMP ASPZ SLOW1389 STEP A23 MOVE ASPZ TO -781/ 781 steps @ 1389 s/s = .56 sec. / PAT FOR 0.7 133 246 247 236 118 216 225 226 331 327 314 316 // //T=27.5 // /Drain HGB CUP. PAT FOR 0.3 133 242 246 247 236 118 216 225 226 331 327 314 316 // //T=28.2 // /End the vacuum draw of HGB ref solution. PAT FOR 0.2 133 242 246 247 236 118 216 225 226 331 327 314 316 // //T=28.5 // / /Continue to drain wbc cup /Flush asp probe into wash cup while submersed to prime probe. /Fill wash cup to ensure submersion for cannula. /Continue with rbc gather data /Stop mix for wbc. PAT FOR 0.4 242 135 137 243 246 247 236 225 226 216 331 327 314 316 // //T=28.7 // /Transfer hgb reference to transducer. 191 192 /Continue to drain wbc cup PAT FOR 0.7 242 135 137 246 247 236 225 226 216 331 327 314 316 // //T=29.1 // PAT FOR 0.4 242 135 136 137 138 246 247 236 225 226 216 331 327 314 316 // /Drain rbc cup /Feed hgb's to hgb xducer. /Reset hgb syringe. /I.29step/ul w/hgb syringe= 1735 stp/1345ul hgb lyse. /Reset rbcdilsyr /Begin fill of flush cup thru cone. STEP H5 PAT FOR 0.2 242 145 135 136 141 137 144 225 226 216 246 247 231 233 236 138 331 335 336 337 327 345 316 314 // //T=30.2 // RAMP APRBP SLOW200 STEP A24 MOVE APRBP BY 96 /96 steps ©400 s/s = .23 sec. RAMP HGBDILSYR FAST400 STEP H6 MOVE HGBDILSYR TO 0 / 996.0ulIS 1440s ©/ is 1735 s & 400s/s =3.6sec. RAMP RBCDILSYR SLOW400 STEP RBC14 MOVE RBCDILSYR TO 0 /7400ul X.1814 s/ul=1342s Θ400s/s=3.34sec. / PAT FOR 0.3 242 135 136 141 137 144 225 226 216 246 247 231 233 236 138 331 335 336 337 327 345 316 314 192 193 // //T=30.4 // STEP RBC15 PAT FOR 1.0 242 135 136 141 146 137 225 226 216 246 247 231 233 236 138 331 335 336 337 327 345 316 314 // //T=30.7 // / PAT FOR 0.5 242 135 136 141 137 225 226 243 216 246 247 231 233 236 138 331 335 336 337 327 345 316 314 // //T=31.7 // FORK CLNPRDRY WAIT 0.2 POWER HIGH LOW ASPZ RAMP ASPZ SLOW1389 STEP A25 MOVE ASPZ TO 0 /250 steps @ 400 s/s = .63sec / /Move asp probe up from washcup. /Fill rbc cup. /Continue to refill rbcdilsyr. PAT FOR 0.5 135 136 141 225 226 246 247 236 138 331 335 336 337 327 314 316 // //T=32.2 // / / /////Move asp probe up from washcup. /Here the pattern duration is controlled by the AwaitCount command which 193 194 /responds to the aggreement between the hardcounter values and /the count statement count minimums and count time maximums.A maximum /duration of 32 seconds is allowed to try to reach the 2000 count minimum. /A 6 second count duration minimum always occurs before count is terminated. PAT 136 141 246 247 236 331 335 336 337 327 314 316 // //T=32.7 // / / AWAITCOUNT PLT HALT OPTDELSYR PAT FOR 0.2 135 136 145 141 234 231 246 247 236 138 331 335 336 337 327 314 316 346 // //T=32.7 // /check to see if aspiration probe has returned to 0. ///IF NOT ASPZ /// AIM 152 /// TERMINATE ///ENDIF /End platlet flow to optical transducer(236 close)& begin wbc flow (open 211) . PAT FOR 0.2 135 136 141 145 234 231 246 247 138 331 335 336 337 327 314 316 346 // //T=32.9 // STEP H7 COUNT HGBSAMP MINTIME 0.7 MAXTIME 0.7 DIL 200.0 RATE 0.0 194 195 UNTIL 0 SAMPLEID sampid REAG 0 IF (isopenmode == 0) RAMP ASPY SLOW400 STEP A26 MOVE ASPY TO 0 /408 steps © 400s/ sec = 1.05sec ENDIF / IF (isopenmode == 1) isopen = 0 isautosamp = 0 FORK CONVSTAT (isopen isautosamp) ENDIF /Stopped gathering data in the optical flow cell .1 sec earlier. /Advance wbc sample © 27.6ul/sec for 2 sec.w/500ul syringe 14.5stp/ul. STEP 6 PAT FOR 0.4 135 136 141 132 246 247 138 211 331 335 336 337 327 314 316 346 // //T=33.1 // POWER HIGH LOW OPTDELSYR RAMP OPTDELSYR FAST741 STEP 7 MOVE OPTDELSYR BY 1408/ 52.44ul / ©26.85st/ul==> 1426 steps in 1.9 sec © 750stps/sec. SETUP WBC /Continue to leave rbcdilsyr reset valves open: close call. /Continue to fill rbc cup. PAT FOR 0.3 128 135 136 146 141 246 247 211 331 335 336 337 195 196 327 316 314 // //T=33.5 // / / / / END OF FIRST WRAP / /Drain rbc cup /Move the asp prb to sample station.0-404=404stps.©400s/s=l. Osec. /Continue to drain HGB cup. STEP H8 PAT FOR 0.5 128 135 136 141 237 242 246 247 211 331 335 336 337 327 314 316 // //T=33.8 // RAMP RBCDILSYR SLOW400 STEP RBC16 MOVE RBCDILSYR BY 250.0UL / / /Empty wbc cup. /End rbcdilsyr reset. /Continue to drain HGB cup. STEP RBC17 PAT FOR 0.5 141 128 135 237 242 243 246 247 211 331 335 336 337 327 314 316 346 // //T=34.3 196 197 // FORK LVLDR24S / /Begin 2.5ul/sec flow of wbcs to the optical flowcell. /36.3s/s for 11.5 sec = 345 steps /Move rbcdilsyr up a little to remove backlash. /Continue to drain HGB cup. /Last drain of RBC cup. PAT FOR 0.5 128 141 135 237 242 243 246 247 211 331 335 336 331 327 314 316 // //T=34.8 // AWAIT OPTDELSYR // //T=35.0 // POWER MED LOW OPTDELSYR RAMP OPTDELSYR FAST67_2 / / Determine how far to move optical delivery syringe based upon whether or / not an extended WBC is being performed / IF (isxwbc == 0) STEP W8 MOVE OPTDELSYR BY 722 / 2.5ul/sec. for 11.5 sec. 28.75ul / © 2.5ul/sec) for 11.5 sec. ENDIF IF (isxwbc == 1) MOVE OPTDELSYR BY 2222 ENDIF / / / Signal AOS and operator that analyzer is ready to aspirate 197 198 next sample / IF (isretic == 0) READY ENDIF / /Continue to gather data in both impedance & optical xducers. /Continue to drain HGB cup. STEP H9 PAT FOR 0.5 128 135 242 243 246 247 211 331 335 336 327 314 316 // //T=35.3 // / /Empty wash cup. /Continue to drain HGB cup. PAT FOR 0.2 128 242 135 243 246 247 211 331 335 327 314 316 317 // //T=35.8 // IF (isxwbc == 0) STEP 9 COUNT WBC MINTIME 10.0 MAXTIME 10.0 DIL 35.0 RATE 2.5 UNTIL 0 SAMPLEID sampid REAG 0 ENDIF IF (isxwbc == 1) COUNT WBC MINTIME 32.0 MAXTIME 32.0 DIL 35.0 RATE 2.5 UNTIL 0 SAMPLEID sampid REAG 0 ENDIF / / / /Continue to drain HGB cup. 198 199 PAT FOR 0.3 128 135 242 246 247 211 331 335 327 314 316 317 // //T=36.0 // / PAT FOR 1.0 128 242 135 246 247 211 331 335 327 314 316 // //T=36.3 // STEP H10 MOVE HGBDILSYR BY 25.OUL/ to remove backlash / / / PAT FOR 0.2 128 135 145 242 246 247 211 331 335 327 314 316 // //T=37.3 // / / /Drain cup thru rbc delivery lines to wc2. STEP RBC18 PAT FOR 0.7 128 242 243 246 247 231 233 331 335 327 314 316 211 // //T=37.5 // / / / /Continue to drain rbc cup thru del lines. /Fill hgb cup. PAT FOR 0.6 128 242 246 247 211 331 335 327 314 316 // //T=38.2 199 200 // / /Continue to drain rbc cup thru imp xducer del lines. /Fill rbc cup while draining (rinse) thru lines. PAT FOR 0.2 128 246 247 233 211 331 335 327 314 316 // //T=38.8 // / /Fill rbc cup while draining (rinse) thru lines. PAT FOR 0.3 135 128 136 141 246 247 233 211 331 335 327 312 314 316 /148 // //T=39.0 // / /Close 21 leaving 26 open to relieve line pressure. /Continue to drain rbc cup thru del lines. /Begin WBC gather data PAT FOR 0.5 128 136 246 247 211 331 327 312 314 316 // //T=39.3 // / /Continue to drain rbc cup thru del lines. /Read hgb xducer 5 times. /End fill & mix on hgb cup. /Drain hgb cup thru hgb xducer. /End rbc gather data from previous cycle , but wait .2 sec before stopping /sample flow and closing valves. /Stop sample flows to rbc xducer and begin backflush of lines. STEP RBC19 PAT FOR 0.5 128 136 246 247 232 233 211 212 331 335 327 312 200 201 314 316 // //T=39.8 // / / /Continue to drain rbc cup thru del lines. /Drain hgb cup thru hgb xducer. PAT FOR 0.5 128 136 246 247 211 212 241 331 335 336 327 312 314 316 // //T=40.3 // / /Close rbc cup drain/delivery valves (41 43) PAT FOR 0.5 128 136 246 247 211 212 241 331 335 336 327 312 314 316 // //T=40.8 // / /Stop rbc cup drain thru lines, drain to wc3. Continue rbc xducer bkflsh. ////////Impediance xducer output flows stop, backflowε continue. /Backflush rbc sample lines via the rbc delivery line to wc2 /Flush rbc del lines from syringe valve. PAT FOR 0.8 128 136 142 246 247 211 212 241 331 335 336 327 312 314 316 // //T=41.3 // / / /Close hgb xducer drain valve. 201 202 /Close hgb cup drain valve. /End all hgb xducer activity. /Flush rbc del lines from syringe valve. STEP RBC20 PAT FOR 1.2 128 136 142 246 247 211 212 241 331 335 336 337 327 312 314 316 // //T=42.1 // / / /Dry vent head once again. /Drain hgb cup thru xducer. /Stop bkflsh of rbc sample tube . PAT FOR 1.0 128 136 142 246 247 211 212 331 335 336 337 327 312 314 316 317 // //T=43.3 // // /Extended WBCs 10 sec. period is augmented by this 22 sec. providing 32 sec. IF (isxwbc == 1) PAT FOR 22.0 128 136 246 211 212 335 336 337 327 312 314 316 317 /247 331 ENDIF / / /Drain flush cup to wc. PAT FOR 2.0 128 136 142 246 247 211 212 331 335 336 337 327 312 314 316 317 // //T=44.3 // / 202 203 / If this is a retic sample, signal the autosampler that it is appropriate / to advance to the next sample / IF (isretic == 1) EVENT MIXHOLD 1 ENDIF // //T=44.3 // /WBC gather data ended © t=42 /Close rbc sample tube backflush valves. /Open optical delivery line diluent port valves. /Link both diluent reservoirs together for dil. res #1 refill. /Refill dil. res. #1. /Backflush all optical lines simultaneously. /Drain RBC cup thru opt pit feed line. /Reset rbcdelsyr to 0 ( 8.75ul © 72.6s/ul +600S = 1231.4stp /© 400s/s = 3.1 sec. WAIT 1.0 // //T=45.3 // STEP Hll COUNT HGBREF MINTIME 0.7 MAXTIME 0.7 DIL 0.0 RATE 0.0 UNTIL 0 SAMPLEID sampid REAG 0 WAIT 1.0 // //T=46.3 // END /* 203 204 /* Copyright 1994 by Abbott Laboratories /* .Source Code Control System keywords /* /* NAME: $Source: /home/rodl/product/RCS/clnhup.f,v $ /* $Locker: $ /* $State: Exp $ /* $Revision: 1.2 $ /* $Author: rodl $ /* $Date: 94/11/10 18:11:30 $ /* Log: .. See below /* /* LANGUAGE: CD4000 Flow sequence language /* /* DESCRIPTION: /* /* ... $Log: clnhup.f,v $ /* Revision 1.2 94/11/10 18:11:30 rodl /* Created clnhup.f to be the cleanup portion following the analysis portion of the sequences involving hematology analysis. /* /* Revision 1.1 94/09/29 23:17:04 scotts /* Initial revision /* /* /* Rev 1.0 16 Aug 1994 16:55:04 RODL /* Initial revision. /* /* Rev 1.2 24 May 1994 21:21:54 RODL /* Generally prepare clnhup for wrap. Move enable to earlier in the sequence 204 205 /* to allow more time to come to pressure.Remove v22 ©44.4. Move optdelsyr /* move to earlier in sequence and rbcdelsyr move to cbs2. Remove v22 46 97 & 71 /* in last two pat's to prevent dilution of opt pit transfer w/wrap. /* /* Rev 1.1 06 May 1994 15:58:28 RODL /* Add label to script. /*NOTE ..DONE .We should be able to move optdelsyr move to /* earlier in the sequence. /* /*/ BEGIN CLNHUP PAT FOR 0.5 128 136 142 246 247 211 212 331 335 336 337 327 312 314 316 317 // //T=42.89 // RAMP RBCDELSYR SLOW400 /2230 - 800 for drawback in cbs steps © 400s/s=3.6 sec. STEP RBC22 MOVE RBCDELSYR TO 0 ENABLE PAT FOR 0.5 128 136 142 143 246 247 211 212 331 335 336 337 327 312 314 316 317 // //T=43.39 // POWER HIGH LOW OPTDELSYR RAMP OPTDELSYR SLOW750 STEP Wll 205 206 MOVE OPTDELSYR TO 0 / / PAT FOR 0.5 128 136 142 143 246 226 227 211 213 217 331 335 336 314 316 342 // //T=43.89 // FORK LVLDR14 / /Reset optdelsyr to 0 (202 ul © 14.5 s/ul =2929 ul © 750s/s=4.Osec. /Move optpp to draw oldsample from waste side of flowcell, 2nd channel. /Drain RBC cup thru opt pit feed line. PAT FOR 0.5 136 142 143 246 233 234 236 226 227 211 217 331 335 336 314 316 342 // //T=44.39 // / / /Close plumbing on left side of opt xducer allowing more rt side flow, /for more effective reagent use. /Rinse retic line to waste cup #2. PAT FOR 1.0 136 142 143 246 233 234 236 227 211 217 331 335 336 314 342 // //T=44.89 // /Flush pit delivery line. /Rinse retic line to waste cup #2. PAT FOR 1.5 136 142 143 246 233 234 236 227 211 217 331 335 336 314 342 206 207 // //T=45.89 // /Take up backlash in rbcdelsyr. PAT FOR 0.5 136 142 143 246 233 234 236 227 211 217 331 335 336 314 342 // //T=47.39 // / / /One last purge of left side of opt flowcell. PAT FOR 0.5 136 142 143 246 236 226 227 211 217 331 335 336 327 314 316 342 // //T=47.89 // RAMP RBCDELSYR FAST400 STEP RBC23 MOVE RBCDELSYR BY 150/ 150s © 400s/s = .375sec / / PAT FOR 0.8 136 143 246 236 226 227 211 217 331 335 336 327 314 316 342 // //T=48.39 // / MOVE OPTDELSYR BY 10.OUL STEP W12 PAT FOR 1.0 FORK LVLDR27 207 208 // //T=48.89 // / / END /** // //T=0.00 // / * /* Copyright 1994 by Abbott Laboratories /* Source Code Control System keywords /* /* NAME: $Source: /tmp/RCS/clnrup.f,v $ /* $Locker: $ /* $State: Exp $ /* $Revision: 1.8 $ /* $Author: rodl $ /* $Date: 95/04/25 13:28:33 $ /* Log: .. See below /* /* LANGUAGE: CD4000 Flow sequence language /* /* DESCRIPTION: /* /* ....$Log: clnrup.f,v $ 208 209 /* Revision 1.8 95/04/25 13:28:33 rodl /* Add full sensing (lvldrl6s) to fill diluent reservoir. /* /* Revision 1.6 95/03/15 15:06:17 rodl /* Modify the transition between reticvu.f and clnrup.f to protecy t the flowcell walls from getting exposed to sample. /* /* Revision 1.5 95/02/24 14:53:25 rodl /* removed LVLDR27 which was causing RTC bead sequence to crash /* /* Revision 1.4 95/02/15 21:01:58 rodl /* Add hybred stepper to optdeelsyr to improve dynamic range. /* /* Revision 1.3 94/11/10 18:13:00 rodl /* Created clnrup.f to cleanup following retic+hematology analysis sequences. /* /* Revision 1.2 94/10/13 00:16:54 rodl /* Add mtwc28 fork at sequence end as Leuven stopgap. /* /* Revision 1.1 94/09/29 23:17:05 scotts /* Initial revision /* /* /* Rev 1.1 29 Sep 1994 17:11:28 RODL /* Ensure the line to rbcpp -peripump is primed at sequence end to prepare for /* rbc transfer sequence which follows. /* /* Rev 1.0 16 Aug 1994 16:55:02 RODL /* Initial revision. /* /* Rev 1.7.1.4 06 May 1994 09:52:20 RODL /* Open v23 during optdelsyr refill. 209 210 /* /* Rev 1.7.1.3 01 Feb 1994 20:49:02 RODL /* Add optical isolator drain . /* /* Rev 1.7.1.2 26 Jan 1994 10:01:54 RODL /* Open v23 for opt syring refill. /* /* Rev 1.7.1.1 18 Oct 1993 12:24:46 LUNAH /* Amy was here to fix up "PROTO" branch. /* /* Rev 1.8 14 Oct 1993 13:44:20 RODL /* Added new proto valve designations. / *_. /*/ / Cleans up the retic optical flowpath after the reticvu / program is forked. / / BEGIN CLNRUP PAT FOR 1.0 128 136 142 143 226 227 222 223 224 246 247 211 212 335 336 337 312 314 316 317 // //T=42.89 // FORK LVLDR16S POWER HIGH LOW OPTDELSYR RAMP OPTDELSYR SLOW1389 STEP W10 MOVE OPTDELSYR TO 0 /2793 oplt adv+2222 max oplt del+1426 wbc adv+2222max wbc+1500 rtc adv+506 rtc del =11916 © 1389 s/sec =8.6sec 210 211 RAMP RBCDELSYR SLOW400 /2230 - 800 for drawback in cbs steps © 400s/s=3.6 sec. STEP RBC21 MOVE RBCDELSYR TO 0 ENABLE / / PAT FOR 0.5 128 136 142 143 246 226 227 211 213 217 335 336 314 316 342 // //T=43.89 // / /Reset optdelsyr to 0 (202 ul © 14.5 s/ul =2929 ul © 750s/s=4.0sec. /Move optpp to draw oldsample from waste side of flowcell, 2nd channel. /Drain RBC cup thru opt pit feed line. PAT FOR 0.5 136 142 143 246 233 234 236 226 227 211 217 335 336 314 316 342 // //T=44.39 // / / /Close plumbing on left side of opt xducer allowing more rt side flow, /for more effective reagent use. /Rinse retic line to waste cup #2. STEP Rll PAT FOR 1.0 136 142 143 222 223 224 246 233 234 236 227 211 217 335 336 314 342 // //T=44.89 // 211 212 /Flush pit delivery line. /Rinse retic line to waste cup #2. PAT FOR 1.5 136 142 143 246 222 223 224 233 234 236 227 211 217 335 336 314 342 // //T=45.89 // /Take up backlash in rbcdelsyr. PAT FOR 0.5 136 142 143 246 233 234 236 227 211 217 335 336 314 342 // //T=47.39 // RAMP RBCDELSYR FAST400 STEP RBC22 MOVE RBCDELSYR BY 150/ 150s © 400s/s = .375sec / / /One last purge of left side of opt flowcell. PAT FOR 0.5 136 142 143 246 236 226 227 211 217 335 336 327 314 316 342 // //T=47.89 // / PAT FOR 0.5 136 143 246 236 226 227 211 217 335 336 327 314 316 342 // //T=48.39 // / PAT FOR 3.0 136 143 /OPEN 153 STEP Wll MOVE OPTDELSYR BY 268 212 213 PAT FOR 1.0 / // //T=48.89 // / / END / * /* Copyright 1994 by Abbott Laboratories /* Source Code Control System keywords /* /* NAME: $Source: /tmp/RCS/reticvu. f,v $ /* $Locker: $ /* $State: R4 $ /* $Revision: 1.10 $ /* $Author: rodl $ /* $Date: 95/03/15 01:36:19 $ /* Log: .. See below /* /* LANGUAGE: CD4000 Flow sequence language /* /* DESCRIPTION: /* Does optical analysis of sample in retic cup. Uses prototype /* valve designations.Cleans cup during analysis. 213 214 /* /* ....$Log: reticvu.f,v $ /* Revision 1.10 95/03/15 01:36:19 rodl /* Add better cotinuity of optical flowcell activity to prevent sample from reaching flowcell walls. /* /* Revision 1.9 95/03/13 15:13:23 rodl /* Add reference timing values , no functional change. /* /* Revision 1.8 95/03/10 11:34:12 rodl /* removed autosamp advance signal in favor of earlier signal in cbs2 /* /* Revision 1.7 95/03/08 18:18:40 davef /* removed erroneously added EVENT SPIN 1 which is obsolete /* / /* /* Revision 1.6 95/03/07 10:51:12 rodl /* added spin event to run back to back autosampler CBCR samples /* /* Revision 1.5 95/02/15 21:04:44 rodl /* Add hybred stepper to optdelsyr to improve dynamic range. /* /* /* Revision 1.4 95/01/11 19:08:18 rodl /* Change count statement to reflect 420:1 dilution ratio for the 4:1 dilution /* giving 1680:1 overall dilution ratio. /* . /* /* Revision 1.3 94/11/18 12:57:12 davef /* added signal to autosampler when ready, this is in a preliminary /* position and will probably change. 214 215 /* /* Revision 1.2 94/11/16 22:05:46 rodl /* Add ready to reticvu to restrict overlap of subsequent run. /* /* Revision 1.1 94/09/29 23:17:26 scotts /* Initial revision /* /* /* Rev 1.6 29 Sep 1994 17:06:20 RODL /* Changed the sample transfer dynamics slightly to better center the slug /* of mix around the nozzle "T" node. /* /* Rev 1.5 20 Sep 1994 19:27:56 RODL /* Remove wbcsetup to allow pmt v to go to min. /* /* Rev 1.4 19 Sep 1994 22:25:00 RODL /* Improve the handoff of the transfer to the delivery by extending /* the peripump motion beyond the time when v223 closes. /* /* Rev 1.3 19 Sep 1994 20:32:46 RODL /* Remove vl38 on .. callout(filter and shutter mover). No pressure to /* filter cylinder. /* /* Rev 1.2 19 Sep 1994 19:21:54 RODL /* Corrected fo an incorrectly translated (due to cvttab error) conversion /* between vl4 and 131 and between v64 and 134; they were reversed. /* /* Rev 1.1 16 Aug 1994 20:29:26 RODL /* Replace quenchsyr with rtcdilsyr callouts. 215 216 /* /* Rev 1.0 16 Aug 1994 16:55:00 RODL /* Initial revision. /* /* Rev 1.8.1.4 06 Jun 1994 15:55:56 RODL /* Raise filter before data is taken and setup wbc after data is taken to protect /* the pmt photocathode. /* /* Rev 1.8.1.3 01 Feb 1994 20:44:00 RODL /* /* /* Rev 1.8.1.2 27 Jan 1994 18:38:42 RODL /* Change to rbcpp pump and open filters 127 128. /* /* Rev 1.8.1.1 15 Oct 1993 12:16:34 AMYS /* Amy was here /* Fix up PROTO branching to go off of 1.8.1 /* /* Rev 1.9 14 Oct 1993 15:26:42 RODL /* Added new proto valve designations. /* /* Rev 1.8 17 Aug 1993 19:58:20 RODL /* Corrected vlo2 closure error during sample advance. /* /* Rev 1.7 03 Feb 1993 14:40:02 RODL /* /* Close optical filter before setup to prevent pmt overcurrent alarm. /* /* Rev 1.6 11 Jan 1993 17:17:12 RODL /* Adapted script to work with new nozzle. / * 216 217 / * / BEGIN RETICVU(sampid) // //T=0.00 // /Do wbc drawback. /Initialize the reservoir conditions at the handoff from cbc. PAT FOR 1.0 136 335 336 337 327 431 434 316 314 226 227 // //T=0.00 // / /Reset the retic dilution syringe /Transfer retics to flowcell proximity. /Raise filter to protect photocathode before setpoints are raised. PAT FOR 1.6 136 221 223 134 215 335 336 337 327 431 127 434 // //T=1.00 // RAMP RTCDILSYR SLOW400 STEP R2 MOVE RTCDILSYR TO 0 /3.1006 UL/STEP=> for 600 ul @400s/s=.5sec. RAMP RBCPP FAST400 STEP R3 MOVE RBCPP BY 900 /was 2402.Oul / 2.5 sec ©400 s/s =1000steps/WAS 4054 © 750 for 2 sec. / PAT FOR 0.4 136 221 134 215 314 335 336 337 327 431 127 434 // //T=2.60 // /Do short drawback of wbc' s to avoid carryover into retics. 217 218 /Finish transfer with flowcell diluent on to bring node to pressure. STEP R4 PAT FOR 0.2 136 221 226 227 335 336 337 327 314 316 431 127 434 // //T=3.0 // / /Before emptying retic cup close 223 for 0.2sec. /Advance retics to flowcell for analysis. /Drain retic cup. STEP R5 PAT FOR 0.5 136 221 222 224 335 336 337 327 314 316 431 127 434 // //T=3.20 // / DISABLE SETUP RTC RAMP OPTDELSYR SLOW1389 STEP R6 MOVE OPTDELSYR BY 4189 /156.OUL/104.Oul / ©26.85 st/ul==> 1500steps in 2 sec=750stps/sec. /Drain the retic cup PAT FOR 2.5 136 221 222 224 335 336 337 327 314 316 431 127 434 // //T=3.70 // / / / 218 219 / /Rinse and drain the retic cup. /Begin 2ul/sec flow of wbc,s to the optical flowcell. /29.3s/s for 9.5 sec = 275.5 steps STEP R7 PAT FOR 0.3 136 221 222 224 147 335 336 337 327 314 316 431 127 434 // //T=5.95 // RAMP OPTDELSYR FAST53_8 STEP R8 MOVE OPTDELSYR BY 510/19.Oul /29s/sec = 14.5stp/ul © 2ul/sec for 9.5 sec. / / / /Drain the retic cup PAT FOR 1.2 136 221 222 224 335 336 337 327 314 316 431 127 434 // //T=6.25 // / / /Fill the retic cup. PAT FOR 0.6 136 222 224 147 335 336 337 327 314 316 431 127 434 // //T=7.45 // STEP R9 COUNT RTC MINTIME 8.0 MAXTIME 8.0 DIL 1680.0 RATE 2.0 UNTIL 0 SAMPLEID sampid REAG 0 219 220 / /Add statement to mark time. PAT FOR 0.5 136 222 224 335 336 337 327 314 316 431 127 434 // //T=8.05 // / / /Again, retic cup drain STEP RIO PAT FOR 2.0 136 221 222 224 335 336 337 327 314 316 431 127 434 // //T=8.55 // / /Rinse the retic cup PAT FOR 0.3 136 221 222 224 147 335 336 337 327 314 316 431 127 434 // //T=10.55 // / /Final retic cup drain PAT FOR 3.0 136 221 222 224 335 336 337 327 314 316 431 127 434 // //T=10.85 // READY / / /Mark time until end of retic count. PAT FOR 3.3 136 222 224 335 336 337 327 314 316 431 127 434 220 221 // //T=13.77 // PAT FOR 0.4 136 222 224 335 336 337 327 314 316 431 127 434 / /Add wbc setup to provide for lower voltages on the pmt after filter is down. /SETUP WBC / PAT FOR 0.0 / / ENABLE // //T=14.69 // / END /** / * /* Copyright 1994 by Abbott Laboratories /* Source Code Control System keywords /* /* NAME: $Source: /tmp/RCS/reticvu. f,v $ /* $Locker: $ /* $State: R4 $ /* $Revision: 1.10 $ /* $Author: rodl $ /* $Date: 95/03/15 01:36:19 $ /* Log: .. See below 221 222 /* /* LANGUAGE: CD4000 Flow sequence language /* /* DESCRIPTION: /* Does optical analysis of sample in retic cup. Uses prototype /* valve designations.Cleans cup during analysis. /* /* ....$Log: reticvu.f,v $ /* Revision 1.10 95/03/15 01:36:19 rodl /* Add better cotinuity of optical flowcell activity to prevent sample from reaching flowcell walls. /* /* Revision 1.9 95/03/13 15:13:23 rodl /* Add reference timing values , no functional change. /* /* Revision 1.8 95/03/10 11:34:12 rodl /* removed autosamp advance signal in favor of earlier signal in cbs2 /* /* Revision 1.7 95/03/08 18:18:40 davef /* removed erroneously added EVENT SPIN 1 which is obsolete /* / /* /* Revision 1.6 95/03/07 10:51:12 rodl /* added spin event to run back to back autosampler CBCR samples /* /* Revision 1.5 95/02/15 21:04:44 rodl /* Add hybred stepper to optdelsyr to improve dynamic range. /* /* /* Revision 1.4 95/01/11 19:08:18 rodl /* Change count statement to reflect 420:1 dilution ratio for 222 223 the 4:1 dilution /* giving 1680:1 overall dilution ratio. /* /* /* Revision 1.3 94/11/18 12:57:12 davef /* added signal to autosampler when ready. this is in a preliminary /* position and will probably change. /* /* Revision 1.2 94/11/16 22:05:46 rodl /* Add ready to reticvu to restrict overlap of subsequent run. /* /* Revision 1.1 94/09/29 23:17:26 scotts /* Initial revision /* /* /* Rev 1.6 29 Sep 1994 17:06:20 RODL /* Changed the sample transfer dynamics slightly to better center the slug /* of mix around the nozzle "T" node. /* /* Rev 1.5 20 Sep 1994 19:27:56 RODL /* Remove wbcsetup to allow pmt v to go to min. /* /* Rev 1.4 19 Sep 1994 22:25:00 RODL /* Improve the handoff of the transfer to the delivery by extending /* the peripump motion beyond the time when v223 closes. /* /* Rev 1.3 19 Sep 1994 20:32:46 RODL /* Remove vl38 on .. callout(filter and shutter mover). No pressure to /* filter cylinder. /* 223 224 /* Rev 1.2 19 Sep 1994 19:21:54 RODL /* Corrected fo an incorrectly translated (due to cvttab error) conversion /* between vl4 and 131 and between v64 and 134; they were reversed. /* /* Rev 1.1 16 Aug 1994 20:29:26 RODL /* Replace quenchsyr with rtcdilsyr callouts. /* /* Rev 1.0 16 Aug 1994 16:55:00 RODL /* Initial revision. /* /* Rev 1.8.1.4 06 Jun 1994 15:55:56 RODL /* Raise filter before data is taken and setup wbc after data is taken to protect /* the pmt photocathode. /* /* Rev 1.8.1.3 01 Feb 1994 20:44:00 RODL /* /* /* Rev 1.8.1.2 27 Jan 1994 18:38:42 RODL /* Change to rbcpp pump and open filters 127 128. /* /* Rev 1.8.1.1 15 Oct 1993 12:16:34 AMYS /* Amy was here /* Fix up PROTO branching to go off of 1.8.1 /* /* Rev 1.9 14 Oct 1993 15:26:42 RODL /* Added new proto valve designations. /* /* Rev 1.8 17 Aug 1993 19:58:20 RODL /* Corrected vlo2 closure error during sample advance. /* /* Rev 1.7 03 Feb 1993 14:40:02 RODL /* 224 225 /* Close optical filter before setup to prevent pmt overcurrent alarm. /* /* Rev 1.6 11 Jan 1993 17:17:12 RODL /* Adapted script to work with new nozzle. / * /*/ BEGIN RETICVU(sampid) // //T=0.00 // /Do wbc drawback. /Initialize the reservoir conditions at the handoff from cbc, PAT FOR 1.0 136 335 336 337 327 431 434 316 314 226 227 // //T=0.00 // / /Reset the retic dilution syringe /Transfer retics to flowcell proximity. /Raise filter to protect photocathode before setpoints are raised. PAT FOR 1.6 136 221 223 134 215 335 336 337 327 431 127 434 // //T=1.00 // RAMP RTCDILSYR SLOW400 STEP R2 MOVE RTCDILSYR TO 0 /3.1006 UL/STEP=> for 600 ul @400s/s=.5sec. RAMP RBCPP FAST400 STEP R3 225 226 MOVE RBCPP BY 900 /was 2402.Oul / 2.5 sec ©400 s/s =1000steps/WAS 4054 © 750 for 2 sec. / PAT FOR 0.4 136 221 134 215 314 335 336 337 327 431 127 434 // //T=2.60 // /Do short drawback of wbc' s to avoid carryover into retics. /Finish transfer with flowcell diluent on to bring node to pressure. STEP R4 PAT FOR 0.2 136 221 226 227 335 336 337 327 314 316 431 127 434 // //T=3.0 // / /Before emptying retic cup close 223 for 0.2sec. /Advance retics to flowcell for analysis. /Drain retic cup. STEP R5 PAT FOR 0.5 136 221 222 224 335 336 337 327 314 316 431 127 434 // //T=3.20 // / DISABLE SETUP RTC RAMP OPTDELSYR SLOW1389 STEP R6 MOVE OPTDELSYR BY 4189 /156.OUL/104.Oul / ©26.85 st/ul==> 1500steps in 2 sec=750stps/sec. /Drain the retic cup r 226 227 PAT FOR 2.5 136 221 222 224 335 336 337 327 314 316 431 127 434 // //T=3.70 // / / / / /Rinse and drain the retic cup. /Begin 2ul/sec flow of wbc,s to the optical flowcell. /29.3s/s for 9.5 sec = 275.5 steps STEP R7 PAT FOR 0.3 136 221 222 224 147 335 336 337 327 314 316 431 127 434 // //T=5.95 // RAMP OPTDELSYR FAST53_8 STEP R8 MOVE OPTDELSYR BY 510/19.Oul /29s/sec = 14.5stp/ul © 2ul/sec for 9.5 sec. / / / /Drain the retic cup PAT FOR 1.2 136 221 222 224 335 336 337 327 314 316 431 127 434 // //T=6.25 // / / /Fill the retic cup. PAT FOR 0.6 136 222 224 147 335 336 337 327 314 316 431 127 227 228 434 // //T=7.45 // STEP R9 COUNT RTC MINTIME 8.0 MAXTIME 8.0 DIL 1680.0 RATE 2.0 UNTIL 0 SAMPLEID sampid REAG 0 / /Add statement to mark time. PAT FOR 0.5 136 222 224 335 336 337 327 314 316 431 127 434 // //T=8.05 // / / /Again, retic cup drain STEP RIO PAT FOR 2.0 136 221 222 224 335 336 337 327 314 316 431 127 434 // //T=8.55 // / /Rinse the retic cup PAT FOR 0.3 136 221 222 224 147 335 336 337 327 314 316 431 127 434 // //T=10.55 // / /Final retic cup drain PAT FOR 3.0 136 221 222 224 335 336 337 327 314 316 431 127 434 // 228 229 //T=10.85 // READY / / /Mark time until end of retic count. PAT FOR 3.3 136 222 224 335 336 337 327 314 316 431 127 434 // //T=13.77 // PAT FOR 0.4 136 222 224 335 336 337 327 314 316 431 127 434 / /Add wbc setup to provide for lower voltages on the pmt after filter is down. /SETUP WBC / PAT FOR 0.0 / / ENABLE // //T=14.69 // / END /** / - • / Copyright 1992 by Abbott Laboratories / Source Code Control System (PVCS) keywords / 229 230 / NAME: SWorkfile cbcsub.f $ / $Revision 1.2.1.1 $ / $Author LUNAH $ / $Date 16 Nov 1994 12:13:08 $ / .Log , see below / / LANGUAGE: CD4000 FlowScript / / DESCRIPTION: / This flow sequence is run by the AOS in the event that the operator / has requested that the measurement type be CBC+SUBSETS. It receives / two parameters from the AOS: the number of reagents currently / configured by the operator (power-up default = 1) and the length of / time (in seconds) to incubate subset samples. The idea is to use the / reagent count to control how many reagent dilutions are to be created / and to initiate an incubation of the appropriate time. / ....$Log: I: /bbd/fsq/vcs/cbcsub.f_v $ / / Rev 1.2.1.1 16 Nov 1994 12:13:08 LUNAH / When "subprep" is complete and the incubation assembly no longer needs access to / the transfer cup, move the vent-aspirate head back to the sample tube (home) / position. / / Rev 1.2.1.0 11 Oct 1994 17:50:54 LUNAH / First working version for Breadotype. 230 231 / / Rev 1.2 24 Feb 1994 18:44:06 LUNAH / Added cleaning of the vent needle so that residual blood on the needle will / not contaminate the next sample. This is necessary at this stage of the / development process because CBCSUB.F is currently subset- only; when CBCSUB.F / is indeed hematology + subset, this cleaning step will no longer be needed / since the vent needle will be cleaned during the hematology flow sequence / before the next sample is aspirated. / / Rev 1.1 25 Jan 1994 17:27:52 LUNAH / This revision of CBCSUB.F is only intended for processing one subset for a / given sample, and therefore, the number of reagent is hard-coded to "1". / Incubation time is hard-coded to 900 seconds (15 minutes) due to an apparent / bug in breadboard DSOS software, making it not possible for the operator to / specify the desired incubation time from the operator interface. / / / Rev 1.0 22 Nov 1993 20:27:52 LUNAH / This initial revision of CBCSUB.F does nothing more than FORKing SUBMANVU.F. / The purpose is to cause SUBMANVU.F to be executed when the "run" button on / the breadboard is pressed, if CBC+SUBSET is selected under TEST SELECT. / 231 232 /*/ / BEGIN CBCSUB(reagcount inctime) / Set number of reagents to 1, indicating single cocktail, and set incubation / time to 120 (NORMALLY 900) seconds for 2-minute incubation time. / reagcount = 1 inctime = 900 /normally 900 sec; 5 sec for testing purposes. / Declare variables / VAR sampid/ ID assoiciated with the whole blood sample in the tube VAR i / Generic loop variable VAR c / Cup number of the next free incubation cup. Used with / GETCUP. VAR w / Well number of the reagent well where the needed antibodies / can be found. / Get the ID associated with the whole blood in the tube. / GETID sampid / Make sure that the ASPY is at the home position before piercing cap. 232 233 / POWER HIGH LOW ASPY POWER HIGH LOW VY RAMP ASPY FAST350 RAMP VY FAST350 MOVE ASPY TO 0 MOVE VY TO 0 AWAIT ASPY AWAIT VY / Pierce sample tube and hold until sample aspiration is complete. / FORK PIERCE JOIN PIERCE / Execute flow sequence which aspirates 300ul of whole blood from the sample / tube and desposits it into the transfer cup for use in subset analysis / later. / FORK SUBASP / *** * ******* * ** * ************** * ******************************* ************** / ************************************************************* ************** / If no hematology flow sequence is to be run for the current sample, "fork" / UNPIERCE to lift the venthead after aspiration of subset sample, and "fork" / CLNVNDLE to clean the vent needle so that it will not contaminate the next 233 234 / sample. (The cleaning flow sequence CLNVNDLE moves the vent head to the / wash cone and lowers it to wash the vent needle. The vent head will start / to return to its home position approx. 4.0 seconds after "fork"ing, and / the cleaning routine ends approx. 9.5 seconds after "fork"ing. ) / If the hematology flow sequence is to be run, then this section should be / commented out because the vent head does not need to be lifted until after / aspiration of the hematology sample is done and the vent needle will be / cleaned during the hematology flow sequence, before the next sample is / aspirated. / WAIT 3.8 /2.8 FORK UNPIERCE WAIT 0.5 FORK CLNVNDLE WAIT 11.7 JOIN CLNVNDLE / Move vent-aspirate assy out of the way to allow incubation probe to move / to transfer cup. / POWER HIGH LOW ASPY POWER HIGH LOW VY RAMP ASPY FAST350 RAMP VY FAST350 MOVE VY TO 100 MOVE ASPY TO 100 234 235 AWAIT VY AWAIT ASPY ************************************************************* ************** / ************************************************************* ************** /JOIN SUBASP WAIT 0.0 /*/ ************************************************************* ************** /*/ ************************************************************* ************** /*/ After aspiration probe has returned to home position after depositing blood /*/ sample in the transfer cup, FORK the hematology flow sequence. /*/ /*FORK CBS (sampid) /* /* /*/ Wait for hematology flow sequence to finish aspirating sample before /*/ raising the piercer by "fork"ing UNPIERCE which closes vl21. /*/ /*WAIT 2.8 /*FORK UNPIERCE /CLOSE 121 235 236 /* /* /*/ Wait until it is appropriate to start processing subsets. /*/ /*PAT FOR 9.5 /*/ ************************************************************* ************** /*/ ************************************************************* ************** / ************************************************************* ************** / ************************************************************* ************** / Dummy CBC SETUP & COUNT statements, required *BEFORE* subset SETUP & COUNT. / Don't need this if CBS.f has been FORKed since CBS.f contains "real" CBC / SETUP & COUNT statements. / SETUP HGBREF WAIT 0.3 COUNT HGBREF MINTIME 1.0 MAXTIME 1.0 DIL 0.0 RATE 0.0 UNTIL 0 SAMPLEID sampid REAG 0 SETUP RBCPLT WAIT 1.1 COUNT RBCPLT MINTIME 0.1 MAXTIME 0.1 DIL 0.0 RATE 0.0 UNTIL 0 SAMPLEID sampid REAG 0 SETUP PLT WAIT 0.3 236 237 COUNT PLT MINTIME 0.1 MAXTIME 0.1 DIL 0.0 RATE 0.0 UNTIL 0 SAMPLEID sampid REAG 0 SETUP HGBSAMP WAIT 0.3 COUNT HGBSAMP MINTIME 1.0 MAXTIME 1.0 DIL 0.0 RATE 0.0 UNTIL 0 SAMPLEID sampid REAG 0 SETUP WBC WAIT 1.1 COUNT WBC MINTIME 0.1 MAXTIME 0.1 DIL 0.0 RATE 0.0 UNTIL 0 SAMPLEID sampid REAG 0 WAIT 0.3 / ************************************************************* ************** / ************************************************************* ************** / Meanwhile, allocate an unused incubation cups in which to prepare the / subset cocktails. / GETCUP c / As soon as SUBASP is done, FORK SUBPREP flow sequence which puts the blood / samples in the transfer cup into the incubation cups in preparation for / incubation with antibodies. / PAT FOR 0.0 237 238 JOIN SUBASP FORK SUBPREP(c) JOIN SUBPREP WAIT 0.0 / Move vent-aspirate assy back to sample tube position. / POWER HIGH LOW ASPY POWER HIGH LOW VY RAMP ASPY FAST350 RAMP VY FAST350 MOVE ASPY TO 0 MOVE VY TO 0 AWAIT ASPY AWAIT VY / Once the whole blood samples have been deposited into the incubation cup, / FORK the SUBINC flow sequence which prepares the incubations with / antibodies, starts the timers, and specifies the appropriate flow sequence / to be run at the end of the incubation peroid. / Note that the AOS ensures that the oldest incubations shall be / processed first. / / First specify the reagent well in which the antibodies can be found. / w = 5 FORK SUBINC(sampid w inctime c) JOIN SUBINC 238 23 9 END /* * / / Copyright 1992 by Abbott Laboratories / Source Code Control System (PVCS) keywords / / NAME: SWorkfile: subasp.f $ / $Revision: 1.1.1.1 $ / $Author: LUNAH $ / $Date: 16 Nov 1994 20:26:00 $ / .Log: .. see below / / LANGUAGE: CD4000 FlowScript / / DESCRIPTION: / This flow script is responsible for aspirating sample from the / sample tube and depositing into the transfer cup for use in subset / processing. After depositing the sample into the transfer cup, the / aspiration probe is cleaned and primed and then returned to the vent / head, ready for the next task. It is normally to be used as a FORKed / sequence from CBCSUB.F. / / ....$Log: I:/bbd/fsq/vcs/subasp.f_v $ 239 240 / / Rev 1.1.1.1 16 Nov 1994 20:26:00 LUNAH / Lengthen flush cup draining time from 1.5 seconds to 3.0 seconds to completely / drain to waste cup #1. / / Rev 1.1.1.0 12 Oct 1994 11:46:28 LUNAH / First working version for Breadotype. / / Rev 1.1 24 Feb 1994 18:37:52 LUNAH / Changed the position of aspiration probe Z during sample deposition into the / transfer cup so that the probe is at the appropriate height when the vent / head assembly is lowered by the vent-needle-cleaning flow sequence. Also / lengthen the draining time for the flush cup to ensure that the cup is / completely drained. / / Rev 1.0 25 Jan 1994 18:05:56 LUNAH / Initial revision. / /*/ BEGIN SUBASP / Keep diluent #2 line pressurized. (132 16) / Keep waste cups #1, #2 and #3 evacuated. (87 85 86! / OPEN 87 85 86 132 16 / Drain aspiration probe wash block to wc#3. (116 240 241 / Meanwhile, prepare to lower aspiration probe to aspirate sample, (i.e. , / initialize aspiration probe Z motor.) / With the piercer still down, lower the aspirate probe until it touches / the bottom of the sample tube. (221STP © 350S/S =.63 sec) / PAT FOR 0.7 116 POWER HIGH MED ASPZ RAMP ASPZ FAST350 /(350S/S) MOVE ASPZ TO -221 /UNTIL ASPLIM AWAIT ASPZ //ENDIF /(ASPLIM) / Run piston pump #1 (APRBP) to aspirate lOOul (4 revolutions © 25ul per rev. ) / of incubated mixture of whole blood and MAb's (10:1 blood:MAb's ratio). / Move incubation probe away to ensure that it does not collide with the / aspiration probe. / PAT FOR 1.1 POWER HIGH LOW APRBP RAMP APRBP SLOW300 MOVE APRBP BY -192 /4 revolutions ©48 steps per rev.= 192 steps (.64 sec) RAMP IPRBX FAST400 MOVE IPRBX TO 400 AWAIT APRBP PAT FOR 1.0 /Wait an extra second before retracting aspiration probe. / Raise aspiration probe back to home position. 241 242 / Clean the aspiration probe (1.0 sec) as we rise. / PAT FOR 1.0 FORK CLNPRBA RAMP ASPZ FAST350 /(350S/S) MOVE ASPZ TO 0 /221 steps © 350s/s = .63 sec / Continue to dry aspiration probe. (116) / Move the aspiration probe to the transfer cup. .0052"/step / PAT FOR 3.0 116 POWER HIGH LOW ASPY RAMP ASPY SLOW400 MOVE ASPY TO -980 /980 stp © 400s/s =2.31sec / Open valve to prepare for sample deposition. (65) / Lower aspiration probe. / PAT FOR 0.5 65 RAMP ASPZ FAST350 MOVE ASPZ TO -60 /-158 with piercer up. /60steps © 350s/s = .18 sec / Deposit 75ul whole blood into transfer cup. (65 & APRBP) / (75ul © 25ul/48steps = 144steps. 144steps © 400 s/s= .36 sec. ) / PAT FOR 0.5 65 /FOR 1.5 if running full panel. RAMP APRBP FAST400 MOVE APRBP BY 144 242 243 / Keep 65 open for upcoming deposition into flush cup. / Move aspiration probe to flush cup. (1130-408= 722 © 400s/s = 1.81 sec) /* After arrival of aspiration probe above the flush cup, start lowering /* aspiration probe into flush cup. / PAT FOR 2.4 65 WAIT 0.5 /Not necessary for full panel. RAMP ASPY SLOW400 MOVE ASPY TO -408 AWAIT ASPY RAMP ASPZ SLOW400 MOVE ASPZ TO -158 /was 80 w/ piercer down. / (158-120) steps © 400s/s = 0.1 seconds / Run aspiration probe piston pump for 10 revolutions to remove excess / sample. (65 & APRBP) PAT FOR 0.8 65 RAMP APRBP SLOW 00 MOVE APRBP BY 480 /480 steps @400s/s = 1.2 sec) / Keep 65 open a little longer until after aspiration probe piston pump has / stopped. / Drain flush cup briefly while filling. (63 107) / PAT FOR 0.8 63 65 107 / Fill flush cup with diluent #2 for 1.4 (was2.0) sec. (63) / Open 65 in preparation for piston pump deposition. 243 244 / Lower aspiration probe further into flush cup. / PAT FOR 1.4 63 65 RAMP ASPZ SLOW400 MOVE ASPZ TO -200 / was 120 w/ piercer down. / (200-158) steps© 400s/s = .1 sec / Fill and drain flush cup simultaneously for 1.0 (was 2.0) sec. (63 107) / With the aspiration probe tip submersed, flush aspiration probe into the / flush cup using the piston pump. (65 & APRBP) / PAT FOR 1.0 63 65 107 /was 2.0 RAMP APRBP FAST400 MOVE APRBP BY 384 /384 steps © 400s/s = .96 sec / Drain flush cup to waste cup #1. (107) / Clean the aspiration probe (1.0 sec) as it moves back up to home position. / After aspiration probe Z has been fully retracted, bring aspiration probe / Y to 100 (past home position) to allow enough room for the incubation probe / to go to the transfer cup to aspirate the sample for subset processing. / PAT FOR 2.0 107 /was 1.0 sec FORK CLNPRBA RAMP ASPZ SLOW400 MOVE ASPZ TO 0 /200steps @400s/s= 0.5 sec AWAIT ASPZ RAMP ASPY SLOW400 244 245 MOVE ASPY TO 0 /508 steps © 400s/s = 1.27 sec JOIN CLNPRBA / Continue to dry aspiration probe. (116) / Continue to drain flush cup to waste cup #1. (107) / PAT FOR 3.0 116 107 WAIT 3.0 / Fill diluent reservoir #2 and empty waste cups #1 and #3 before leaving / this flow sequence. / CLOSE 87 86 132 16 FORK LVLDR24 FORK MTWC14 FORK MTWC34 JOIN LVLDR24 JOIN MTWC14 JOIN MTWC34 END ** / -- / Copyright 1992 by Abbott Laboratories / Source Code Control System (PVCS) keywords / / NAME: $Workfile: subinc. f $ 245 246 / $Revision: 1.0.1.0 $ / $Author: LUNAH $ / $Date 12 Oct 1994 12:08:54 $ / .Log: . see below / / LANGUAGE: CD4000 FlowScript / / DESCRIPTION: This flow sequence prepares a subset incubation by mixing / the sample in the specified incubation cup "c" with the / reagent in reagent well "w", starting the incubation timer, / and specifying the appropriate flow sequence to be run at / the end of the incubation period. It is normally to be / used as a FORKed sequence from CBCSUB.F. / / ....$Log: I:/bbd/fsq/vcs/subinc. f_v $ / / Rev 1.0.1.0 12 Oct 1994 12:08:54 LUNAH / First working version for Breadotype. / / Rev 1.0 25 Jan 1994 18:07:20 LUNAH / Initial revision. / /*/ / BEGIN subinc (sampid w inctime c) VAR incx / X-coord of the incubation cup "C". 246 247 VAR incy / Y-coord of the incubation cup "C". VAR col / Column number (x-index) of incubation cup "C" VAR row / Row number (y-index) of incubation cup "C". VAR reagx / X-coord of the reagent well. VAR reagy / Y-coord of the reagent well. / The following table is to be used to navigate the incubation probe to the / appropriate reagent well. The "reagxpos" and "reagypos" variable arrays / contains the position of the IPRBY motor for each of the six reagent wells / used on the breadboard. The position of the IPRBX motor is the same for / all six reagent wells. / VAR reagxpos[6] reagxpos[0] = 690 reagxpos[1] = 690 reagxpos[2] = 690 reagxpos[3] = 810 reagxpos[4] = 810 reagxpos[5] = 810 VAR reagypos[6] reagypos[0] = -940 reagypos[1] = -1065 reagypos[2] = -1190 reagypos[3] = -940 reagypos[4] = -1065 reagypos[5] = -1190 / The following tables are to be used to navigate the incubation probe to the / appropriate incubation cup. The "incxpos" variable array contains / the position of the IPRBX motor for each of the 15 incubation strip / columns (each containing 4 cups) . Similarly, the "incypos' 247 248 variable / array contains the position of the IPRBY motor for each of the 4 incubation / strip rows (each containing 15 cups) . / VAR incxpos[15] incxpos[0] = 328 incxpos[1] = 378 incxpos[2] = 428 incxpos[3] = 478 incxpos[4] = 528 incxpos[5] = 645 incxpos[6] = 695 incxpos[7] = 745 incxpos[8] = 795 incxpos[9] = 845 incxpos[10] = 962 incxpos[11] = 1012 incxpos[12] = 1062 incxpos[13] = 1112 incxpos[14] = 1162 VAR incypos [4] incypos [0] = -30 incypos[1] = -140 incypos[2] = - 250 incypos[3] = -360 / Set speeds of incubation probe motors: X, Y, and Z, / RAMP IPRBX SLOW400 RAMP IPRBY SLOW1200 RAMP IPRBZ SLOW400 RAMP IPRBP FAST400 /SLOW400 /FAST400 / Determine the X and Y coordinates of the reagent well from which the / incubation probe will be aspirating. / To bring the incubation probe to the reagent well number "w", we use the / reagent well number "w" to index into the reagypos array to get the / position for the IPRBY motor. The position for the IPRBX 248 249 motor is the / same for all six reagent wells on the breadboard. / reagx = reagxpos [w] reagy = reagypos[w] / Move the incubation probe to the reagent well. / MOVE IPRBX TO reagx AWAIT IPRBX WAIT 0.2 MOVE IPRBY TO reagy AWAIT IPRBY WAIT 0.2 //Move the incubation probe to the designated reagent well. // /MOVE IPRBX TO 690 /AWAIT IPRBX /WAIT 0.2 /MOVE IPRBY TO -940 /AWAIT IPRBY /WAIT 0.2 / Open valves for incubation probe aspiration and deposition. (17 132 16) / OPEN 17 132 16 / Lower the incubation probe into the reagent well, / 249 250 MOVE IPRBZ TO 320 /was 420 for off-the-shelf pediatric tube AWAIT IPRBZ WAIT 0.2 / Aspirate 20ul from the reagent well. / MOVE IPRBP BY -96 /20ul © lOul/rev = 2 rev x 48 steps/rev 96 steps AWAIT IPRBP wait 0.2 // Close valves previously open for incubation probe aspiration and // deposition. (17 132 16) // /CLOSE 17 132 16 / Raise incubation probe from reagent well. / MOVE IPRBZ TO 0 / Determine the X and Y coordinates of the incubation cup into which the / reagent is to be deposited. / To bring the incubation probe to the incubation cup number c, we use / the logical operators supported by the flow sequence compiler to extract / the cup number modulo 2 and modulo 12 to index into the incxpos and incypos / arrays respectively. 250 251 / col = c>>2 row = c - col * 4 incx = incxpos [col] incy = incypos [row] / Move incubation probe to incubation cup number c as soon as the probe is / fully retracted. / AWAIT IPRBZ WAIT 0.2 MOVE IPRBX TO incx AWAIT IPRBX WAIT 0.2 MOVE IPRBY TO incy AWAIT IPRBY WAIT 0.2 // Open valves for incubation probe aspiration and deposition. (17 132 16) // /OPEN 17 132 16 / Deposit the 2Oul of antibodies into the incubation cup with the piston / pump. / MOVE IPRBP BY 96 /20ul © lOul/rev = 2 rev x 48 steps/rev = 96 steps AWAIT IPRBP WAIT 0.5 251 252 / Close valves previously open for incubation probe aspiration and / deposition. (17 132 16) / CLOSE 17 132 16 / Mix the sample and the antibodies with the incubation probe. / FORK INCUMIX JOIN INCUMIX / FORK PRIMIPRB flow sequence to clean, prime, and dry O.D. of incubation / probe to get ready for its next task. / FORK PRIMIPRB JOIN PRIMIPRB / Now that the sample and the antibodies have been mixed together, incubation / has begun. We need to 'schedule' processing of the sample by a flow / sequence in 'inctime' seconds. We also need to inform the flow sequence / that processes the incubated sample of the sample id, the reagent number / and the incubation cup number. The cup number will be sufficient to / navigate to the cup and also to release the cup after it 252 253 has been cleaned. / The AOS shall automatically start the flow sequence when the time expires / if the system is otherwise idle. / Note that the breadboard doesn't perform any fancy scheduling of incubated / vs. newly introduced samples. / Note that the lastreag parameter shall be forwarded to the SUBVU flow / sequence as received from the CBCSUB flow sequence. / INCUBATE CUP c FOR inctime SUBVU(sampid c incx incy) /INCUBATE CUP c FOR inctime DUMMY / ************************************************************* *************** / ******** * **************************************************** *************** / / The following is for testing only; if SUBINC is "forked" from CBCSUB: / 1) Comment out "FORK SUBVU" etc and replace with INCUBATE statement to use / AOS to keep track of incubation timer. / 2) Comment out the dummy CBC SETUP and COUNT statements. / /WAIT 5.0 /FORK SUBVU(sampid c incx incy) /SETUP HGBREF /WAIT 0.3 253 254 /COUNT HGBREF MINTIME 1.0 MAXTIME 1.0 DIL 0.0 RATE 0.0 UNTIL 0 / SAMPLEID sampid REAG 0 /SETUP RBCPLT /WAIT 1.1 /COUNT RBCPLT MINTIME 0.1 MAXTIME 0.1 DIL 0.0 RATE 0.0 UNTIL 0 / SAMPLEID sampid REAG 0 /SETUP PLT /WAIT 0.3 /COUNT PLT MINTIME 0.1 MAXTIME 0.1 DIL 0.0 RATE 0.0 UNTIL 0 / SAMPLEID sampid REAG 0 /SETUP HGBSAMP /WAIT 0.3 /COUNT HGBSAMP MINTIME 1.0 MAXTIME 1.0 DIL 0.0 RATE 0.0 UNTIL 0 / SAMPLEID sampid REAG 0 /SETUP WBC /WAIT 1.1 /COUNT WBC MINTIME 0.1 MAXTIME 0.1 DIL 0.0 RATE 0.0 UNTIL 0 / SAMPLEID sampid REAG 0 /WAIT 0.3 /JOIN SUBVU / / ************************************************************* *************** / ************************************************************* *************** END 254 255 / * * / Copyright 1992 by Abbott Laboratories / Source Code Control System (PVCS) keywords / / NAME: $Workfile: subprep. f $ / $Revision: 1.0.1.0 $ / $Author: LUNAH $ / SDate: 12 Oct 1994 12:14:02 $ / .Log: .. see below / / LANGUAGE: CD4000 FlowScript / / DESCRIPTION: / Given the total number of reagents with which a blood sample is to be / incubated and the id's of the sites in which these incubations are to / take place, SUPREP will aspirate the blood sample from the transfer / cup and deposit 40ul into the designated incubation cups. It is / normally to be used as a FORKed sequence from CBCSUB.F. / / ....$Log: I: /bbd/fsq/vcs/subprep. f_v $ / / Rev 1.0.1.0 12 Oct 1994 12:14:02 LUNAH / First working version for Breadotype. / / Rev 1.0 25 Jan 1994 18:09:38 LUNAH 255 256 / Initial revision. / /*/ BEGIN SUBPREP(c) VAR incx / Variable holding the X-coordinate of the current incubation / cup. VAR incy / Variable holding the Y-coordinate of the current incubation / cup. VAR col VAR row VAR ypos [4] ypos[0] = -30 ypos.l] = -140 ypos[2] = -250 ypos[3] = -360 VAR xpos[15] xpos[0] = 328 xpos[l] = 378 xpos[2] = 428 xpos[3] = 478 xpos[4] = 528 xpos[5] = 645 xpos[6] = 695 xpos[7] = 745 xpos[8] = 795 xpos[9] = 845 xpos[10] = 962 xpos.ll] = 1012 xpos[12] = 1062xpos[13] = 1112xpos[14] = 1162 / Initialize incubation probe motors / POWER HIGH LOW IPRBX POWER HIGH LOW IPRBY POWER HIGH MED IPRBZ POWER HIGH LOW IPRBP RAMP IPRBX SLOW400 RAMP IPRBY SLOW1200 RAMP IPRBZ SLOW400 256 257 RAMP IPRBP FAST400 /SLOW750 / Move incubation probe to transfer cup to pick up sample for subset / processing. / MOVE IPRBX TO 5 MOVE IPRBY TO -650 AWAIT IPRBX AWAIT IPRBY / Lower incubation probe to bottom of transfer cup to ensure proper / aspiration. / MOVE IPRBZ TO 360 /was 380 AWAIT IPRBZ / Open valves for incubation probe aspiration and deposition. (17 132 16) / Aspirate 70ul (280ul for full panel) of sample from the transfer cup by / using the piston pump. (can also be done by the RBC dilution syringe) / OPEN 132 16 PAT FOR 0.9 17 MOVE IPRBP BY -336 /70ul x Irev/lOul x48stps/rev = 336 steps © 400s/s = .84 sec AWAIT IPRBP WAIT 0.2 257 258 / Raise incubation probe out of transfer cup after aspiration. / MOVE IPRBZ TO 0 AWAIT IPRBZ WAIT 0.5 // Deposit the first drop of sample back into the transfer cup to initialize // end condition of incubation probe. (17 & IPRBP) // /PAT FOR 0.2 17 /MOVE IPRBP BY 48 /AWAIT IPRBP /WAIT 0.5 / Move incubation probe to the incubation wells previously allocated for this / purpose. / /incx = xpos[c&l] /incy = ypos[c»l] col = c»2 row = c - col * 4 incx = xpos[col] incy = ypostrow] /Move incubation probe to the location of the incubation site. 258 259 / MOVE IPRBX TO incx MOVE IPRBY TO incy AWAIT IPRBX AWAIT IPRBY / Lower incubation probe to slightly above the incubation cup before / deposition. / MOVE IPRBZ TO 55 / (55 steps © 400s/s = .14 sec) AWAIT IPRBZ / Deposit 40ul of sample into incubation cup. (17 & IPRBP) / PAT FOR 0.6 17 MOVE IPRBP BY 192 / (40ul = 4 rev = 192 steps © 400s/s = .48 sec) AWAIT IPRBP WAIT 0.5 / Raise incubation probe after deposition is complete. / MOVE IPRBZ TO 0 AWAIT IPRBZ / Close valves previously open to pressurize diluent #2 reservoir and line. / (132 16) / CLOSE 132 16 259 260 / Clean and dry transfer cup. / RAMP IPRBX SLOW400 RAMP IPRBY SLOW1200 MOVE IPRBY TO -650 AWAIT IPRBY MOVE IPRBX TO 5 AWAIT IPRBX FORK CLNSITE JOIN CLNSITE WAIT 1.0 / FORK CLNIPRB flow sequence to clean, prime, and dry O.D. of incubation / probe to get ready for its next task. / FORK CLNIPRB JOIN CLNIPRB END ** / Copyright 1992 by Abbott Laboratories / Source Code Control System (PVCS) keywords / / NAME: $Workfile: subvu.f $ / $Revision: 1.3.1.1 $ 260 261 / $Author: LUNAH $ / $Date: 16 Nov 1994 11:10:10 $ / .Log: .. see below / / LANGUAGE: CD4000 FlowScript / / DESCRIPTION: / This flow sequence is responsible for processing an incubated sample / by transfering it from its incubation cup to the hotpot for lysing / and then delivering it to the optical flow cell for counting and data / collection. It is normally to be used as a FORKed sequence from / SUBINC.F, which in turn is FORKed from CBCSUB.F. / / ....$Log: I: /bbd/fsq/vcs/subvu. f_v $ / / Rev 1.3.1.1 16 Nov 1994 11:10:10 LUNAH / Open valve #127 only, rather than #127 and #128, during subset data / collection ("COUNT SUB" statement) in order to get FLl and PSS signals / instead of FLl and FL2. This change is to make the flowscript compatible / with WBC expanded differential methods work rather than lymphocyte subset / methods work. / / Rev 1.3.1.0 12 Oct 1994 12:19:02 LUNAH / First working version for Breadotype. / / Rev 1.3 09 Jun 1994 14:52:32 LUNAH 261 262 / Added "SETUP WBC" to flowscript to return PMT setpoints to appropriate levels / prior to removing the optical filters from the light path. / / Rev 1.2 21 Mar 1994 19:43:36 LUNAH / Change step rate of incubation piston pump motor from SLOW750 to FAST400 / because some piston pumps miss step at 750 steps/second. / / Rev 1.1 10 Feb 1994 10:58:06 LUNAH / Updated erroneous comments regarding a "fork"ed subroutine, ADDLYSE. No / change to executable code. / / Rev 1.0 25 Jan 1994 18:10:48 LUNAH / Initial revision. / /*/ / This flow sequence is responsible for processing an incubated sample. / It is normally to be used as a FORKed sequence from SUBINC.F, which in / turn is FORKed from CBCSUB.F. BEGIN subvu(sampid c incx incy) VAR reagid reagid = 1 / Keep waste cup #1, #2 and #3 evacuated. (87 85 86) / Keep diluent lines (#1 and #2) pressurized. (122 97 & 132 16) / 262 263 OPEN 87 85 86 122 132 97 16 / Open vl7 to prepare for aspiration, / OPEN 17 / Move aspiration assembly to the back so that incubation probe can access / the wbc cup (hotpot) to deposit the incubated sample. / POWER HIGH LOW ASPY RAMP ASPY SLOW400 MOVE ASPY TO -1323 / Move incubation probe to the cup with the incubated sample in it. / POWER HIGH LOW IPRBX POWER HIGH LOW IPRBY RAMP IPRBX SLOW 00 RAMP IPRBY SLOW400 MOVE IPRBX TO incx MOVE IPRBY TO incy / FORK ADDLYSE to inject 670ul (3Oul incubated sample © 40:20 blood:antibody / ratio => 20ul blood © 35x dilution => 20 x 35 - 30 = 670ul diluent) / wbc diluent into the hotpot and then reprime the wbc dilution syringe / afterwards. (Injection of wbc diluent is completed 263 264 approximately 2.2 / seconds after FORKing. Entire addlyse flow sequence ends approximately / 6.6 seconds after FORKing.) / FORK ADDLYSE / As soon as incubation probe arrives at the specified cup location, lower / incubation probe into the cup. / AWAIT IPRBX AWAIT IPRBY POWER HIGH MED IPRBZ RAMP IPRBZ SLOW400 /FAST200 MOVE IPRBZ TO 360 /was 384 /360 steps © 200s/s = 1.80 sec AWAIT IPRBZ / Aspirate 40ul of incubated sample from the incubation cup. (was 50ul) / POWER HIGH LOW IPRBP RAMP IPRBP FAST400 /MOVE IPRBP BY -240 /50ul © lOul/rev = 5 rev x 48 step/rev = 240 steps / /240 steps © 400s/s = 0.60 sec MOVE IPRBP BY -192 /40ul © lOul/rev = 4 rev x 48 step/rev = 192 steps /192 steps © 400s/s = 0.48 sec AWAIT IPRBP WAIT 0.2 264 265 / Raise incubation probe out of the cup. / MOVE IPRBZ TO 0 /360 steps © 400s/s = 0.9 sec AWAIT IPRBZ // Deposit lOul of incubated sample back into incubation cup to initialize // end condition of probe. // /MOVE IPRBP BY 48 /AWAIT IPRBP /WAIT 0.5 / Move incubation probe to wbc cup (hotpot) . / Deposit 30ul of incubated sample into the hotpot, (was 40ul) / MOVE IPRBY TO -910 /distance from farthest cup = -30+910 = 880 => 0.74sec /distance from nearest cup = -360+910 = 550 => 0.46sec WAIT 0.5 MOVE IPRBX TO 5 /distance from farthest cup = 1162-5 = 1157 => 2.90sec /distance from nearest cup = 328-5 = 323 => 0.81sec AWAIT IPRBX AWAIT IPRBY WAIT 0.5 /MOVE IPRBP BY 192 /40ul © lOul/rev = 4 rev x 48 steps/rev 192 steps / /192 steps © 400s/s = 0.48 sec MOVE IPRBP BY 144 /30ul © lOul/rev = 3 rev x 48 steps/rev 265 266 144 steps /144 steps © 400s/s = 0.36 sec AWAIT IPRBP / Vortex hotpot for 5 seconds after sample deposition to ensure proper mixing / of sample and wbc diluent to effectively lyse the rbc's. / Wait 0.5 seconds after sample deposition. / Close vl7 since sample deposition by incubation probe is done. / FORK CLNICUP to clean the incubation site and then clean, prime, and dry / O.D. of incubation probe. / Move aspiration assembly back to the home position now that the incubation / probe has moved away from the wbc cup (hotpot) . / PAT FOR 5.0 67 WAIT 0.5 CLOSE 17 FORK CLNICUP(incx incy) MOVE ASPY TO 0 / Move appropriate optical filters into place. (Open 127 and 128 for FLl and / FL2 respectively; close 127 and 128 for DSS and PSS respectively. ) / OPEN 127 /128 266 267 / Wait until sample has been in hotpot for 11 seconds prior to bulk transfer. / PAT FOR 6.0 / Load the appropriate subset hardware setpoints into the hardware using / the SETUP command. This should happen a second or two before the subset / COUNT starts. / SETUP SUB / Disable 10-psi pressure regulation to prepare for data gathering. / DISABLE / Bulk transfer of sample (incubated, diluted and fully lysed) from vortexer / to staging area in preparation for injection into optical flow cell. (55 57 / 57 73) /PAT FOR 1.4 55 57 73 /106/Added 106 only because cbs.f has it. Was 1.8s /POWER HIGH LOW HGBPP /OPTPP /RAMP HGBPP FAST400 /MOVE HGBPP BY 640 /640 steps © 400 s/s = 1.6 sec; was 880 steps & 2.2sec) PAT FOR 2.1 55 57 73 /106 POWER HIGH LOW HGBPP /OPTPP RAMP HGBPP SLOW400 267 268 MOVE HGBPP BY 920 /920 steps © 400 s/s = 2.3 sec; was 880 steps & 2.2sec) / Close off WBC path (57) to staging area for 0.2 sec before opening wbc / cup drain (56) to prevent backflow. / Open 106 during the last .2 sec of optical peri-pump activity / to pressurize the delivery line. / Drain WBC cup for 2.5 seconds into waste cup #2. (55 56) / Start Sheath flow through flow cell. (106 104) / PAT FOR 0.2 55 73 106 104 PAT FOR 2.5 55 56 106 104 / Continue sheath flow through flow cell. (106 104) / Advance subset sample into flow cell © 27.6ul/sec (400 stps/sec © / 14.5 stps/ul) for 2 seconds. (71 106; OPTDELSYR) / PAT FOR 2.0 71 106 104 /57 POWER HIGH LOW OPTDELSYR RAMP OPTDELSYR FAST400 MOVE OPTDELSYR BY 55.2UL / (400 St/sec * 2 sec) / 14.5 St/ul = 55.17ul AWAIT OPTDELSYR / Continue sheath flow through flow cell. (106 104) / Continue advance of subset sample into flow cell © 2.5ul/sec for 12.5 sec. / (71 106; OPTDELSYR) / Start gathering data 2.0 seconds after 2.5ul/sec sample 268 269 advance begins. / Enable 10-psi pressure regulation again once data collection is complete. / PAT FOR 2.0 71 106 104 POWER HIGH LOW OPTDELSYR RAMP OPTDELSYR FAST36_3 /(36.3 st/sec) / (14.5 st/ul) = 2.5ul MOVE OPTDELSYR BY 454 /(36.3 st/sec * 12.5 sec) = 454 st / PAT FOR 12.0 71 106 104 COUNT SUB MINTIME 10.0 MAXTIME 10.0 DIL 35.0 RATE 2.5 UNTIL 0 SAMPLEID sampid REAG reagid / ♦ WAIT 0.5 //wait 10.5 /*/Replace "count" statement with this when testing w\ "tstvu.f" PAT FOR 0.0 ENABLE /*/ ************************************************************* *************** /*/ The purpose of the following section of flow sequence is to flush the lines /*/ to remove any residual sample, empty waste cups, reprime the optical /*/ delivery syringe, fill reservoirs, and returning hardware to previous /*/ condition. /*/ ************************************************************* *************** /* /*/The following section of flow script is copied from the original submanvu.f 269 270 /*/to reflect basically the same cleaning routine used by Rod in cbs.f. /* /*PAT FOR 0.5 22 23 112 36 81 46 71 57 56 41 44 43 73 77 106 104 /* /* / ♦ /Reset optdelsyr to 0 (202 ul © 14.5 s/ul =2929 ul © 750s/s=4.0sec. / ♦ /Drain RBC cup thru opt pit feed line. /*/ / ♦ PAT FOR 0.5 22 23 112 36 81 46 71 57 56 41 44 43 73 77 106 104 / ♦ RAMP OPTDELSYR SLOW750 /*MOVE OPTDELSYR TO 0 /BY -2929 / ♦ /* / ♦ /Close plumbing on left side of opt xducer allowing more rt side flow, / ♦ /for more effective reagent use. / ♦ / / ♦ PAT FOR 1.0 22 23 112 36 81 46 71 57 41 44 43 73 77 104 44 /* / ♦ /Flush pit delivery line. / ♦ / / ♦ PAT FOR 2.0 22 23 112 36 81 46 71 57 44 43 73 77 104 44 /* /* / ♦ /One last purge of left side of opt flowcell. /*/ / ♦ PAT FOR 0.5 23 112 36 81 42 46 71 57 56 44 43 73 77 106 104 44 134 /* / ♦ / ♦ PAT FOR 0.5 23 112 36 81 42 46 71 57 56 44 43 73 77 33 106 270 271 104 /*/ / ♦ AWAIT OPTDELSYR / ♦ MOVE OPTDELSYR BY 10.OUL / ♦ MOVE ASPY TO 0 /* /* / ♦ PAT FOR 3.0 55 56 /* /* / ************************************************************* *************** / ************************************************************* *************** / ************************************************************* *************** / The purpose of the following section of flow sequence is to flush the lines / to remove any residual sample, empty waste cups, reprime the optical / delivery syringe, fill reservoirs, and returning hardware to previous / condition. / ************************************************************* *************** /Clean subset sample lines, sample needle and optical flow cell using RBC 271 272 /diluent from diluent #2 reservoir. PAT FOR 0.5 16 23 45 47 56 57 71 73 104 106 112 /Reset optdelsyr to 0 (202 ul © 14.5 s/ul =2929 ul © 750s/s=4.0sec. / PAT FOR 0.5 16 23 45 47 56 57 71 73 104 106 112 RAMP OPTDELSYR SLOW750 MOVE OPTDELSYR TO 0 /Close plumbing on left side of opt xducer (56 106) allowing more rt side /flow, for more effective reagent use. / PAT FOR 3.0 16 23 45 47 57 71 73 104 112 /One last purge of left side of opt flowcell. / PAT FOR 1.0 16 23 45 47 56 57 71 73 104 106 112 134 / AWAIT OPTDELSYR MOVE OPTDELSYR BY 10.OUL MOVE ASPY TO 0 PAT FOR 3.0 55 56 272 273 ************ * ********** * ******* * ***** ************************ * ** * * *** * ***** * ************************* * *** * * * ***************************** *************** /Replace the hardware setpoints for subset measurements with those for wbc /measurements prior to moving the filters back to their original positions. / SETUP WBC /Move filters back to their original positions. / PAT FOR 0.5 CLOSE 127 /128 / Put off rinsing wbc cup till now / Transfer wbc diluent from reservoir to wbc cup for 2.0 seconds (13 134 24) / while vortexing to clean wbc cup. (67) PAT FOR 2.0 13 134 24 67 PAT FOR 2.0 67 / / Drain rinse diluent out of wbc cup into waste cup #2 (55 56) while / continuing to vortex. (67) PAT FOR 2.0 55 56 67 PAT FOR 5.0 55 56 WAIT 8.0 273 274 / Empty waste cups. / Fill Diluent Reservoirs. / FORK MTWC28 FORK LVLW5 FORK LVLDR24 FORK LVLDR14 OPEN 93 /Open 93 to drain optical flow cell waste isolator. WAIT 3.0 CLOSE 93 FORK MTWC34 JOIN LVLW5 JOIN MTWC28 / Evacuate waste cups #1, #2, and #3 again and keep them evacuated once / they have been emptied. / Repressurize diluent reservoirs and lines #1 (122 97)and #2 (132 16) after / filling. / OPEN 87 85 86 OPEN 16 97 122 132 / Assume the sample cup has been cleaned. It must now be deallocated. / JOIN CLNICUP FREECUP c / ♦ /Comment this line out when testing with "TSTVU.F" 274 275 / Since the incubating sample in the system for the sample with id sampid / has been processed, the id must be released. / FREEID sampid / ♦ /Comment this line out when testing with "TSTVU.F" END 275 276 APPENDIX B 276 277 * * * * Copyright 1993 by Abbott Laboratories * Source Code Control System keywords * * NAME: SSource: /home/michaelf/R2- 13/m/src/RCS/mcCBCAlgorithm.cc,v $ * $Locker: $ * $State: Exp $ * $Revision: 1.12 $ * $Author: jamesb $ * $Date: 94/10/18 17:23:50 $ * Log: .. See below * ♦ LANGUAGE: LynxOS Cl C++ * ♦ DESCRIPTION: ♦ This file contains the implementation for the top-level algorithms ♦ used to calculate CBC test results. * ♦ ....$Log: mcCBCAlgorithm.ee,v $ ♦ Revision 1.12 94/10/18 17:23:50 jamesb ♦ SCR 359: ♦ Added a function to send raw data summaries to results. * ♦ Revision 1.11 94/10/13 14:25:34 larar ♦ SCR #335: ♦ Update constructors' arguments for new dcCalibrationData interface. * 277 278 ♦ Revision 1.10 94/09/30 13:44:45 Johns ♦ SCR 373: ♦ Enable calculations for standard reference specimens. The calculations * in this case are the same as for background specimens. * ♦ Revision 1.9 94/07/22 12:04:48 larar ♦ SCR #225: ♦ Added dilution and calibration factors to argument lists of RBC and ♦ PLT algorithms in CalcResults () . * ♦ Revision 1.8 94/07/21 15:52:17 jamesb ♦ SCR 225: ♦ Added dil. and cal. factors to the interface to CBCAlgorithm. * ♦ Revision 1.7 94/07/20 16:24:15 larar ♦ No changes. ♦ ♦ Revision 1.6 94/07/14 12:20:15 jamesb ♦ SCR 225: ♦ Added RCS ID string. ♦ SCR 231: ♦ Added "delete" for all three algorithm classes created. * ♦ Revision 1.5 94/06/14 13:57:43 jamesb ♦ SCR 156: ♦ Added diagnostic messages sent to "InternalLog" file for monitoring. * ♦ Revision 1.4 94/04/11 15:12:45 jamesb ♦ Changed call to cRBCAlgorithm constructor to match changes in header file. ♦ 278 279 * Revision 1.3 94/03/07 11:45:02 jamesb * Changed function calls to match changes in class definition; used "set" * instead of assignment in constructor; chnaged specimen- type checking. * * Revision 1.2 94/02/23 14:17:52 jamesb * Added check for proper specimen type and pass-through of "TimeFlag", etc. * * Revision 1.1 94/01/26 15:34:24 jamesb * Initial revision * #include "dtlnternalLog.h" #include "mcCBCAlgorithm.h" ♦include "mcWBCAlgorithm.h" #include "mcRBCAlgorithm.h" #include "mcPLTAlgorithm.h" static const char^ const RCSid = "$Header: mcCBCAlgorithm.ccv 1.12 94/10/18 17:23:50 jamesb Exp $"; static const char Λ SourceFileName = FILE ; mcCBCAlgorithm: :mcCBCAlgorithm(const diSpecimenType& spectype, const dsWBCMeasfc wbc, const dsRBCMeas& rbc, const dsPLTiMeas& plti, const dsPLToMeas& plto, const dsHGBMeas& hgbr, const dsHGBMeasδc hgbs, 279 280 dsCBCResults& cbcrslt, const dcCalibrationData& cal, int dotiming, int priority) : specimentype (spectype) , wbcmeas (wbc) , rbcmeas (rbc) , pltimeas (plti) , pltomeas (plto) , hgbrmeas (hgbr) , hgbsmeas (hgbs) , cbcresults (cbcrslt) , caldata(cal) { SetTimeFlag( (Boolean)dotiming) ; SetPriority(priority) ; dtlnternalLog log(SourceFileName) ; log « Line ( LINE ) « "Creating CBC algorithm class" « Flush; } mcCBCAlgorithm: :-mcCBCAlgorithm( ) { dtlnternalLog log(SourceFileName) ; log << Line ( LINE ) « "Deleting CBC algorithm class" « Flush; } Boolean mcCBCAlgorithm: :CalcResults (void) { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) 280 281 << "Entering CBC algorithm 'CalcResults' function" « Flush; // Get the specimen-type data for this sample; skip doing full // calculations if it's a background sample; return a failure if it's // an improper type: if ( (specimentype.Type ( ) == diSpecimenType: :PatientSpecimen) && (specimentype.Patient ( ) == diSpecimenType: :Human) ) calcflag = TRUE; else if (specimentype.Type ( ) == diSpecimenType: :QCSpecimen) calcflag = TRUE; else if (specimentype.Type ( ) == diSpecimenType: :BackgroundSpecimen) calcflag = FALSE; else if (specimentype.Type() == diSpecimenType: :StdRefSpecimen) calcflag = FALSE; else return (FALSE) ; // Send raw summary results for all measurements: log « Line ( LINE ) << "Sending CBC raw-data summary" « Flush; SendRawSummary( ) ; // Create and run a WBC algorithm for this test: mcWBCAlgorithm^ wbcalg = new mcWBCAlgorithm(specimentype, wbcmeas, cbcresults, caldata, 281 282 ( int ) CalcFlag O , (int)TimeFlag() , GetPriority0 ) ; Boolean wbcret = wbcalg->CalcResults() ; delete (wbcalg) ; // Create and run an RBC algorithm for this test: mcRBCAlgorithm* rbcalg = new mcRBCAlgorithm(specimentype, rbcmeas, hgbrmeas, hgbsmeas, cbcresults, caldata, (int)CalcFlag( ) , (int)TimeFlag() , GetPriority() ) ; Boolean rbcret = rbcalg->CalcResults () ; delete (rbcalg) ; // Create and run a platelet algorithm for this test: mcPLTAlgorithm^ pltalg = new mcPLTAlgorithm(specimentype, pltimeas, pltomeas, cbcresults, caldata, (int)CalcFlagO , (int)TimeFlag() , 282 283 GetPriority ( ) ) ; Boolean pltret = pltalg->CalcResults ( ) ; delete (pltalg) ; log « Line( LINE ) << "Finished CBC analysis; exiting 'CalcResults' function" « Flush; return (wbcret && rbcret && pltret); }; void mcCBCAlgorithm: :SendRawSummary(void) { dsRawCBCSummary& rawcbc = cbcresults.RawCBC 0 ; rawcbc.RawWBC ( ) .Extract (wbcmeas) ; rawcbc.RawRBC ( ) .Extract (rbcmeas) ; rawcbc.RawPLTi ( ) .Extract (pltimeas) ; rawcbc.RawPLTo ( ) .Extract (pltomeas) ; rawcbc.RawHGBr( ) .Extract (hgbrmeas) ; rawcbc.RawHGBs () .Extract (hgbsmeas) ; } *_. Copyright 1993 by Abbott Laboratories ♦ Source Code Control System keywords * ♦ NAME: $Source: /home/michaelf/R2- 13/inc/RCS/mcCBCAlgorithm.h,v $ ♦ $Locker: $ ♦ $State: Exp $ 283 284 $Revision: 1.10 $ $Author: jamesb $ $Date: 94/10/18 17:20:24 $ Log: .. See below * LANGUAGE: LynxOS Cl C++ * * DESCRIPTION: * This file contains the class definition for the top-level algorithms * used to calculate CBC test results. * * ....$Log: mcCBCAlgorithm.h,v $ * Revision 1.10 94/10/18 17:20:24 jamesb * SCR 359: * Added a function to send raw data summaries to results. * * Revision 1.9 94/10/13 14:28:03 larar * SCR #335: * Update constructor arguments for new dcCalibrationData interface. * * Revision 1.8 94/07/21 15:54:21 jamesb ♦ SCR 225: * Added dil. and cal. factors to the interface to CBCAlgorithm. * * Revision 1.7 94/07/15 14:10:15 larar ♦ SCR #219: * Made destructor virtual. * * Revision 1.6 94/05/11 23:46:47 Johns * SCR 132: * In the member function GetTiming0 , delete the name for 284 285 the ♦ argument, since it is not used in the body of the function. ♦ This eliminates a "not used" compiler warning. It can be added ♦ back in when the function actually uses the argument. * ♦ Revision 1.5 94/05/05 18:27:44 jamesb ♦ Upgraded to T3 compatibility by filling in in-line functions. * ♦ Revision 1.4 94/03/07 11:30:43 jamesb ♦ Moved passed parameters to the constructor, made called functions virtual, ♦ and made other changes recommended at the inspection. * ♦ Revision 1.3 94/02/23 14:16:36 jamesb ♦ Added null copy constructor and assignment operator. * ♦ Revision 1.2 94/01/31 13:48:15 jamesb ♦ Added "graphical results" to description of what this class produces. * ♦ Revision 1.1 94/01/26 15:36:30 jamesb ♦ Initial revision * ♦ ....Previous Log as "dsResultAlgorithm.h,v" ♦ Revision 1.3 1993/11/24 09:16:55 Johns ♦ Changed 2-letter prefix from "dm" to "ds". ♦ Changed return types of algorithm calls to Boolean. ♦ Add specimen type to the argument list for the algorithms, ♦ Revision 1.2 93/11/17 17:00:18 Johns ♦ Documentation fixups as per inspection. * Added multiple inclusion guard. 285 286 * Revision 1.1 93/10/29 13:56:45 Johns * Initial revision #ifndef _mcCBCAlgorithm_ #define _mcCBCAlgorithm_ #include "cd4000.h" ♦include "diSpecimenType.h" #include "dsWBCMeas.h" #include "dsRBCMeas.h" #include "dsPLTiMeas.h" #include "dsPLToMeas.h" #include "dsHGBMeas.h" #include "dsCBCResults.h" #include "dcCalibrationData.h" #include " gCellAlgorithm.h" class mcCBCAlgorithm : public mgCellAlgorithm { public: mcCBCAlgorithm(const diSpecimenType& spectype, const dsWBCMeas& wbc, const dsRBCMeas& rbc, const dsPLTiMeas& plti, const dsPLToMeasfc plto, const dsHGBMeas& hgbr, const dsHGBMeas& hgbs, dsCBCResults& cbcrslt, const dcCalibrationData& cal, int dotiming = 0, 286 287 int priority = 0); // Constructor for the class. // Parameters: // spectype - specimen type for the run // wbc - WBC optical transducer measurement data // rbc - RBC impedance transducer measurement data // plti - PLT impedance transducer measurement data // plto - PLT optical transducer measurement data // hgbr - HGB absorbance transducer measurement data (reference) // hgbs - HGB absorbance transducer measurement data (sample) // cbcrslt - entire set of CBC results, including numerical, alert, // scattergram, and histogram data // cal - Dilution and calibration factors // dotiming - sets "timeflag" to TRUE or FALSE, which determines whether // timing values will be recorded (default is FALSE) . // priority - used to set the LynxOS priority for the thread containing // the algorithm operations (default is 0, normal priority) . virtual -mcCBCAlgorithm() ; // Destructor for the class -- default action only. virtual Boolean CalcResults(void) ; // Calculates the entire set of CBC test results from the CBC transducer // measurements. The numerical, alert, and graphical results produced // include all of the CBC-specific results, which are specified in 287 288 // separate files. Returns whether the algorithms completed successfully. virtual double GetTiming(int) { return (0.0) ; } // Returns the results (in seconds) of the run time for the specified // section of a specific algorithm. // Each algorithm is responsible for setting up an array of timing // values appropriate to its own architecture, and providing the // functions to put the proper timing values into this array. // Calling this function for "mcCBCAlgorithm" has no meaning (returns 0) . Boolean CalcFlag(void) { return (calcflag) ; } // Returns the value of "calcflag", indicating whether a full set of // algorithm calculations should be performed. private: const diSpecimenTypeSc specimentype; const dsWBCMeas& wbcmeas; const dsRBCMeas& rbcmeas; const dsPLTiMeas& pltimeas; const dsPLToMeas& pltomeas; const dsHGBMeas& hgbrmeas; const dsHGBMeas& hgbsmeas; 288 289 dsCBCResultsδ cbcresults; const dcCalibrationDatak caldata; Boolean calcflag; void SendRawSummary(void) ; // Sends the raw summary data for all measurements to dsCBCResults. mcCBCAlgorithm(const mcCBCAlgorithm&) ; // Null copy constructor -- no copies allowed. mcCBCAlgorithm& operator= (const mcCBCAlgorithmfc) ; // Null assignment operator -- no assignment allowed. }; #endif // _mcCBCAlgorithm_ ** * ♦ Copyright 1993 by Abbott Laboratories ♦ Source Code Control System keywords * * NAME: $Source: /home/larar/printme/RCS/mcPLTAlgorithm.cc,v $ * $Locker: larar $ * SState: Exp $ * $Revision: 2.28 $ ♦ $Author: larar $ $Date: 94/11/30 14:59:17 $ ♦ Log: .. See below * * LANGUAGE: LynxOS Cl C++ 289 290 ♦ DESCRIPTION: ♦ This file contains the implementation for the algorithms ♦ used to perform the PLT differential part of the CBC. * ♦ ....$Log: mcPLTAlgorithm.ee,v $ ♦ Revision 2.28 94/11/30 14:59:17 larar ♦ SCR #515: ♦ Changed plateletcrit calculation to use optical instead of impedance ♦ concentration. Moved plateletcrit calculation and flagging to optical ♦ arena. * ♦ Revision 2.27 94/11/30 12:29:35 larar ♦ SCR #513: ♦ Added flow/time diagnostic flags. * ♦ Revision 2.26 94/11/29 10:43:54 larar ♦ SCR #511: ♦ Added CalcPLTiConc and CalcPLTDist to replace CalcPLTiParams. Changed ♦ some return types from Boolean to void in cases where Boolean return ♦ was inappropriate or not used. Removed memory leak in CalcResults. * ♦ Revision 2.25 94/11/21 11:59:07 larar ♦ SCR508: ♦ Add valley finds to BinCut in order to handle SRP doublets and triplets. ♦ SCR509: ♦ Add arguments to Filter64Bin for optional filtering with reflection and * zeroing of left end to reduce artifacts. 290 291 * Revision 2.24 94/11/17 17:12:37 larar * SCR #505: * Add calculation of IAS/PSS statistics to CalcPLToParams. Complete * sending of all platelet numerical results and status in SendNumResults. * Implement overrange check on reported parameters. * ♦ Revision 2.23 94/11/17 10:54:12 larar * SCR443: * Changes to SetPLTiFlags, SetPLToFlags and SendAlertResults to accommodate * new flags. * ♦ Revision 2.22 94/11/11 09:59:51 larar ♦ SCR #495: ♦ Add validity check for leftmost peak to PLToFindUpperPopulation. ♦ Revision 2.21 94/11/01 10:48:56 larar ♦ SCR #467: ♦ Added additional check of specimen type in MakeDisplayHist ( ) and ♦ SendScatResults () . * ♦ Revision 2.20 94/10/28 13:06:44 larar ♦ SCR #413: ♦ Added clip to max display of unsealed histograms in MakeDisplayHist 0. * ♦ Revision 2.19 94/10/26 15:16:25 larar ♦ SCR #444: ♦ Changed test of background to test of 'calcflag' in DoAlgorithm( ) in 291 292 ♦ order to accomodate fix in mcCBCAlgorithm. * ♦ Revision 2.18 94/10/26 11:41:59 larar ♦ SCR #444: ♦ Added default regression band gate, spacing in PLToRegressBandGate( ) . * ♦ Revision 2.17 94/10/26 08:05:49 larar ♦ SCR #430: ♦ SCR #435: ♦ Put in test for background specimen in DoAlgorithm() . * ♦ Revision 2.16 94/10/25 13:31:32 larar ♦ SCR #430: ♦ SCR #435: ♦ Added DoPLTiSparse ( ) and DoPLToSparse () to process low count and ♦ background samples. ♦ Expanded arguments of MakeDisplayHist 0. ♦ SCR #300: ♦ Removed more extraneous globals from argument lists. * ♦ Revision 2.15 94/10/19 15:55:09 larar ♦ SCR #393: ♦ Changed discriminant handling in SendScatResults to reflect new ♦ dsScattergramData interface for release 2-13. * ♦ Revision 2.14 94/10/18 12:52:21 larar ♦ SCR #393: ♦ Added optical platelet discriminant processing to PLToNoiseGate ( ) , ♦ PLToRegressBandGate() , PLToFindUpperPopulation() and SendScatResults () . * SCR #413: 292 293 ♦ Replaced BinCut ( ) filtering with call to Filter64Bin( ) . * ♦ Revision 2.13 94/10/14 11:08:25 larar ♦ SCR #413: ♦ Replaced local scaling with mgCellAlgorithm: :ScaleDisplayHist () in ♦ MakeDisplayHist ( ) . * ♦ Revision 2.12 94/10/13 14:30:09 larar * SCR #335: ♦ Update constructor arguments and parameter equations for new ♦ dcCalibrationData interface. * * Revision 2.11 94/10/13 12:32:07 larar ♦ SCR #361: ♦ Added checks of optical platelet regression line slope and intercept ♦ in DoPLToAnalysis and PLToRegressBandGate. ♦ ♦ Revision 2.10 94/10/12 16:54:29 larar ♦ SCR #361: ♦ Improved logic of PLToFindUpperPopulation. ♦ Added method Filter64Bin to severely filter very noisy data. * ♦ Revision 2.9 94/09/30 ' 12:37:03 larar ♦ SCR #370: ♦ Replaced NoData status with NoCalc. ♦ SCR #361: ♦ Fixed logic error in PLToFindUpperPopulation. * ♦ Revision 2.8 94/09/28 13:30:20 larar ♦ SCR #360: * Replaced explicit code with calls to new mgCellAlgorithm 293 294 methods * ReduceResolution and Interpolate in impedance platelet processing. ♦ SCR #361: ♦ Replaced curve fitting with a bin thresholding algorithm in optical * platelet processing. * * Revision 2.7 94/09/27 17:53:48 larar * SCR #300: ♦ Fixed array index error in assignment of measurement timing array, * optical platelets. * * Revision 2.6 94/09/26 14:21:05 larar * SCR #300: * ml47 R4. Removed globals from argument lists. * ♦ Revision 2.5 94/09/23 08:20:42 larar * SCR #300: ♦ Removed extraneous globals and reorganized status markers. * Added method CalcPLTiShapeParams to calculate MPV and PDW using * lognormal regression. ♦ ♦ Revision 2.4 94/09/14 08:32:43 larar ♦ SCR #300: ♦ Fixed out-of-index error in MakeDisplayHist. ♦ SCR #332: ♦ Added internal logs of uncalibrated results to SendNumResults. * * Revision 2.3 94/09/09 14:27:20 larar ♦ SCR #312: ♦ Removed 4-to-3 decade optical platelet scaling from 294 295 SendScatResults. * ♦ Revision 2.2 94/09/09 10:10:23 larar ♦ SCR #303: ♦ Changes to accommodate addition of gated/ungated switch in ♦ mgCellAlgorithm: :Concentration. * ♦ Revision 2.1 94/09/08 08:03:04 larar ♦ SCR #300: * Removed curve fitting from impedance platelet algorithm, added method ♦ BinCut and made appropriate changes to CalcPLTiParams. ♦ SCR #303: ♦ Changed arguments for mgCellAlgorithm: Concentration. ♦ SCR #309: ♦ Added usage of mgCellAlgorithm: :GenericFilter for impedance platelet ♦ display and processing. ♦ SCR #321: ♦ Transfered usage of calibration and dilution factors from impedance ♦ platelet calculation to optical platelet calculation. * ♦ Revision 2.0 94/08/19 15:23:12 larar ♦ SCR #252: ♦ Code redesigned for greater modularity. * ♦ Revision 1.32 1994/07/22 12:13:27 larar ♦ SCR #225: ♦ Added calibration and dilution factors to constructor arguments. * ♦ Revision 1.31 94/07/22 10:36:20 larar ♦ SCR #118: ♦ Changes made after redesign review. 295 296 ♦ Removed maxplticells, maxpltocells, muchoPLTiCells, muchoPLToCells. * ♦ Revision 1.30 94/07/21 16:23:17 larar * SCR #118: ♦ Changes made after redesign review. ♦ Included mgConvergMet.h to access ReportStats structure. ♦ Converted nonlinear least squares fitting arguments to ReportStats * structure elements in DoPLTiAnalysis and DoPLToAnalysis. * ♦ Revision 1.29 94/07/20 14:00:02 larar ♦ SCR #239: ♦ Fix memory leak involving temporary array used in filtering of PLT ♦ impedance histogram. * ♦ Revision 1.28 94/07/20 08:44:09 larar ♦ SCR #219: ♦ Put explicit casts on several variables written to InternalLog in order ♦ to silence new compiler warnings. ♦ SCR #239: ♦ Fixed histogram resolution at mgMaxImpedMeas / rbchistsize. * ♦ Revision 1.27 94/07/18 17:59:00 larar ♦ SCR #204: ♦ In SendScatResults () , changed population names to match enums in ♦ dsCellPopulation.h. ♦ SCR #222: ♦ Built file ID into binary using RCSid. * ♦ Revision 1.26 94/07/07 14:53:34 larar 296 297 ♦ SCR #118: ♦ Added processing of arrays of fitted lineshapes to CalcResults() , ♦ DoPLTiAnalysis () and DoPLToAnalysis() . ♦ Revision 1.25 94/06/28 17:14:04 larar ♦ SCR #204: ♦ Changed algorithms to use new mcPLTiListMode and cPLToListMode classes ♦ (formerly used mcPLTiCell and mcPLToCell) . * ♦ Revision 1.24 94/06/27 13:45:08 larar ♦ SCR #194: ♦ Ongoing debugging of sparse data handling. ♦ Fixed unmatched new/delete in DoPLToAnalysis, which occurs in event of no ♦ data. ♦ Fixed casts in display histograms. ♦ SCR #208: * Replaced the hardware counts used in the calculations and storage with ♦ dsCountData.FinalCount() and dsCountData.FinalGatedCoun () . * ♦ Revision 1.23.1.2 94/06/22 08:40:05 larar ♦ SCR #194: ♦ Fixed unmatched new/delete in DoPLToAnalysis, which occurs in event of ♦ no data. * ♦ Revision 1.23.1.1 1994/06/20 23:05:12 larar ♦ SCR #194: ♦ Ongoing debugging of sparse data handling. Fixed casts in display * histograms. 297 298 ♦ Revision 1.23 94/06/17 09:01:29 larar ♦ SCR #194: ♦ DoPLTAnalysis: Fixed possible index error in creation of display ♦ histogram (impedance data) under circumstances of zero data. * ♦ Revision 1.22 94/06/16 16:59:35 larar ♦ SCR #194: ♦ Added forgotten SCR number to previous version. ♦ Added more flagging to optical platelet section. ♦ Added more InternalLog messages. * ♦ Revision 1.21 1994/06/15 22:48:26 larar ♦ SCR #194: ♦ Added flags for abundant and absent data and reorganized flagging and ♦ status structures. * ♦ Revision 1.20 94/06/14 12:16:56 larar ♦ SCR #185: ♦ Added low pass filtering of impedance PLT display histogram. Quartic ♦ filter, cutoff = 0.15 ♦ Nyquist. ♦ SCR #188: ♦ Used dsPLTiHist.MaxCount to scale impedance PLT display histogram. ♦ SCR #191: * Added cieling for the number of mcPLTiCell and mcPLToCell instances read ♦ from listmode. * ♦ Revision 1.19 1994/06/09 00:24:29 larar ♦ SCR #172: 298 299 ♦ Rescaled result histograms to point resolution of 256; max = 255. * ♦ Revision 1.18 1994/06/07 22:08:39 larar ♦ SCR #171: ♦ Added explicit divisor checks to all expressions with divides. ♦ Removed conditional sends of results and made them automatic. * ♦ Revision 1.17 1994/06/07 00:24:08 larar ♦ SCR #170: ♦ Added check for zero peak in histogram, DoPLTiAnalysis ( ) . ♦ Revision 1.16 1994/06/02 14:32:10 larar ♦ Permitted stuffing of histogram results for sparse data. ♦ Revision 1.15 1994/06/02 20:05:33 larar ♦ Added checks for return value of mmHist256.Peak() * ♦ Revision 1.14 1994/05/31 18:55:29 larar ♦ SCR #156: ♦ Added dtlnternalLog messages. * Revision 1.13 1994/05/25 21:16:20 larar ♦ Fixed deletes again. * ♦ Revision 1.12 1994/05/25 13:42:21 larar ♦ Removed 'deletes' in CalcResults which could cause memory leaks. * ♦ Revision 1.11 1994/05/24 00:40:16 larar ♦ Histogram scaling fixes. ♦ Added measurement timing checks. 299 300 ♦ Revision 1.10 1994/05/19 15:22:52 larar ♦ SCR #145: ♦ Changed some arguments and casts to suppress warnings, * ♦ Revision 1.9 1994/05/12 20:00:22 larar ♦ Removed includes of dsNumericalResultlD.h and dsAlertResultlD.h in ♦ accordance with SCR 136. * ♦ Revision 1.7 1994/05/12 18:23:41 larar ♦ Split SetFlags into SetPLTiFlags and SetPLToFlags. ♦ Added status and morphology flags. ♦ Added status processing. * * Revision 1.6 1994/05/05 20:49:34 larar ♦ Changed IDs to match DSOS T3 code. ♦ MT3 label. * ♦ Revision 1.4 94/04/08 20:31:31 larar ♦ Post-inspection changes. ♦ Removed SendHistResults ( ) , GetPLTiData( ) . ♦ Added dynamic allocation for data. ♦ Reorganized flagging protocol. ♦ Replaced initial data checks. ♦ Revision 1.3 94/03/25 15:08:28 larar Fleshed out pseudocode. Revision 1.2 94/03/14 08:03:20 larar No significant changes. Revision 1.1 94/03/11 09:58:56 larar Initial revision // Revision 1.1 1994/03/11 17:26:36 larar 300 301 // Initial revision // 7 #include <rw/lsqfit.h> // Rogue Wave Math.h++ #include "mcPLTAlgorithm.h" #include "mmHist256.h" #include "mmScatter.h" #include "dtlnternalLog.h" #include "mgConvergMet.h" #include "mgPoint.h" // Internal diagnostics. static const char^ const RCSid = "$Header: mcPLTAlgorithm.ccv 2.28 94/11/30 14:59:17 larar Locked $"; static const char ♦ SourceFileName = FILE ; //#define TIMEDIAG // If defined, timing info written to 'plttimes.txt'. //#define SPOTDIAG // If defined, writes nonspecific info to 'pltspot.txt'. //#define PLTOCHANGE // Sensitivity/specificity improvement for optical platelet algorithm. //#define SCR509 mcPLTAlgorithm: :mcPLTAlgorithm (const diSpecimenTypefc spectype, 301 302 const dsPLTiMeas& plti, const dsPLToMeas& plto, dsCBCResults& cbcrslt, const dcCalibrationData& cal, int docalc, int dotiming, int priority) : specimentype (spectype! plti eas (plti) , pltomeas (plto) , cbcresults (cbcrslt), caldata(cal) , calcflag (docalc) // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) << "Top of mcPLTAlgorithm constructor. « Flush; if (calcflag == FALSE) { ilog « Line( LINE ) « "Constructor. ' calcflag FALSE " « Flush; } ilog « Line( LINE ) « "Constructor, specimen type " « specimentype.Type() « Flush; SetTimeFlag ( (Boolean)dotiming) ; 302 303 SetPriority (priority) ; } / /= mcPLTAlgorithm: :-mcPLTAlgorithm ( ) { } Boolean mcPLTAlgorithm: :CalcResults(void) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of CalcResults." « Flush; // Clock items. long startclock, endclock, startclock2, endclock2; startclock = clockO; // Utility variables. unsigned long i; Boolean gotInput = FALSE; // Indicates whether various 303 304 major Boolean didAlgo = FALSE; // sections were completed. Boolean sentRes = FALSE; // Initializations. // Initialize timing, ford = 0; i < maxalgsection; i++) { timevalues[i] = 0.0; } // Get input. startclock2 = clockO; Getlnput() ; endclock2 = clockO; timevalues[getlnput] = (double) (endclock2 - startclock2) / clockMil; gotInput = TRUE; // Do algorithm. startclock2 = clockO; DoAlgorithmO ; endclock2 = clock() ; timevalues[doAlgorithm] = (double) (endclock2 startclock2) / clockMil; didAlgo = TRUE; // Send results. 304 305 startclock2 = clockO; SendResults() ; endclock2 = clockO; timevalues[sendResults] = (double) (endclock2 startclock2) / clockMil; sentRes = TRUE; // Clean up. delete pltiLItem; delete [] pltiVolArray; delete [] . pltiTimeArray; delete pltoLltem; ilog « Line( LINE ) « "CalcResults. End. « Flush; // End clock. endclock = clockO; timevalues[CalcResults] = (double) (endclock - startclock) / clockMil; // Diagnostics. #ifdef TIMEDIAG FILE* diag = fopen("plttimes.txt", "a") ; fprintf(diag, "Getlnput %6.3f\t", timevalues [getlnput] ) ; 305 306 fprintf (diag, "ParamDefaults %6.3f\t", timevalues [paramDefaults] ) ; fprintf (diag, "ClassFlagDefaults %6.3f\t", timevalues [ClassFlagDefaults] ) ; fprintf (diag, "GetPLTiData %6.3f\t", timevalues [getPLTiData] ) ; fprintf (diag, "GetPLToData %6.3f\t", timevalues [getPLToData] ) ; fprintf (diag, "DoAlgorithm %6.3f\t", timevalues [doAlgorithm] ) ; fprintf (diag, "DoPLTiSparse %6.3f\t", timevalues [doPLTiSparse] ) ; fprintf(diag, "DoPLTiAnalysis %6.3f\t", timevalues [doPLTiAnalysis] ) ; fprintf (diag, "DoPLTiAnalysis_hist %6.3f\t", timevalues [doPLTiAnalysis_hist] ) ; fprintf (diag, "PLTiProcessNumbers %6.3f\t", timevalues [pltiProcessNumbers] ) ; fprintf (diag, "SetPLTiFlags %6.3f\t", timevalues [SetPLTiFlags]); fprintf (diag, "DoPLToSparse %6.3f\t", timevalues[doPLToSp arse] ) ; fprintf(diag, "DoPLToAnalysis %6.3f\t", 306 307 timevalues [doPLToAnalysis] ) ; fprintf(diag, "PLToNoiseGate %6.3f\t", timevalues [pltoNoiseGate] ) ; fprintf(diag, "PLToRegressBandGate %6.3f\t", timevalues [pltoRegressBandGate] ) ; fprintf(diag, "PLToRegressBandGate_lsf %6.3f\t", timevalues [pltoRegressBandGate_lsf] ) ; fprintf(diag, "PLToRegressBandGate_count %6.3f\t", timevalues [pltoRegressBandGate_count] ) ; fprintf(diag, "PLToRegressBandGate_tag %6.3f\t", timevalues[pltoRegressBandGate_tag] ) ; fprintf(diag, "PLToFindUpperPopulation %6.3f\t", timevalues[pltoFindUpperPopulation] ) ; fprintf(diag, "PLToFindUpper_proj %6.3f\t", timevalues[pltoFindUpper_proj] ) ; fprintf(diag, "PLToFindUpper_filter %6.3f\t", timevalues [pltoFindUpper_filter] ) ; fprintf(diag, "PLToFindUpper_char %6.3f\t", timevalues [pltoFindUpper_char] ) ; fprintf(diag, "CalcPLToParams %6.3f\t", 307 308 timevalues [CalcPLToParams] ) ; fprintf (diag, "SetPLToFlags %6.3f\t" , timevalues[setPLToF lags] ) ; fprintf (diag, "SendResults %6.3f\t" , timevalues[sendResults] ) ; fprintf (diag, "SendNumResults %6.3f\t" , timevalues [SendNumResults] ) ; fprintf (diag, "SendAlertResults %6.3f\t" , timevalues [SendAlertResults] ) ; fprintf(diag, "MakeDisplayHist %6.3f\t", timevalues [makeDisplayHist]); fprintf(diag, "SendScatResults %6.3f\n" , timevalues [SendScatResults] ) ; fclose(diag) ; #endif return(gotInput && didAlgo && sentRes); } / /============================================================ double mcPLTAlgorithm: :GetTiming(int section) { 308 309 // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog << Line ( LINE ) « "Top of GetTiming." « Flush; if (section < maxalgsection) { return(timevalues[section] ) ; } else return(0.0); } void mcPLTAlgorithm: :Getlnput (void) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of Getlnput." « Flush; // Clock items. long startclock, endclock; // Initialize parameters, status, impedance display histogram, and 309 310 // display scattergram. startclock = clockO ; ParamDefaults ( ) ; endclock = clockO; timevalues[paramDefaults] = (double) (endclock - startclock) / clockMil; // Initialize class-specific flags. startclock = clockO; ClassFlagDefaults ( ) ; endclock = clockO; timevalues[ClassFlagDefaults] = (double) (endclock - startclock) / clockMil; // Get PLTi list mode data and check initial conditions. startclock = clockO; GetPLTiData() ; endclock = clockO; timevalues[getPLTiData] = (double) (endclock - startclock) / clockMil; // Get PLTo list mode data and check initial conditions. startclock = clockO; GetPLToData() ; endclock = clockO; timevalues [getPLToData] = (double) (endclock - 310 311 startclock) / clockMil; } void mcPLTAlgorithm: :DoAlgorithm(void) { dtlnternalLog ilog(SourceFileName) ; ilog << Line ( LINE ) << "Top of DoAlgorithm. " << Flush; // Clock items, double startclock, endclock; // Method flags. Boolean pltialgstat, pltoalgstat; // impedance platelet algorithm. startclock = clockO; pltialgstat = DoPLTiAnalysis 0 ; endclock = clockO; timevalues[doPLTiAnalysis] = (double) (endclock startclock) / clockMil; // Optical platelet algorithm. 311 312 startclock = clockO; pltoalgstat = DoPLToAnalysis () ; endclock = cloc O; timevalues[doPLToAnalysis] = (double) (endclock startclock) / clockMil; } void mcPLTAlgorithm: :SendResults(void) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of SendResults." « Flush; // Clock items. long startclock, endclock; // Send the numerical results to storage. startclock = clock( SendNumResults() ; endclock = clockO; 312 313 timevalues [SendNumResults] = (double) (endclock startclock) / clockMil; // Send the alert results to storage. startclock = clockO; SendAlertResults () ; endclock = clockO; timevalues [SendAlertResults] = (double) (endclock - startclock) / clockMil; // Send display histogram. double resol; unsigned short pltihistsize = cbcresults.PLTiHist ( ) .Size 0 ; if (pltihistsize > 0) resol = mgMaxImpedMeas / pltihistsize; else resol = 1; mmHist256 displayHist (pltiVolArray, pltimeas.List ( ) .NumberCells ( ) , resol) ; if ( (noPLTiCells == FALSE) I I (calcflag == FALSE)) { . startclock = clockO; MakeDisplayHist (displayHist, TRUE, TRUE); 313 314 endclock = clockO; timevalues[makeDisplayHist] = (double) (endclock startclock) / clockMil; } else { startclock = clockO; MakeDisplayHist (displayHist, FALSE, FALSE) ; endclock = clockO; timevalues[makeDisplayHist] = (double) (endclock startclock) / clockMil; } // Send the scattergram results to storage. startclock = clockO; SendScatResults ( ) ; endclock = clockO; timevalues[SendScatResults] = (double) (endclock startclock) / clockMil; } / /===================================================: void mcPLTAlgorithm: :ParamDefaults (void) { dtlnternalLog ilog(SourceFileName) ; 314 315 ilog << Line ( LINE ) « "Top of ParamDefaults." << Flush; // Initialize parameters to zero. pLT = 0.0 mPV = 0.0 pDW = 0.0 pCT = 0.0; OPLT = 0.0; iasMean = 0.0; pssMean = 0.0; iasCv = 0.0; pssCv = 0.0; // Initialize status to NoCalc pltStat = dsNumericalResult: :NoCalc; mpvStat = dsNumericalResult: :NoCalc; pdwStat = dsNumericalResult: :NoCalc; pctStat = dsNumericalResult: :NoCalc; opltStat = dsNumericalResult::NoCalc; iasMeanStat = dsNumericalResult::NoCalc; pssMeanStat = dsNumericalResult: :NoCalc; iasCvStat = dsNumericalResult::NoCalc; pssCvStat = dsNumericalResult::NoCalc; // Initialize display histogram. unsigned short i; ford = 0; i < cbcresults.PLTiHist 0.Size 0 ; i++! 315 316 cbcresults.PLTiHist 0 [i] = (dsHistCount) 0; void mcPLTAlgorithm: :ClassFlagDefaults (void) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of ClassFlagDefaults." « Flush; // Set flags. pltiupper = FALSE; pltilower = FALSE; pltoupper = FALSE; pltolower = FALSE; noPLTiCells = FALSE; noPLToCells = FALSE; pltiEvenTiming = FALSE; pltoEvenTiming = FALSE; pdwHiFlag = FALSE; mcPLToMiRBC = FALSE; } void mcPLTAlgorithm: :GetPLTiData (void) 316 317 dtlnternalLog ilog(SourceFileName) ; ilog « Line ( LINE ) « "Top of GetPLTiData." << Flush; // Set up listmode data arrays pltiVolArray = new dsListModeMeas [1] ; pltiTimeArray = new dsListModeMeas [1] ; // Get listmode items, pltiLItem = new mcPLTiListMode (pltimeas.List () ); // Listmode object. pltiLItem->Resolution(dsPLTiListMode: :VOL, 0) ; // Set up zero //bit shift. pltiLItem->Resolution(dsPLTiListMode: :TIME,0) ; // Check number of cells and flag if too low. if (pltimeas.List 0.NumberCells 0 < minAllowPLTCount) { noPLTiCells = TRUE; } // Get listmode data and store. 317 318 unsigned long il; if (pltimeas.List () .NumberCells ( ) >= minAllowPLTCount) { delete [] pltiVolArray; delete [] pltiTimeArray; pltiVolArray = new dsListModeMeas[pltimeas.List () .NumberCells 0 ] ; pltiTimeArray = new dsListModeMeas[pltimeas.List ( ) .NumberCells () - 1]; for (il = 0; il < pltimeas.List 0.NumberCells0 ; il++) { pltiVolArray[il] = pltiLItem->CellMeas (il, dsPLTiListMode: :VOL) ; } fordl = 1; il < pltimeas.List0.NumberCells 0 ; il++) { pltiTimeArray[il - 1] = pltiLItem- >CellMeas (il, dsPLTiListMode: :TIME) - pltiLItem- >CellMeas(il - 1, dsPLTiListMode: :TIME) ; } // Internal logs, 318 319 ilog << Line( LINE ) << "GetPLTiData. Dilution " << pltimeas.Count ( ) .Dilution( ) « Flush; ilog « Line ( LINE ) « "GetPLTiData. Flow rate " « pltimeas.Count ( ) .FlowRate( ) « Flush; ilog « Line( LINE ) « "GetPLTiData. Meas time " « pltimeas.Count ( ) .FinalTime ( ) « Flush; ilog « Line ( LINE ) « "GetPLTiData. Hardware events " « pltimeas.Count ( ) .FinalCount ( ) « Flush; ilog « Line ( LINE ) « "GetPLTiData. # listmodes " « pltimeas.List O .NumberCells 0 « Flush; } / /================================================ ======= void mcPLTAlgorithm: :GetPLToData(void) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) 319 320 << "Top of GetPLToData. " << Flush; // Set up listmode data arrays pltoPssArray = new dsListModeMeas [1] ; pltoIasArray = new dsListModeMeas[1] ; pltoTimeArray = new dsListModeMeas [1] ; // Get listmode items. pltoPltCount = pltomeas.List 0.NumberCells 0 ; pltoLItem = new mcPLToListMode (pltomeas.List ()); // Listmode object. pltoLItem->Resolution(dsPLToListMode: :PSS, 0); // No bit shift. pltoLItem->Resolution(dsPLToListMode: :IAS, 0); // No bit shift. pltoLItem->Resolution(dsPLToListMode: :TIME, 0); //No bit shift. // Check number of cells and flag if too low. if (pltomeas.List 0.NumberCells ( ) < minAllowPLTCount) { noPLToCells = TRUE; opltStat = dsNumericalResult: :NoCalc; pctStat = dsNumericalResult:: oCalc; } // Get listmode data and store. 320 321 // Set default population to 'platelet' . unsigned il; if (pltomeas.List 0.NumberCells 0 >= minAllowPLTCount) { delete [] pltoPssArray; delete [] pltoIasArray; delete [] pltoTimeArray; pltoPssArray = new dsListModeMeas [pltomeas.List ( ) .NumberCells ( ) ] ; pltoIasArray = new dsListModeMeas[pltomeas.List ( ) .NumberCells 0 ] ; pltoTimeArray = new dsListModeMeas [pltomeas.List 0.NumberCells 0 - 1] ; for (il = 0; il < pltomeas.List 0.NumberCells 0 ; il++) { pltoPssArray[il] = pltoLItem->CellMeas (il, dsPLToListMode: :PSS) ; pltoIasArray[il] = pltoLItem->CellMeas (il, dsPLToListMode: :IAS) ; pltoLItem->CellPopulation(dsPLToPLT, il) ; } fordl = 1; il < pltomeas.List 0.NumberCells 0 ; il++) { pltoTimeArray[il - 1] = pltoLItem- >CellMeas(il, dsPLToListMode: :TIME) - pltoLItem- >CellMeas(il - 1, 321 322 dsPLToListMode: :TIME) ; } // Internal logs ilog « Line( LINE ) « "GetPLToData. Dilution " « pitomeas.Count0.Dilution() « Flush; ilog « Line( LINE ) « "GetPLToData. Flow rate " « pltomeas.Count () .FlowRate() « Flush; ilog « Line( LINE ) « "GetPLToData. Meas time " « pltomeas.Count () .FinalTime() « Flush; ilog « Line( LINE ) « "GetPLToData. Hardware events " « pitomeas.CountO . FinalGatedCount() « Flush; } / /================================================ void mcPLTAlgorithm: :DoPLTiSparse(void) { dtlnternalLog ilog(SourceFileName) ; 322 323 ilog « Line( LINE ) « "Top of DoPLTiSparse." « Flush; // Set threshold values to defaults. pltiLoThresh = 0; pltiHiThresh = 255; // Report concentration based on entire listmode. Boolean concFlag = TRUE; if ( (pltimeas.Count() .FlowRate() > 0.0) && (pltimeas.Count0.DilutionO > 0.0) S S (pltimeas.Count0.FinalTime0 > 0.0) ) concFlag = Concentration(FINAL, pltomeas.Count () , pLT, pltStat, 1, (double)0.001, 1.0, 1.0); if ( (pLT < pltRangeLo) I I (pLT > pltRangeHi) ) pltStat = dsNumericalResult: :OverRange; ilog « Line( LINE ) « "DoPLTiSparse. pLT " « pLT « Flush; } 323 324 // Compose alerts. SetPLTiFlags(TRUE) ; void mcPLTAlgorithm: :DoPLToSparse(void) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of DoPLToSparse." « Flush; // Calculate optical platelet concentration. CalcPLToParams (1.0) ; // Compose alerts. SetPLToFlags(TRUE) ; Boolean mcPLTAlgorithm: :DoPLTiAnalysis(void) { // Internal diagnostics. 324 325 dtlnternalLog ilog(SourceFileName) ; ilog << Line ( LINE ) « "Top of DoPLTiAnalysis." << Flush; // Clock items. long startclock, endclock; // Local flags. Boolean pltiDatFlag = TRUE; // Flag for validity of input data. // TRUE if input data OK. Boolean pltiAlgFlag = TRUE; // Flag for validity of algorithm. // TRUE if processing OK. // Declare histograms, startclock = clockO; unsigned long pltihistsize = cbcresults.PLTiHist ( ) .Size 0 ; double resol; if (pltihistsize > 0) resol = mgMaxImpedMeas / pltihistsize; else resol = 1; 325 326 mmHist256 calcHist (pltiVolArray, // Histogram for calculations. pltimeas.List ( ) .NumberCells ( ) , resol) ; endclock = clockO; timevalues[pltiProcessNumbers] = (double) (endclock - startclock) / clockMil; // Get numerical results and alerts. startclock = clockO; pltiAlgFlag = PLTiProcessNumbers (calcHist) ; endclock = clockO; timevalues [pltiProcessNumbers] = (double) (endclock - startclock) / clockMil; // Compose alerts. startclock = clockO; SetPLTiFlags (pltiAlgFlag) ; endclock = clockO; timevalues[setPLTiFlags] = (double) (endclock startclock) / clockMil; ilog « Line( LINE ) « "DoPLTiAnalysis. End." « Flush; return (pltiAlgFlag && pltiDatFlag) ; } 326 327 Boolean mcPLTAlgorithm: :DoPLToAnalysis(void) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of DoPLToAnalysis." << Flush; // Clock items, long startclock, endclock; // Utility variables. Boolean pltoDatFlag = ! (noPLToCells) ; // Flag for validity of input data. // TRUE if input data OK. Boolean pltoAlgFlag = TRUE; // Flag for validity of algorithm. // TRUE if processing OK. Boolean flagstat = TRUE; // Flag for flagging. // Set up objects and variables for calculation. 327 328 PLToLinRegress = new mgLine(l,l); // Dummy regression line through // cluster. // Initialize all points to 'platelet'. unsigned long il; for(il = 0; il < pltomeas.List0.NumberCells0 ; il++) { pltoLItem->CellPopulation(dsPLToPLT,il) ; } // Check timing. if ( (specimentype.Type0 == diSpecimenType: :PatientSpecimen) II (specimentype.Type() == diSpecimenType: :QCSpecimen) ) { pltoEvenTiming = FlowTimeDiag(pltomeas.Count0 ) ; ilog « Line( LINE ) « "DoPLToAnalysis. pltoEvenTiming " « pitoEvenTiming « Flush; } double proportion = 1.0; // Proportion of surviving platelet // which does not fall into an upper // population. 328 329 if ( ( (specimentype.Type ( ) == diSpecimenType: :PatientSpecimen) I I (specimentype.Type ( ) == diSpecimenType: :QCSpecimen) ) && (noPLToCells == FALSE) && (calcflag == TRUE) ) { // Apply electronic noise gate. startclock = clockO; PLToNoiseGate( ) ; endclock = clockO; timevalues[pltoNoiseGate] = (double) (endclock - startclock) / clockMil; // Apply regression band gate. startclock = clockO ; PLToRegressBandGate ( ) ; endclock = clockO; timevalues[pltoRegressBandGate] = (double) (endclock - startclock) / clockMil; // Search for and gate upper population. if ( (PLToLinRegress->Slope 0 > 0) £c& (PLToLinRegress->Intercept 0 > 0)) 329 330 { startclock = clock0 ,- pltoAlgFlag = PLToFindUpperPopulation(&proportion) ; endclock = clockO; timevalues[pltoFindUpperPopulation] = (double) (endclock startclock) clockMil; } } // Calculate optical platelet concentration. startclock = clockO; CalcPLToParams (proportion) ; endclock = clockO; timevalues[CalcPLToParams] = (double) (endclock startclock) / clockMil; // Calculate plateletcrit. CalcPCT() ; // Set morphology flags startclock = clockO; SetPLToFlags (pltoAlgFlag) ; endclock = clockO; 330 331 timevalues[SetPLToFlags] = (double) (endclock - startclock) / clockMil; // Clean up. delete [] pltoPssArray; delete [] pltoIasArray; delete [] pltoTimeArray; delete PLToLinRegress; ilog « Line( LINE ) « "DoPLToAnalysis. End." « Flush; return (pltoDatFlag && pltoAlgFlag && flagstat) ; } / /=========================================================== Boolean mcPLTAlgorithm: :PLTiProcessNumbers(const mmHist256& calcHist) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE_) « "Top of PLTiProcessNumbers." « Flush; // Method flags. Boolean algstat = TRUE; // Flag for validity of 331 332 algorithm // processing. Boolean datstat = ! (noPLTiCells) ; // Flag for validity of data. // Check measurement timing. if ( (specimentype.Type() == diSpecimenType: :PatientSpecimen) II (specimentype.Type0 == diSpecimenType: :QCSpecimen) ) { pltiEvenTiming = FlowTimeDiag(pltimeas.Count()) ; ilog « Line( LINE ) « "PLTiProcessNumbers. pltiEvenTiming " « pltiEvenTiming « Flush; } // Find discriminants. if ( ( (specimentype.Type() == diSpecimenType: :PatientSpecimen) II (specimentype.Type0 diSpecimenType: :QCSpecimen) ) ScSc (noPLTiCells == FALSE) ScSc (calcflag == TRUE) BinCut (calcHist! 332 333 } else { // Threshold defaults. pltiLoThresh = 0; pltiHiThresh = 255; } // Parameter calculations.- // Count-based parameters. Boolean concFlag = TRUE; // Flag for concentration calculation. if { (noPLTiCells == TRUE) I I (calcflag == FALSE) ) { concFlag = CalcPLTiConc (calcHist, 0, calcHist.HistRes - 1); } else { concFlag = CalcPLTiConc (calcHist, pltiLoThresh, pltiHiThresh) ; } if (concFlag == FALSE) { pltStat = dsNumericalResult: :Suspect; } // Distributional and derived parameters. Boolean distFlag = TRUE; // Flag for distributional 333 334 calculations. if ( ( (specimentype.Type ( ) == diSpecimenType: :PatientSpecimen) I I (specimentype.Type( ) == diSpecimenType: :QCSpecimen) ) S S (noPLTiCells == FALSE) ScSc (calcflag == TRUE) ) { // MPV, PDW. distFlag = CalcPLTDist (calcHist, pltiLoThresh, pltiHiThresh) ; if (concFlag == FALSE) { mpvStat = dsNumericalResult::Suspect; pdwStat = dsNumericalResult::Suspect; } } return(algstat) ; } / /=========================================================== ======= void mcPLTAlgorithm: :MakeDisplayHist (const mmHist256& plainHist, const Boolean doFilter, const Boolean 334 335 showDiscrim) { dtlnternalLog ilog (SourceFileName) ; ilog « Line( LINE ) << "Top of MakeDisplayHist." « Flush; // Apply severe bin-reduction filtering algorithm.-- mmHist256 localHist (plainHist) ; // Working copy of histogram. if (doFilter == TRUE) { #ifdef SCR509 Filter64Bin(plainHist, TRUE, FALSE, localHist) ; #else Filter64Bin(plainHist, FALSE, FALSE, localHist) ; #endif } // Scale and fill result histogram. // Scaling occurs if platelet concentration exceeds a threshold, // otherwise no scaling is done. unsigned short iSh; 335 336 Boolean scaleFlag = TRUE; double* scaledNums = new double [localHist.HistRes] ; double* scaledNums2 = new double [localHist.HistRes] ; for (iSh = 0; iSh < localHist.HistRes; iSh++) { scaledNums[iSh] = (double) localHist[iSh] ; } if (oPLT > pltiScaleThresh) { scaleFlag = ScaleDisplayHist(scaledNums, scaledNums2, cbcresult s.PLTiHist 0.MaxCount () , pltiLoModeSearchBin, pltiHiModeSearchBin) ; for Sh = 0; iSh < localHist.HistRes; ish++) { cbcresults.PLTiHist() [iSh] = (dsHistCount)scaledNums2 [iSh] ; } } else { ilog « Line( LINE ) « "MakeDisplayHist. No scaling done." « Flush; fordSh = 0; iSh < localHist.HistRes; iSh++) { cbcresults.PLTiHist 0 [iSh] = 336 337 (dsHistCount) (MlN(cbcresult s. PLTiHist ( ) .MaxCount ( ) , localHist [iSh] ) ) ; } } // Fill discriminants, if (showDiscrim == TRUE) { cbcresults.PLTiHis ( ) .Channel ( cbcresults.PLTiHist ( ) . owerThresh) pltiLoThresh; cbcresults.PLTiHist ( ) .Channel ( cbcresults.PLTiHist ( ) .UpperThresh) pltiHiThresh; } // Clean up. delete [] scaledNums; delete [] scaledNums2; void mcPLTAlgorithm: :SetPLTiFlags (const Boolean& algflag) { // Internal diagnostics. dtlnternalLog ilog (SourceFileName) ; 337 338 ilog << Line ( LINE ) « "Top of SetPLTiFlags." « Flush; // Transfer status if ( algflag == TRUE ) { ilog << Line ( LINE ) « "SetPLTiFlags. PLTi calculations OK." « Flush; if ( (pDW > pdwhi) S S (pdwStat == dsNumericalResult: :CalcOK) ) { pdwHiFlag = TRUE; ilog « Line( LINE ) « "SetPLTiFlags. pdwHiFlag tripped." << Flush; } if ( ( mPV > mpvhi) && (mpvStat == dsNumericalResult: :CalcOK) ) { mpvHiFlag = TRUE; ilog « Line( LINE ) << "SetPLTiFlags. mpvHiFlag tripped." « Flush; } } else if (algflag == FALSE) 338 33 9 { ilog << Line ( LINE ) « "SetPLTiFlags. PLTi calculations bad." « Flush; pltStat = dsNumericalResult::Suspect; mpvStat = dsNumericalResult::Suspect; pdwStat = dsNumericalResult::Suspect; } } / /============================================================ ======= void mcPLTAlgorithm: :PLToNoiseGate(void) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of PLToNoiseGate. " « Flush; // Tag as noise all scatter points below noise gate.-- unsigned il; for (il = 0; il < pltomeas.List O .NumberCells () ; il++) { if (pltoPssArray[il] < pssNoiseThresh * 0.01 * pltoScatSize) { pltoLItem->CellPopulation(dsPLToNoise, il) ; pltoPltCount--; pltoNoiseCount++; 339 340 } } // Set noise gate discriminant. backgroundDisc.Reset(0.0, pssNoiseThresh ♦ 0.01 pltoScatSize) ; } void mcPLTAlgorithm: :PLToRegressBandGate(void) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of PLToRegressBandGate." « Flush; ilog « Line( LINE ) « "PLToRegressBandGate. pltoPltCount " « pltoPltCount « Flush; // Clock items, long startclock, endclock; // Construct regression line.— // Use points that are PLT only. 340 341 unsigned long il; unsigned long pltCount = 0; // Create vectors to feed to least squares fit. DoubleVec pssvec ( (int)pltoPltCount, 0.0); DoubleVec iasvec ( (int)pltoPltCount, 0.0); double sumpp = 0; double sumii = 0; double sumpi = 0; double sump = 0; double sumi = 0; fordl = 0; il < pltomeas.List 0.NumberCells 0 ; il++) { if (pltoLItem->CellPopulation(il) == dsPLToPLT) { pssvec [ (int)pltCount] = (double)pltoLItem- >CellMeas ( (int) il, dsPLToListMode: :PSS) ; iasvec[ (int)pltCount] = (double)pltoLItem- >CellMeas( (int)il, dsPLToListMode: :IAS) ; sump += (double)pssvec[ (int)pltCount] ; sumi += (double) iasvec[ (int)pltCount] ; sumpp += (double) (pssvec[ (int)pltCount] * pssvec [ (int)pltCount] ) ; sumii += (double) (iasvec[ (int)pltCount] ♦ iasvec [ (int)pltCount] ) ; sumpi += (double) (pssvec[ (int)pltCount] ♦ iasvec [ (int)pltCount] ) ; pltCount++; 341 342 ilog « Line ( LINE ) << "CalcRegressBandGate. Final pltCount " « pltCount << Flush; // Regression. startclock = clockO; LeastSqFit lsf (iasvec, pssvec); endclock = clockO; timevalues[pltoRegressBandGate_lsf] = (double) (endclock - startclock) / clockMil; // Store regression line. // If the magnitude of the returned slope is greater than 100: // assume vertical line. Reset regression line to x axis (where // slope and intercept are zero) . // Negative slopes are not a concern. delete PLToLinRegress; if (lsf.sloped < 1000) { PLToLinRegress = new mgLine (lsf.slope () , lsf.intercept ( ) ) ; } else { PLToLinRegress = new mgLine0 ; // X axis. } 342 343 // Find standard error of pss. double standerr = 0.0; double sii = (pltomeas.List () .NumberCells0 * sumii) - (sumi * sumi) ; double spp = (pltomeas.List 0.NumberCells0 * sumpp) - (sump * sump) ; double spi = (pltomeas.List 0.NumberCells ( ) * sumpi) - (sump * sumi) ; if ((pltoPltCount > 2) && (sii > 0)) { standerr = ((sii ♦ spp) - (spi * spi)) / (pltoPltCount ♦ (pltoPltCount - 2) * sii) ; if (standerr >= 0) standerr = sqrt (standerr) ; else standerr = 0.0; } else standerr = 0; ilog « Line( LINE ) « "PLToRegressBandGate. Standard error " « standerr « Flush; // Change standard error to default if necessary, in order to // enclose ill-defined clusters. if (standerr > mcPLTLRStderrMax) { standerr = mcPLTLRStderrMax; 343 344 ilog << Line ( LINE ) « "PLToRegressBandGate. Defaulted standard error " << standerr « Flush; // Tag points outside gates as noise. // Do this only if regression line valid, i.e. not equal to // the X axis. double upgate; double downgate; startclock = clockO; if ( (PLToLinRegress->Slope () > 0) S S (PLToLinRegress->lntercept 0 > 0)) { for (il = 0; il < pltomeas.List () .NumberCells 0 ; il++) { upgate = lsf.yPosition( (double)pltoLItem- >CellMeas (il, dsPLToListMode: :IAS) ) + (mcPLToHiGate ♦ standerr); downgate = lsf.yPosition( (double)pltoLItem- >CellMeasdl, dsPLToListMode: :IAS) ) - (mcPLToLoGate * standerr); if (pltoLItem->CellPopulation(il) == dsPLToPLT) 344 345 { if ( (double)pltoLItem- >CellMeas (il,dsPLToListMode: :PSS) < downgate) { pltoLItem- >CellPopulation(dsPLToNoise, il) ; pltoPltCount--; pltoNoiseCount++; } if ( (double)pltoLItem- >CellMeas (il,dsPLToListMode: :PSS) > upgate) { pltoLItem- >CellPopulation(dsPLToNoise, il) ; pltoPltCount--; pltoNoiseCount++; } } } } endclock = clock( ) ; timevalues [pltoRegressBandGate_tag] = (double) (endclock - startclock) / clockMil; // Stuff discriminants (upper and lower gates) if ( (PLToLinRegress->Slope0 > 0) && (PLToLinRegress->lntercept 0 > 0)) { pltLowerDisc.Reset (PLToLinRegress->Slope 0 , 345 346 (PLToLinRegress- >Intercept ( ) - mcPLToLoGate * standerr) ) ; pitUpperDisc.Reset (PLToLinRegress->Slope 0 , (PLToLinRegress- >Intercept () + mcPLToHiGate ♦ standerr) ) ; } else { ilog « Line ( LINE ) « "PLToRegressBandGate. Bad regression line params. " << Flush; pitLowerDisc.Reset (0.0, 0.0); pitUpperDisc.Reset (0.0, 0.0); } / /= Boolean mcPLTAlgorithm: :PLToFindUpperPopulation(double^ proportion) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of PLToFindUpperPopulation. " « Flush; // Clock items. 346 347 double startclock, endclock; // Method constants. unsigned short pltoHistSize = 256; // Size of projection // histogram. // Initialize return, ♦ proportion = 1.0; // Flags. Boolean pltoAlgFlag = TRUE; // Create projection histogram. // Use only points labeled as PLT. startclock = clockO; unsigned long il; int Λ projStatus = new int [pltomeas.List () .NumberCells 0 ] ; // Tells which bin of the projection histogram a point falls into. // Regular bins: 0 to pltoHistSize. // If the point is not used in the calculation, the value is -1. // Initialize status. 347 348 for (il = 0; il < pltomeas.List 0.NumberCells () ; il++) { if (pltoLItem->CellPopulation(il) == dsPLToPLT) { projStatus[il] = 0; // Default bin is zero. } else projStatus [il] = -1; } // Create projections. double ♦ projRegress = new double [pltomeas.List ( ) .NumberCells () ] ; // Projection array. // Not all points will go into the projection histogram; // points with negative projStatus will be excluded. // Histogram is created regardless of line orientation. double tempor; dsListModeMeas minproj = 1000000; // Always nonzero. dsListModeMeas maxproj = 0; fordl = 0; il < pltomeas.List 0.NumberCells 0 ; il++) { if (pro Status [il] >= 0) { tempor = (double)pltoLItem->CellMeas (il, dsPLToListMode: :PSS) - PLToLinRegress->Intercept ( ) ; projRegress [il] = (double) 348 349 (pltoLItem- >CellMeas dl,dsPLToListMode: :IAS) ) + (PLToLinRegress->Slope ( ) * tempor) ; projRegress [il] /= sqrtd.O + (PLToLinRegress- >Slope() ♦ PLToLinRegress • >SlopeO) ); if (projRegress [il] < minproj ) minproj = (dsListModeMeas)projRegress [il] ; if (projRegress [il] > maxproj ) maxproj = (dsListModeMeas)projRegress[il] ; } else projRegress[il] = 0.0; // To prevent undefined points. } // Create histogram of type double. Build from scratch to allow // status tagging. double resol; if (maxproj > minproj) { resol = (maxpro - minproj) / (double)pltoHistSize; // Histogram resolution. } else { 349 350 resol = 1.0; // If error: allow histogram to // be built anyway and check later. } mmHist256 projHist; // Blank histogram // object. unsigned short iSh; fordl = 0; il < pltomeas.List () .NumberCells () ; il++ { projRegress[il] = projRegress[il] - minproj; if (projstatusfil] >= 0) { iSh = 0; while (( projRegress [il] > (double) (iSh * resol) ) S S ( iSh < (pltoHistSize - 2) )) iSh++; } projHist.AddCount ( (int) iSh) ; projStatus [il] = iSh; } endclock = clockO; timevalues[pltoFindUpper_proj] = (double) (endclock - startclock) / clockMil; // Find and segment upper population using projection histogram // characteristics. 350 3 51 // Smooth histogram. startclock = clockO; mmHist256 identHist (projHist) ; #ifdef PLTOCHANGE // Alternative filter double* filt = new double [10] ; fordSh = 0; iSh < 10; iSh++) { filt[iSh] = 1.0; } double^ filtRes = new double [256]; fordSh = 0; iSh < 256; iSh++) { filtRes[iSh] = (double) identHist [iSh] ; } GenericFilter(filt, filtRes, 2, 10, 256, filtRes) ; fordSh = 0; iSh < 256; iSh++) { identHist[iSh] = filtRes[iSh] ; } delete [] filt; delete [] filtRes; #else Filter64Bin(projHist, FALSE, 351 352 FALSE, identHist) ; #endif endclock = clockO; timevalues[pltoFindUpper_filter] = (double) (endclock startclock) / clockMil; // Identify peaks and valleys. startclock = clockO ; // Look for a principal peak in the first 2/3 of the histogram. int pltPeakLoc = -1; iSh = (int) (projHist.HistRes ♦ 0.66); while ( (iSh > 0) && (identHist.Peak(0, (int) iSh) < 0) ) { iSh--; } pltPeakLoc = identHist.Peak(0, (int) iSh) ; ilog « Line( LINE ) « "PLToFindUpperPopulation. pltPeakLoc " « pltPeakLoc « Flush; // Look for a second peak in the last quarter of the histogram. // Exclude last bin. int pltPeakLoc2 = -1; iSh = (int) (projHist.HistRes - 2); if (pltPeakLoc > 0) 352 353 /* while (iSh > pltPeakLoc) S Sc (identHist.Peak( (int) (projHist.HistRes * 0.75), (int)iSh) < 0) iSh--; } */ pltPeakLoc2 = identHist.Peak( (int) (projHist.HistRes 0.75) (int)iSh) ; ilog « Line( LINE ) « "PLToFindUpperPopulation. pltPeakLoc2 " « pltPeakLoc2 « Flush; // Look for the lowest point between them, starting from the // left. // Peak 2 should not be at 3/4 ♦ resolution; otherwise the peak // is false and the valley should be set at the end, indicating // no microcytic population. int projValley = projHist.HistRes - 1; if ( (pltPeakLoc < pltPeakLoc2) ScSc (pltPeakLoc > 0) ScS (pltPeakLoc2 > projHist.HistRes ♦ 0.75 + 1) ) 353 354 { int lowPoint = pltPeakLoc; fordSh = pltPeakLoc; iSh < pltPeakLoc2; iSh++) { if (identHist[iSh] < identHist[lowPoint] ) { lowPoint = iSh; } } projValley = lowPoint; } else { ilog « Line( LINE ) « "PLToFindUpperPopulation. Peak locations faulty. " « Flush; projValley = projHist.HistRes - 1; } if (projValley == pltPeakLoc) { ilog « Line ( LINE ) « "PLToFindUpperPopulation. projValley hit pltPeakLoc. " « Flush; projValley = projHist.HistRes - 1; } ilog « Line ( LINE ) « "PLToFindUpperPopulation. projValley " « projValley « Flush; 354 355 // Find upper and lower counts based on projValley. int upperCount = projHist.GetCount (projValley, proj Hist.HistRes - 1) ; int lowerCount = projHist.GetCount (0, projValley - 1) ; ilog « Line ( LINE ) « "PLToFindUpperPopulation. Upper count " « upperCount << Flush; ilog « Line ( LINE ) « "PLToFindUpperPopulation. Lower count " « lowerCount « Flush; double prop = 0.0; if (upperCount + lowerCount > 0) { prop = (double) lowerCount / (double) (lowerCount + upperCount) ; ilog « Line ( LINE ) « "PLToFindUpperPopulation. prop " « prop « Flush; } else { pltoAlgFlag = FALSE; } // Find statistics of upper and lower populations, double upperMean = 0.0; double lowerMean = 0.0; double upperSD = 0.0; 355 356 double lowerSD = 0.0; double upperCV = 0.0; double lowerCV = 0.0; projHist.GetStats (0, projValley, lowerMean, lowerSD, lowerCV) ; projHist.GetStats (projValley + 1, projHist.HistRes -1, upperMean, upperSD, upperCV) ; ilog « Line( LINE ) « "PLToFindUpperPopulation. upperMean " « upperMean « Flush; ilog « Line( LINE ) « "PLToFindUpperPopulation. lowerMean " « lowerMean « Flush; ilog « Line( LINE ) « "PLToFindUpperPopulation. lowerSD " « lowerSD « Flush; endclock = clockO; timevalues[pltoFindUpper_char] = (double) (endclock - startclock) / clockMil; // Assess presence of microcytics. // Criteria: // 1. Large upper population ( > 10% of lower population) 356 357 // AND deep valley (count at valley < 0.6 * count at // first peak) // 2. Well-separated upper population (upper mean > lower mean // + 3 * lower standard deviation) AND deep valley as // above // 3. Count at valley < 0.3 ♦ count at first peak and valley // is not at right edge if ( ( (upperCount > (lowerCount * 0.10)) c (projHist[projValley] < (0.6 ♦ projHist [pltPeakLoc] ) ) ) I I ( (upperMean > lowerMean + (3 ♦ lowerSD) ) ScSc (projHist[projValley] < (0.6 * projHist[pltPeakLoc] ) ) ScSc (upperCount > 0) ) I I ( (projValley < projHist.HistRes - 1) ScSc (projHist[projValley] < (0.3 * projHist [pltPeakLoc] ) ) ) ) { ilog « Line( LINE ) « "PLToFindUpperPopulation. Microcytics." « Flush; mcPLToMiRBC = TRUE; // Tag microcytic population. 357 358 if (mcPLToMiRBC == TRUE) { fordl = 0; il < pltomeas.List 0.NumberCells O ; il++) { if (projStatus [il] > projValley) { pltoLItem->CellPopulation(dsPLToRBC, il) ; } } ♦ proportion = prop; } else { ♦ proportion = 1; } ilog « Line ( LINE ) « "PLToFindUpperPopulation. proportion " « ♦ proportion « Flush; // Create discriminant line. // Backtransform valley marker to X and Y coordinates double marker; if (mcPLToMiRBC == FALSE) marker = projHist.HistRes - 1; else marker = projValley; marker *= resol; marker += minproj ; double theta = atan(PLToLinRegress->Slope() ) ; double markx = marker * cos (theta); 358 359 double markY = marker * sin(theta) + PLToLinRegress->Intercept() ; // Determine discriminant characteristics. double dSlope = 0.0; double dlntercept = 0.0; if (abs(PLToLinRegress->Slope() > 0)) { dSlope = -1 / PLToLinRegress- >Slope(); // Perpendicular line. dlntercept = markY - dSlope ♦ markX; } // Store. pitRBCDisc.Reset(dSlope, dlntercept) ; // Clean up. delete [] projRegress; delete [] projStatus; return(pltoAlgFlag) ; } / /= void mcPLTAlgorithm: :CalcPLToParams(const double proportion) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of CalcPLToParams." 359 360 << Flush; // Count platelet tags. unsigned long pcount = 0; for(unsigned long il = 0; il < pltomeas.List() .NumberCells() ; il++) { if (pltoLItem->CellPopulation(il) == dsPLToPLT! { pcount++; } } // Calculate optical platelet concentration. if ( (pltomeas.Count () .FlowRate( ) > 0.0) ScSc (pltomeas.Count 0.Dilution 0 > 0.0) ScSc (pltomeas.Count 0.FinalTime 0 > 0.0) ) { double popratio = proportion ♦ pcount / pltomeas.List() .NumberCells() ; ilog « Line( LINE__) « "CalcPLToParams. proportion " « proportion « Flush; ilog « Line( LINE ) « "CalcPLToParams. pcount " « pcount « Flush; 360 361 ilog « Line ( LINE ) « "CalcPLToParams. popratio " << popratio « Flush; Boolean concFlag = TRUE; // TRUE if concentration calculation // OK. concFlag = Concentration(GATED, pltomeas.Count () , oPLT, opltStat, popratio, (double) 0.001, caldata.CalFactor (dcCalibrationData: :PLT) , caldata.DilFactor (dcCalibrationData: :PLT) ) ; if ( (oPLT < pltRangeLo) I I (oPLT > pltRangeHi) ) { opltStat = dsNumericalResult: :OverRange; } ilog << Line ( LINE ) « "CalcPLToParams. OPLT in K/uL:" « oPLT « Flush; // Calculate statistics. unsigned long iasSum = 0; // Sum of IAS values. unsigned long pssSu = 0; // Sum of PSS values. unsigned long iasS2 = 0; // Sum of IAS squares, 361 362 unsigned long pssS2 = 0; // Sum of PSS squares, for (il = 0; il < pltomeas.List 0.NumberCells () ; il++) { iasSum += pltoLItem->CellMeas dl, dsPLToListMode: :IAS) ; pssSum += pltoLItem->CellMeas (il, dsPLToListMode: :PSS) ; iasS2 += (pltoLItem->CellMeas (il, dsPLToListMode: :IAS) * pltoLItem->CellMeas dl, dsPLToListMode: :IAS) ) ; pssS2 += (pltoLItem->CellMeas (il, dsPLToListMode: :PSS) ♦ pltoLItem->CellMeas (il, dsPLToListMode: :PSS) ) ; } iasMean = (double)iasSum / (double)pltomeas.List 0.NumberCells0 ; iasMeanStat = dsNumericalResult: :CalcOK; pssMean = (double)pssSum / (double)pltomeas.List0.NumberCells0 ; pssMeanStat = dsNumericalResult: :CalcOK; iasCv = (( (double)pltomeas.List 0.NumberCells( ) ♦ (double) iasS2) - ( (double)iasSum ♦ (double) iasSum) ) / ( (double)pltomeas.List 0.NumberCells 0 ♦ ( (double)pltomeas.List 0.NumberCells 0 - 1.0)); iasCv = sqrt (iasCv) ; iasCv = iasCv / iasMean ♦ 100; iasCvStat = dsNumericalResult: :CalcOK; 362 363 pssCv = (( (double)pltomeas. ist O .NumberCells ( ) * (double)pssS2) - ( (doubleJpssSum * (double)pssSum) ) / ( (double)pltomeas.List ( ) .NumberCells ( ) * ( (double)pltomeas.List 0.NumberCells 0 ■ 1.0)); pssCv = sqrt (pssCv) ; pssCv = pssCv / pssMean * 100; pssCvStat = dsNumericalResult: :CalcOK; #ifdef SPOTDIAG FILE* spotd = fopen( "pltspot.txt", "a") ; double RBCo; // Optical RBC concentration. // Based on ungated - gated + // microcytic. dsNumericalResult: :NRStatus rbcoStat; concFlag = Concentration(FINAL, pltomeas.Count () , RBCo, rbcoStat, 1.0, (double) 0.001, caldata.CalFactor (dcCalibrationData: :PLT) , caldata.DilFactor (dcCalibrationData: :PLT) ) ; double MicR; dsNumericalResult: :NRStatus micrStat; concFlag = Concentration(GATED, pltomeas.Count ( ) , MicR, micrStat, 363 364 1.0 - popratio, (double) 0.001, caldata.CalFactor (dcCalibrationData: :PLT) , caldata.DilFactor (dcCalibrationData: :PLT) ) ; RBCo = RBCo - oPLT + MicR; fprintf(spotd, "RBCo\t%f\tPLToMeasTime\t%f\n", RBCo * 0.001, pltomeas.Count () .FinalTime0 ) ; fclose(spotd) ; #endif } } / ___ = _ = =-=-= =— void mcPLTAlgorithm: :SetPLToFlags (const Boolean& algflag) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line ( LINE ) « "Top of SetPLToFlags." « Flush; // Set flags. if (algflag == TRUE ) { 364 365 ilog << Line ( LINE ) << "SetPLToFlags. PLTo calculation OK." << Flush; if ( (oPLT > plthi) ScSc (opltStat == dsNumericalResult : : CalcOK) ) { pltHiFlag = TRUE; } if ( (oPLT < pltlo) && (opltStat == dsNumericalResult: :CalcOK) ) { pltLoFlag = TRUE; } } else if (algflag == FALSE) { ilog << Line( LINE ) « "SetPLToFlags. PLTo calculation bad." « Flush; opltStat = dsNumericalResult: -.Suspect; pctStat = dsNumericalResult::Suspect; } } void mcPLTAlgorithm: :SendNumResults (void) { // Internal diagnostics. 365 366 dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) << "Top of SendNumResults." « Flush; // Internal logs for hardware diag. ilog « Line( LINE ) << "SendNumResults. HEY ROD impedance pit cone = " << pLT << Flush; double temp = oPLT; // Uncalibrated concentration. if ( (caldata.CalFactor(dcCalibrationData: :PLT) > 0) S (caldata.DilFactor (dcCalibrationData: :PLT) > 0) ) { temp = oPLT / caldata.CalFactor(dcCalibrationData: :PLT) / caldata.DilFactor(dcCalibrationData: :PLT) ; ilog « Line( LINE ) « "SendNumResults. HEY ROD optical pit cone = " « temp « Flush; // Send the numerical results to storage. // 366 367 / / PLT . cbcresults.Number() [dsPLTConc] .Value(oPLT) ; cbcresults.Number() [dsPLTConc] .Stat (opltStat) ; ilog << Line( LINE ) « "SendNumResults. PLTo " « oPLT « " status " « opltStat « Flush; ilog « Line( LINE ) « "SendNumResults. PLTi " « pLT << " status " « pltStat « Flush; // MPV. cbcresults.Number0 [dsMeanPLTVolume] .Value(mPV) ; cbcresults.Number() [dsMeanPLTVolume] .Stat( pvStat) ; ilog « Line( LINE ) « "SendNumResults. MPV " « mPV « " status " « mpvStat << Flush; // PDW. cbcresuits.Number() [dsPLTDistributionWidth] .Value(pDW) ; cbcresults.Number() [dsPLTDistributionWidth] .Stat(pdwStat) ; ilog « Line( LINE ) « "SendNumResults. PDW " « pDW « " status " « pdwStat << Flush; 367 368 / / PCT . cbcresults.Number() [dsPLTCrit] .Value (pCT) ; cbcresuits.Number0 [dsPLTCrit] .Stat(pctStat) ; ilog « Line( LINE ) << "SendNumResults. PCT " « pCT << " status " « pctStat « Flush; // Derived statistics, cbcresuits.Number() [dsPLTMean_IAS] .Value(iasMean) ; cbcresults.Number0 [dsPLTMean_IAS] .Stat(iasMeanStat) ; cbcresults.Number() [dsPLTMean_PSS] .Value(pssMean) ; cbcresults.Number() [dsPLTMean_PSS] .Stat(pssMeanStat) ; cbcresults.Number() [dsPLTCV_IAS] .Value(iasCv) ; cbcresuits.Number0 [dsPLTCV_IAS] .StatdasCvStat) ; cbcresults.Number() [dsPLTCV_PSS] .Value(pssCv) ; cbcresults.NumberO [dsPLTCV_PSS] .Stat(pssCvStat) ; // Misc. listmode items. cbcresuits.Number() [dsPLToListModeSize] .Value( pltomeas.ListO .NumberCells0 ); cbcresuits.Number() [dsPLToListModeSize] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number0 [dsPLToUngatedCount] .Value( 368 369 pltomeas.Count ( ) .FinalCoun ( ) ) ; cbcresults.Number0 [dsPLToUngatedCount] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number() [dsPLToGatedCount] .Value( pltomeas.Count () .FinalGatedCount 0 ) ; cbcresults.Number0 [dsPLToGatedCount] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number ( ) [dsPLToCountTime] .Value( pltomeas .Count ( ) .FinalTime 0 ) ; cbcresults.Number( ) [dsPLToCountTime] .Stat( dsNumericalResult: :CalcOK) ; cbcresults. umber 0 [dsPLToDilution] .Value ( pltomeas.Count 0.Dilution() ); cbcresults.Number() [dsPLToDilution] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number() [dsPLToFlowRate] .Value( pltomeas.Count () .FlowRate0 ) ; cbcresults.NumberO [dsPLToFlowRate] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number0 [dsPLTiListModeSize] .Value( pltimeas.List () .NumberCells ( ) ); cbcresults. umber 0 [dsPLTiListModeSize] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number ( ) [dsPLTiUngatedCount] .Value ( pltimeas.Count () .FinalCount 0 ) ; cbcresults. umber() [dsPLTiUngatedCount] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number0 [dsPLTiGatedCount] .Value( 369 370 pltimeas.Count ( ) .FinalGatedCount ( ) ) ; cbcresults. umber ( ) [dsPLTiGatedCount] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number () [dsPLTiGatedCount] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number ( ) [dsPLTiCountTime] .Value ( pitimeas.Count () .FinalTime 0 ); cbcresults.Number ( ) [dsPLTiCountTime] .Stat( dsNumericalResult: :CalcOK) ; cbcresults.Number ( ) [dsPLTiDilution] .Value( pltimeas.Count () .Dilution( ) ) ; cbcresults.Number ( ) [dsPLTiDilution] .Stat ( dsNumericalResult: :CalcOK) ; cbcresults.Number () [dsPLTiFlowRate] .Value( pltimeas.Count () .FlowRate ( ) ); cbcresults.Number 0 [dsPLTiFlowRate] .Stat( dsNumericalResult: :CalcOK) ; } / /==============================================: void mcPLTAlgorithm: :SendAlertResults (void) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of SendAlertResults." 370 371 << Flush ; // Utility variables. Boolean algstat = TRUE; // Trip flags that are dependent on plti if (mpvHiFlag) { cbcresults.Alert 0 [dsPLTLarge] .Value( cbcresults.Alert ( ) [dsPLTLarge] .Alerted) ; } if (pdwHiFlag) { cbcresults.Alert 0 [dsPLTVolumeAnisocytosis] .Value( cbcresults.Alert 0 [dsPLTVolumeAnisocytosis] .Alerted) ; } if (pltilower) { cbcresults.Alert O [dsPLTiLowerInterfere] .Value( cbcresults.Alert 0 [dsPLTiLowerInterfere] .Alerted) ; } if (pltiupper) { cbcresults.Alert ( ) [dsPLTiUpperInterfere] .Value( cbcresults.Alert () [dsPLTiUpperinterfere] .Alerted) ; cbcresults.Alert 0 [dsPLTMicroRBC] .Value( cbcresults.Alert 0 [dsPLTMicroRBC] .Alerted) ; } if (!pltiEvenTiming) { cbcresults.Alert 0 [dsPLTiNonuniformFlowRate] .Value( 371 372 cbcresults.Aler ( ) [dsPLTiNonuniformFlowRat lerted) ; } // Trip flags that are dependent on plto if (pltolower) { cbcresults.Alert 0 [dsPLToLowerlnterfere] .Value( cbcresults.Alert () [dsPLToLowerlnterfere] .Alerted) ; } if (pltoupper) { cbcresults.Alert 0 [dsPLToUpperlnterfere] .Value ( cbcresults.Alert O [dsPLToUpperlnterfere] .Alerted) ; cbcresults.Alert 0 [dsPLTMicroRBC] .Value ( cbcresults.Alert 0 [dsPLTMicroRBC] .Alerted) ; } if (pltLoFlag) { cbcresults.Alert () [dsPLTThrombocytopenia] .Value ( cbcresults.Alert () [dsPLTThrombocytopenia] .Alerted) ; } if (pltHiFlag) { cbcresults.Alert () [dsPLTThrombocytosis] .Value ( cbcresults.Alert 0 [dsPLTThrombocytosis] .Alerted) ; } if (!pltoEvenTiming) { cbcresults.Alert 0 [dsPLToNonuniformFlowRate] .Value( cbcresults.Alert 0 [dsPLToNonuniformFlowRat 372 373 e] .Alerted) ; } // Trip flags that are dependent on both plto and plti if (oPLT > 0) { if ( fabsdpLT - oPLT) / oPLT) > (mcPLTDelta * 0.01) ) { cbcresults.Alert 0 [dsPLTDelta] .Value( cbcresults.Alert () [dsPLTDelta] .Alerted) ; } } } void mcPLTAlgorithm: :SendScatResultsO { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of SendScatResults." « Flush; // Utility variables. Boolean algstat = TRUE; 373 374 unsigned long maxopltscat = MI (pltomeas.List ( ) .NumberCells ( ) , cbcresult s.PLToScat 0.MaxCellsO ) ; // Send the scatter results to storage. for (unsigned long i = 0; i < maxopltscat; i++ { dsPLToScatMeas cellmeas; // Arrays for display. // Zero values below (resolution/4) and scale rest by 4/3 cellmeas.ias = (unsigned char)pltoLItem->CellMeas (i, dsPLToListMode: :IAS) ; cellmeas.pss = (unsigned char)pltoLItem->CellMeas(i, dsPLToListMode: :PSS) ; const dsPLToScatMeas* newmeas = &cellmeas; dsPLToPopulation type; if ( pltoLItem->CellPopulation(i) == dsPLToPLT) type = dsPLToPLT; else if (pltoLItem->CellPopulation(i) == dsPLToRBC) type = dsPLToRBC; else type = dsPLToNoise; algstat = algstat ScSc cbcresults.PLToScat 0.AddCell (newmeas, 374 375 type ) } / / Store discriminants . // Store no discriminants if listmode count too low. mgRealPoint discPoint; if ( (noPLToCells == FALSE) I I (calcflag == FALSE) ) { // Low PSS gate. dsScatDiscriminant& lowPSS = cbcresults.PLToScat() .Discriminant(dsPLToSca t: :Background) ; lowPSS.AddPoint(0, (dsScatMeas)backgroundDis c.Intercept0 ) ; lowPSS.AddPoint(pltoScatSize - 1, (dsScatMeas)backgroundDis c.Intercept0 ) ; // Lower regression gate. dsScatDiscriminant& lowReg = cbcresults.PLToScat() .Discriminant(dsPLToSca t: :PLTLower) ; if (pltLowerDisc.Intercept 0 < 0) // Fit to frame. { discPoint.x = -pltLowerDisc.Intercept() 375 376 / pltLowerDisc.Slope ( ) ; discPoint.y = 0; } else if (pltLowerDisc.Intercept ( ) > pltoScatSize - 1) { discPoint.x = (pltoScatSize - pltLowerDisc.Intercept ( ) - 1) / pltLowerDisc.Slope() ; discPoint.y = pltoScatSize - 1; } else { discPoint.x = 0; discPoint.y = pltLowerDisc.Intercept 0 ; } lowReg.AddPoint ( (dsScatMeas)discPoint.x, (dsScatMeas)discPoint.y) ; double endpoint = (pltLowerDisc.Slope ( ) * (pltoScatSize - 1) ) + pltLowerDisc.Intercept 0 ; if (endpoint < 0) { discPoint.y = 0; discPoint.x = -pltLowerDisc.Intercept ( ) / pltLowerDisc.Slope 0 ; } else if (endpoint > pltoScatSize - 1) { discPoint.y = pltoScatSize - 1; discPoint.x = (pltoScatSize - pltLowerDisc.Intercept 0 - 1) / pltLowerDisc.Slope ( ) ; } else { 376 377 discPoint.x = pltoScatSize - 1; discPoint.y = (pltLowerDisc.Slope ( ) * discPoint.x) + pltLowerDisc.Intercept ( ) ; } lowReg.AddPoint ( (dsScatMeas)discPoint.x, (dsScatMeas)discPoint.y) ; // Upper regression gate. dsScatDiscriminant& hiReg = cbcresults.PLToScat ( ) .Discriminant (dsPLToSca t: :PLTUpper) ; if (pltUpperDisc.Intercept( ) < 0) //Fit to frame. { discPoint.x = -pltUpperDisc.Intercept ( ) / pltUpperDisc.Slope ( ) ; discPoint.y = 0; } else if (pltUpperDisc.Intercept ( ) > pltoScatSize - 1) { discPoint.x = (pltoScatSize - pltUpperDisc.Intercept () - 1) / pltUpperDisc.Slope ( ) ; discPoint.y = pltoScatSize - 1; } else { discPoint.x = 0; discPoint.y = pltUpperDisc.Intercept 0 ; } 377 378 hiReg.AddPoint ( (dsScatMeas)discPoint.x, (dsScatMeas)discPoin .y) ; endpoint = pltUpperDisc.Slope ( ) * (pltoScatSize - 1) + pltUpperDisc.Intercept () ; if (endpoint < 0) { discPoint.y = 0; discPoint.x = -pltUpperDisc.Intercept ( ) / pltUpperDisc.Slope 0 ; } else if (endpoint > pltoScatSize - 1) { discPoint.y = pltoScatSize - 1; discPoint.x = (pltoScatSize - pltUpperDisc.Intercept ( ) - 1) / pltUpperDisc.Slope ( ) ; } else { discPoint.x = pltoScatSize - 1; discPoint.y = (pltUpperDisc.Slope0 * discPoint.x) + pltUpperDisc.Intercept 0 ; } hiReg.AddPoint ( (dsScatMeas)discPoint.x, (dsScatMeas)discPoint.y) ; // Microcytic RBC gate. dsScatDiscriminant& micGate = cbcresults.PLToScat ( ) .Discriminant (dsPLToSca 378 379 t: :PLT_RBC) ; micGate.AddPoint ( (dsScatMeas) ( pltRBCDisc.Intersect (pltUpperDisc) .x) , (dsScatMeas) ( pltRBCDisc.Intersect (pltUpperDisc) .y) ) ; micGate.AddPoint ( (dsScatMeas) ( pltRBCDisc.Intersect (pltLower Disc) .x) , (dsScatMeas) ( pltRBCDisc.Intersect (pltLowerDisc) .y) ) ; } } / /= void mcPLTAlgorithm: :BinCut (const mmHist256& calcHist) { dtlnternalLog ilog(SourceFileName) ; ilog « Line ( LINE ) « "Top of BinCut." « Flush; // Constants. double fraction = 0.04; // Fraction of histogram 379 380 mode that // a count must be in order to lie // outside a threshold (searching // outward from the mode; double valleyLid = 0.2; // Fraction of mode that a valley must // fall below in order to be considered // a valley. // Filter histogram. - // Use 64 bin filtering algorithm. unsigned short iSh; // Create 64 bin histogram, made of 4 point averages of calcHist. Boolean scaleFlag = TRUE; mmHist256 filtHist (calcHist; // Filtered histogram. #ifdef SCR509 Filter64Bin(calcHist, TRUE, FALSE, filtHist) ; #else Filter64Bin(calcHist, FALSE, FALSE, 380 381 filtHist) ; #endif // Find peak of histogram excluding first and last bins. // Label peaks and valleys. intVec peakMarker(256, 0) ; peakMarker = filtHist.Peaks() ; iSh = filtHist.HistRes - 2; int peakLoc = maxlndex(filtHist) ; double peakval = (double)maxValue(filtHist) ; ilog « Line( LINE ) « "BinCut. peak mode " << peakval « Flush; ilog « Line( LINE ) « "BinCut. peak bin " « peakLoc « Flush; // Search on either side of peakBin for bins such that histogram // counts = fraction * peakMode. Use filtered histogram. // Low threshold. // Find first occurrence of: // 1. Count = fraction * peakval. // 2. Valley between main peak and next peak to left, if such // peak exists. Valley must be less than valleyLid ♦ mode. 381 382 int leftLoc, lvalLoc; // Leftward peak and valley. iSh = peakLoc; while ( (iSh > 0) ScSc ( (double) filtHist [iSh] > fraction ♦ peakval) ) { iSh--; } pltiLoThresh = iSh; // Look for left peak. iSh = peakLoc - 1; while((iSh > pltiLoThresh) && (peakMarker[iSh] <= 0)) { iSh--; } leftLoc = iSh; ilog « Line ( LINE ) « "BinCut. leftLoc " « leftLoc « Flush; // Look for valley between left peak and main peak. if (leftLoc > pltiLoThresh) { lvalLoc = filtHist.Valley(leftLoc, peakLoc); ilog « Line ( LINE ) « "BinCut. lvalLoc " « lvalLoc « Flush; 382 383 if ( (lvalLoc > 0) ScSc (filtHist [lvalLoc] < valleyLid ♦ peakval) { pltiLoThresh = lvalLoc; } } ilog « Line ( LINE ) « "pltiLoThresh " << pltiLoThresh « Flush; // High threshold. // Find first occurrence of: // 1. Count = fraction ♦ peakval. // 2. Valley between main peak and next peak to right, if such // peak exists. int rightLoc, rvalLoc; iSh = peakLoc; while ( (iSh < filtHist.HistRes - 2) S (filtHist[iSh] > fraction ♦ peakval) ) { iSh++; } pltiHiThresh = iSh; // Look for right peak. iSh = peakLoc + 1; while( (iSh < pltiHiThresh) && (peakMarker[iSh] <= 0)) { iSh++; 383 384 } rightLoc = iSh; ilog « Line ( LINE ) << "BinCut. rightLoc " « rightLoc « Flush; // Look for valley between main peak and right peak. if (rightLoc < pltiHiThresh) { rvalLoc = filtHist.Valley(peakLoc, rightLoc); ilog « Line ( LINE ) « "BinCut. rvalLoc " « rvalLoc « Flush; if ( (rvalLoc > 0) ScSc (filtHist [rvalLoc] < valleyLid ♦ peakval)) { pltiHiThresh = rvalLoc; } } ilog « Line( LINE ) « "BinCut. pltiHiThresh " « pltiHiThresh « Flush; // Trap errors. // In case of error, set thresholds at ends. if (pltiLoThresh > pltiHiThresh) { ilog « Line( LINE ) « "BinCut. Problem with thresholds, 384 385 << Flush ; pltiLoThresh = 0; pltiHiThresh = filtHist.HistRes - 1; } // Search for valley in histogram, indicating possible red cell // microcytic population. int mcytVal = filtHist.Valley ( (int) (filtHist.HistRes ♦ 0.10) , (int) (filtHist.HistRes * 0.75) ); if (mcytVal > 0) { pltiupper = TRUE; ilog << Line ( LINE ) « "BinCut. Upper region interference." « Flush; } } / /============================================================ void mcPLTAlgorithm: :CalcPLTiParams (const mmHist256& calcHist) { dtlnternalLog ilog(SourceFileName) ; ilog « Line ( LINE ) « "Top of CalcPLTiParams. " « Flush; 385 386 // Local flags. Boolean concFlag; // Create histogram containing only the counts between thresholds. // mmHist256 cutHist; unsigned short iSh; fordSh = 0; iSh < (unsigned short) (calcHist.HistRes 1) ; iSh++) { if ( (iSh < pltiLoThresh) I I (iSh > pltiHiThresh) cutHist[iSh] = 0; else cutHist [iSh] = calcHist [iSh] ; } // Count-based parameters. concFlag = TRUE; if ( (noPLTiCells == TRUE) I I (calcflag == FALSE)) { concFlag = CalcPLTiConc (calcHist, 0, calcHis t.HistRes - 1) ; } 386 387 else { concFlag = CalcPLTiConc(calcHist, pltiLoThresh, pltiHiThresh) ; if (concFlag == FALSE) { ilog « Line ( LINE ) « "CalcPLTiParams, Bad thresholds." « Flush; // Distributional and derived parameters. concFlag = TRUE; if ( ( (specimentype.Type( ) == diSpecimenType: :PatientSpecimen) I I (specimentype.Type( diSpecimenType: :QCSpecimen) ) ScSc (noPLTiCells == FALSE) Sc (calcflag == TRUE) ) { // MPV, PDW. concFlag = CalcPLTDist (calcHist, pltiLoThresh, pltiHiThresh) ; 387 388 if (concFlag == FALSE) { ilog « Line( LINE ) « "CalcPLTiParams. Bad thresholds, « Flush; } // InternalLogs. ilog « Line( LINE ) « "CalcPLTiParams. PLT " « pLT « Flush; ilog « Line ( LINE ) « "CalcPLTiParams. MPV " « mPV « Flush; ilog « Line( LINE ) « "CalcPLTiParams. PDW " « pDW « Flush; } / /====================================================: Boolean mcPLTAlgorithm: :CalcPLTiConc (const mmHist256& calcHist, const int lowBin, const int hiBin) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) 388 389 << "Top of CalcPLTiConc." << Flush; // Initial checks. if (lowBin >= hiBin) return(FALSE) ; // Histogram ratios double pltratio = 0.0; int totalCounts = calcHist.GetCountO ; int upperCounts = calcHist.GetCount(lowBin, hiBin); if (totalCounts <= 0) { pltStat = dsNumericalResult: -.Suspect; } else { pltratio = (double) (upperCounts) / (double) (totalCounts) ; } // Concentration calculation. Boolean concFlag; if ( (pltimeas.Count 0.FlowRate() > 0.0) S Sc (pltimeas.Count0.Dilution0 > 0.0) ScSc (pltimeas.Count0.FinalTime0 > 0.0) ScSc (pltStat != dsNumericalResult::Suspect) 389 390 concFlag = Concentration(FINAL, pltimeas .Count ( ) , pLT, pltStat, pltratio, (double) 0.001, 1.0, 1.0); if ( (pLT < pltRangeLo) I I (pLT > pltRangeHi)) { pltStat = dsNumericalResul : :OverRange; } ilog « Line( LINE ) « "CalcPLTiConc. pLT " << pLT « Flush; return(TRUE) ====== Boolean mcPLTAlgorithm: :CalcPLTDist (const mmHist256& calcHist, const int lowBin, const int hiBin) { dtlnternalLog ilog(SourceFileName) ,- ilog « Line( LINE ) « "Top of CalcPLTDist." « Flush; 390 391 // Initial checks. if (lowBin >= hiBin) return(FALSE) ; // MPV and PDW calculation. Boolean concFlag; if ( (pitimeas.Count 0.FlowRate 0 > 0.0) ScSc (pltimeas.Count 0.DilutionO > 0.0) Sc c (pitimeas.Count 0.FinalTime() > 0.0) ) { double standDev; // Standard deviation, not used. calcHist.GetStats(pltiLoThresh, pltiHiThresh, mPV, standDev, pDW) ; pdwStat = dsNumericalResult: :CalcOK; // Scale MPV. mPV *= mcPLTVolPerBin ♦ caldata.CalFactor(dcCalibrationData: :MPV) ♦ caldata.DilFactor(dcCalibrationData: :MPV) ,- if ( (mPV < mpvRangeLo) I I (mPV > mpvRangeHi)) { mpvStat = dsNumericalResult: :OverRange; } 391 392 else { mpvStat = dsNumericalResult: :CalcOK; } } ilog « Line( LINE ) « "CalcPLTDist. MPV " « mPV « Flush; ilog « Line( LINE ) « "CalcPLTDist. PDW " « pDW « Flush; return(TRUE) ; } / /=================================================== ====== void mcPLTAlgorithm: :CalcPCT() { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of CalcPCT." « Flush; ilog « Line( LINE ) « "CalcPCT. oPLT " « OPLT « Flush; ilog « Line( LINE ) « "CalcPCT. mPV " « mPV « Flush; 392 393 pCT = oPLT * mPV * 0.0001; if ((opltStat == dsNumericalResult: :CalcOK) ScSc (mpvStat == dsNumericalResult: :CalcOK) ) { pctStat = dsNumericalResult: :CalcOK; } else { pctStat = dsNumericalResult::Suspect; } ilog « Line( LINE ) « "CalcPCT. optical PCT " « pCT « Flush; double PCTi = pLT * mPV * 0.0001; ilog « Line( LINE ) « "CalcPCT. impedance PCT " « PCTi « Flush; } / /========================================================== void mcPLTAlgorithm: :Filter64Bin(const mmHist256& calcHist, const Boolean reflectEnd, const Boolean zeroLeft, mmHist256& filtHist) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) 393 394 « "Top of Filter64Bin. " « Flush; // Create 64 bin histogram, made by averaging every 4 bins. double ♦ finArray = new double [ (int) (calcHist.HistRes) ] ; double ♦ reducArrayl = new double [ (int) (calcHist.HistRes) /4] ; double ♦ reducArray2 = new double [ (int) (calcHist.HistRes) /4] ; unsigned short iSh; // Fill array of doubles. fordSh = 0; iSh < calcHist.HistRes; iSh++) { finArray[iSh] = calcHist[iSh] ; } // Define 7-bin boxcar filter. double *boxcar7 = new double [7] ; fordSh = 0; iSh < 7; ' iSh++) { boxcar7[iSh] = 1.0; } // Create reduced arrays. Boolean shrinkFlag = ReduceResolution(finArray, 394 395 calc Hist . HistRes , reducArrayl, calc Hist.HistRes/4) ; // Filter twice. if (shrinkFlag == TRUE) { GenericFilter(boxcar7, reducArrayl, 2, 7, 64, reducArray2) ,- } // Reflect ends, if desired. if (reflectEnd == TRUE) { ilog « Line ( LINE ) « "Filter64Bin. Ends reflected." « Flush; double sum; // Left end. sum = reducArrayl[0] ; int leftReflect = 3; int rightReach = 4; fordSh = 1; iSh < 4; iSh++) 395 396 { sum += 2*reducArrayl [iSh] ; } fordSh = 0; iSh < 4; iSh++) { reducArray2 [iSh] = sum / 7; sum = sum - reducArrayl[leftReflect] + reducArrayl [rightReach] ; // Move box. leftReflect--,- rightReach++; } // Right end. sum = reducArrayl[63] ; int rightReflect = 60; int leftReach = 59; fordSh = 60; iSh < 63; iSh++) { sum += 2*reducArrayl [iSh] ; } fordSh = 63; iSh > 60; iSh--) { reducArray2 [iSh] = sum / 7; sum = sum - reducArrayl[rightReflect] + reducArrayl [leftReach] ; // Move box. leftReach--; rightReflect++; } } // Zero left, if desired. 396 397 if (zeroLeft == TRUE) { ilog << Line ( LINE ) << "Filter64Bin. Zero left end. " « Flush; fordSh = 0; iSh < 3; iSh++) { reducArray2 [iSh] = 0.0; } // Expand back out to 256 if (shrinkFlag == TRUE) { shrinkFlag = Interpolate(reducArray2, calcHist.HistRes/4, 4, finArray) ; } // Fill result histogram. // If reduction and/or interpolation failed: the returned // histogram will be the same as the original, and no filtering // will have occurred. fordSh = 0; iSh < calcHist.HistRes; iSh++) { filtHist [iSh] = (int) finArray[iSh] ; 397 398 } // Clean up. delete [] finArray; delete [] reducArrayl; delete [] reducArray2; delete [] boxcar7; } / /============================================================ void mcPLTAlgorithm: :CalcPLTiShapeParams (const mmHist256& calcHist) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of CalcPLTiShapeParams." « Flush; // Constants. const int binsToAvg = 4; // Number of bins to average // together to smooth data in // original domain. // Power of two only. const int numberGroups = 8; int A firstBin = new int [numberGroups + 1] ; 398 399 // First bins of bin groupings // for taking averages which will be // used in regression. firstBin[0] = 25; // These values are taken from firstBin[l] = 31; // CD3500 precedent. firstBin[2] = 38; // Widths increase because of firstBin[3] = 48; // later lognorm scaling and to firstBin[4] = 59; // reduce effects of contamination firstBin[5] = 73; // in tail. firstBin[6] = 91; // The ends of the histogram are firstBin[7] = 113; // avoided. firstBin[8] = 139; // Only the first eight groups are // used. FirstBin[8] is a cieling. // Derived values. double InRes = log(calcHist.HistRes) / calcHist.HistRes; // Create reduced bin array and fill with natural log of bin value. double^ binArray = new double [numberGroups] 399 400 unsigned iSh; // Take In of bin in middle of grouping. fordSh = 0; iSh < numberGroups; iSh++) { binArray[iSh] = log(firstBinfiSh] + (firstBinfiSh + 1] - firstBinfiSh] ) 1 2 ) ; } binArray[numberGroups + 1] = calcHist.HistRes; // Create array of grouped averages and take In. double* logData = new double [numberGroups] ; unsigned iSh2; double avg; fordSh = 0; iSh < numberGroups; iSh++) { avg = 0.0; for(iSh2 = firstBin[iSh] ; iSh2 < firstBin[iSh + 1] ; iSh2++) { avg += calcHist[iSh2] ; } avg /= (firstBin[iSh + 1] - firstBinfiSh]); if (avg <= 0) { logData[iSh] = 0.0; } else { logDatafiSh] = log(avg); 400 401 } } // Create array of delta (In(data) ) / delta (ln(bin)). double* delt = new double [numberGroups - 1] ; fordSh = 0; iSh < numberGroups - 1; iSh++) { if (binArray[iSh + 1] != binArray[iSh] ) { deltfiSh] = logData[iSh + 1] - logData[iSh] ,- delt[iSh] /= (binArray[iSh + 1] - binArray[iSh] ) ; } } DoubleVec yvec(delt, numberGroups - 1) ,- DoubleVec xvec(delt, numberGroups - 1); for (iSh = 0; iSh < numberGroups - 1; iSh++) { xvec[iSh] = log(exp (binArray[iSh + 1] ) ) ; ilog << Line ( LINE ) « "CalcPLTiShapeParams. x " « xvec[iSh] « " y " « yvec[iSh] « Flush; } ilog « Line( LINE ) « "CalcPLTiShapeParams. Made doublevecs." « Flush; // Linear regression. 401 402 LeastSqFit lsf(xvec, yvec) ; // Calculate MPV. // Formulae from Paulus (1975! double stdevLogDis = 0; // Standard deviation of logO . double meanLogDis = 0; // Mean of log( ) . if (lsf.slopeO < 0) { stdevLogDis = sqrt ( -InRes / lsf.slope 0 ); meanLogDis = -( lsf.intercept 0 / lsf.slope () ) + (0.5 * stdevLogDis * stdevLogDis); ilog « Line ( LINE ) « "CalcPLTiShapeParams. stdevLogDis " « stdevLogDis « Flush; ilog « Line ( LINE ) « "CalcPLTiShapeParams. meanLogDis " « meanLogDis « Flush; mPV = exp(meanLogDis) * mcPLTVolPerBin * caldata.CalFactor(dcCalibrationData: :MPV) * caldata.DilFactor(dcCalibrationData: :MPV) ; } if (meanLogDis > 0) { mPV = exp(meanLogDis) 402 403 * mcPLTVolPerBin * caldata.CalFactor(dcCalibrationData: :MPV) caldata.DilFactor(dcCalibrationData: :MPV) ; } // Retrieve PDW. // Formulae from Paulus (1975) and Probability and Statistics // for Engineers, Miller/Freund. double varianceVolDis = 0; if (stdevLogDis > 0 ) { varianceVolDis = (2 * -lsf.intercept O / lsf.slope 0) + (stdevLogDis * stdevLogDis); varianceVolDis = exp( varianceVolDis); varianceVolDis ♦ = exp(stdevLogDis * stdevLogDis - 1); } if (varianceVolDis > 0) { pDW = sqrt (varianceVolDis) ♦ mcPLTVolPerBin ♦ 100 / mPV; } // Clean up. delete [] binArray; delete [] logData; delete [] delt; delete [] firstBin; 403 404 ilog « Line( LINE ) << "CalcPLTiShapeParams. End." << Flush; } ** *_. ♦ Copyright 1993 by Abbott Laboratories ♦ Source Code Control System keywords * * NAME: $Source: /home/larar/printme/RCS/mcPLTAlgorithm.h,v $ ♦ $Locker: $ ♦ $State: Exp $ ♦ $Revision: 2.16 $ ♦ $Author: larar $ ♦ $Date: 94/11/30 15:08:20 $ ♦ Log: .. See below * * LANGUAGE: LynxOS Cl C++ * ♦ DESCRIPTION: ♦ This file contains the class definition for the algorithms * used to calculate the platelet part of the CBC. * ♦ ....$Log: mcPLTAlgorithm.h,v $ ♦ Revision 2.16 94/11/30 15:08:20 larar ♦ SCR #515: * Updated documentation to reflect changes in PCT 404 405 calculation. * * Revision 2.15 94/11/30 12:25:09 larar * SCR #513: * Renamed uneven timing flags. * * Revision 2.14 94/11/29 10:32:20 larar * SCR #511: * Added CalcPLTiConc, CalcPLTDist and CalcPCT. Changed some return types * from Boolean to void where Boolean return was inappropriate or not used. * * Revision 2.13 94/11/21 12:02:18 larar ♦ SCR509: * Add arguments to Filter64Bin for optional filtering with reflection * and zeroing of left end to reduce artifacts. * * Revision 2.12 94/11/17 17:08:26 larar * SCR #505: * Add storage and status for derived statistical results. * Add range limits. * ♦ Revision 2.11 94/11/17 10:47:25 larar * SCR443: * Added class constants and updated timing enums. Added flags and * thresholds. * Revision 2.10 94/10/26 11:43:13 larar * SCR #444: * Added default standard error of regression for use in * PLToRegressBandGate0. This is to confine diffuse and low count 405 406 * optical platelet clusters. * * Revision 2.9 94/10/25 13:29:54 larar * SCR #430: * SCR #435: * Added DoPLTiSparse () and DoPLToSparse() to process low count and * background samples. * Expanded arguments of MakeDisplayHist() . * SCR #300: * Removed more extraneous globals from argument lists. * * Revision 2.8 94/10/21 17:13:40 larar * SCR #435: * Change number of cells required for listmode analysis from 30 to 50. * * Revision 2.7 94/10/18 12:51:25 larar * SCR #393: ♦ Added storage for optical platelet discriminant lines. * * Revision 2.6 94/10/14 11:06:28 larar * SCR #413: * Added threshold and mode search constants for use with ♦ mgCellAlgorithm: :ScaleDisplayHistO . * * Revision 2.5 94/10/13 14:29:23 larar * SCR #335: * Update constructor arguments for new dcCalibrationData interface. * * Revision 2.4 94/10/12 16:42:01 larar * SCR #361: * Added method Filter64Bin to severely filter noisy data. * Reintroduced upper regression band gate and tightened both 406 407 gates . * * Revision 2.3 94/09/26 14:23:38 larar * SCR #300: * ml47 R4. Removed globals from argument lists. * * Revision 2.2 94/09/23 08:22:45 larar * SCR #300: * Removed extraneous globals and reorganized status markers. ♦ Added method CalcPLTiShapeParams to calculate MPV and PDW using ♦ lognormal regression. * ♦ Revision 2.1 94/09/08 08:12:28 larar ♦ SCR #300: ♦ Added method BinCut for bin thresholding. * ♦ Revision 2.0 94/08/19 15:24:16 larar ♦ SCR #252: * Code redesigned for greater modularity. * * Revision 1.20 94/07/22 12:09:16 larar * SCR #225: * Added calibration and dilution factors to constructor arguments and ♦ storage. * ♦ Revision 1.19 94/07/22 10:34:02 larar * SCR #118: * Changes made after redesign review. ♦ Removed maxplticells, maxpltocells, muchoPLTiCells, muchoPLToCells. * ♦ Revision 1.18 94/07/21 16:25:50 larar ♦ SCR #118: 407 408 ♦ Changes made after redesign review. ♦ Removed pltifitvec and pltofitvec. * ♦ Revision 1.17 94/07/18 17:36:47 larar ♦ SCR #219: ♦ Made destructor virtual . * ♦ Revision 1.16 94/07/07 14:48:30 larar ♦ SCR #118: * Added storage for returned arrays of fitted lineshapes (both impedance ♦ and optical least squares fitting) . * ♦ Revision 1.15 94/06/28 17:17:14 larar * SCR #204: ♦ Replaced mcPLTiCell and mcPLToCell with mcPLTiListMode and mcPLToListMode; ♦ changed pltiLItem and pltoLIte accordingly. * ♦ Revision 1.14 94/06/27 13:37:55 larar ♦ SCR #208: ♦ Added 'pltievents' and 'pltoevents' to accommodate hardware counts. * ♦ Revision 1.13 94/06/15 22:51:47 larar ♦ SCR #194: ♦ Added flags for abundant and absent data and reorganized flagging and ♦ status protocols. ♦ Revision 1.12 1994/05/24 00:40:53 larar ♦ Added measurement timing flags. * ♦ Revision 1.11 1994/05/19 15:23:58 larar * SCR #145: 408 409 Changed some arguments to suppress warnings. Revision 1.10 1994/05/12 18:24:16 larar Split SetFlags into SetPLTiFlags and SetPLToFlags Added status and morphology flags. Revision 1.9 1994/05/05 20:50:22 larar Minor changes. MT3 label. Revision 1.7 1994/04/08 20:23:35 larar Post-inspection changes. Removed rbc-related includes and arguments, Removed dsos constants. Added storage for data and algorithm flags. Removed SendHistResults ( ) and GetPLTDataO. * Revision 1.6 94/03/25 15:09:25 larar ♦ Added more constants and arguments. * ♦ Revision 1.5 94/03/14 08:03:38 larar * No significant changes. * Revision 1.4 94/03/11 21:31:57 larar ♦ Added private data and members. ♦ Revision 1.3 94/03/07 11:29:42 jamesb ♦ Moved passed parameters to the constructor, made called functions virtual, ♦ and made other changes recommended at the inspection. * Revision 1.2 94/02/23 14:23:05 jamesb * Added non-default constructor for timing purposes Revision 1.1 94/01/26 15:37:35 jamesb 409 410 * Initial revision * #ifndef _mcPLTAlgorithm_ ♦define _mcPLTAlgorithm_ ♦include "dtObject.h" #include "mgAlgoDefs.h" #include "mgLine.h" #include "cd4000.h" ♦include "diSpecimenType.h" #include "dsCBCResults.h" #include "dsPLTiMeas.h" #include "dsPLToMeas.h" #include "dcCalibrationData.h" ♦include "mcPLTiListMode.h" #include "mcPLToListMode.h" #include "mgCellAlgorithm.h" ♦include "mgPLTiNonlinLS.h" #include "mgPLToNonlinLS.h" // Non-integer constants. // Algorithm. const double mcPLToLoGate = 2.5; // Percent of standard error below // regression line, below which optical // platelet scatter point is considered // noise, 410 411 const double cPLToHiGate = 2.0; // Percent of standard error above // regression line, const double mcPLToUpperPop = 150; // Minimum required size of optical // platelet upper population. const double mcPLTVolPerBin = 0.137; // PLT volume per bin in fL. // Source: Theory of Operation // Marcus Reid const double pltiScaleThresh = 50; // Impedance platelet cell concentration // in K/uL above which display scaling // is to occur. const double mcPLTDelta = 10.0; // Impedance platelet concentration // must be within 'mcPLTDelta' percent // of optical platelet concentration // else flag tripped. // Source: Rod Larue. 411 412 const double mcPLTLRStderrMax = 13.2; // Maximum allowable standard error // of regression in // PLToRegressBandGate() . If the // standard error exceeds this than // this becomes the default value. // This is to enclose ill-defined // optical platelet clusters. // Thresholds for morphology flagging. // Source: Young Ran Kim, 10/31/94. const double pltlo = 50; // Low platelets. K/uL. const double plthi = 600; // High platelets, K/uL. const double pdwhi = 13.0; // High platelet distribution // width, %. const double mpvhi = 10.0; // High platelet mean volume, fL. // Range limits for accuracy. Source: 'acceptable range', Hematology // Specs 10/28/94. const double pltRangeLo = 0.0; // Platelet concentration low range, 412 413 // K/uL. const double pltRangeHi = 2000.0; // Platelet concentration high // range, K/uL. const double mpvRangeLo = 5.0; // Mean platelet volume low range, // fL. const double mpvRangeHi = 18.0; // Mean platelet volume high range, // fL. // • class mcPLTAlgorithm : public mgCellAlgorithm { public: // Data. // IDs for platelet algorithm timing. enum pltalgsection CalcResults, getlnput, paramDefaults, ClassFlagDefaults, getPLTiData, getPLToData, doAlgorithm, doPLTiSparse, doPLTiAnalysis, 413 414 doPLTiAnalysis_hist, pltiProcessNumbers, binCut, CalcPLTiParams, CalcPLTiConc, CalcPLTDist, CalcPLTiShapeParams, setPLTiFlags, doPLToSparse, doPLToAnalysis, pltoNoiseGate, pitoRegressBandGate, pltoRegressBandGate_lsf, pltoRegressBandGate_count, pltoRegressBandGate_tag, pitoFindUpperPopulation, pltoFindUpper_proj , pltoFindUpper_filter, pltoFindUpper_char, CalcPLToParams, SetPLToFlags, sendResults, SendNumResults, SendAlertResults, makeDisplayHist, filter64Bin, SendScatResults, maxalgsection }; // Methods, mcPLTAlgorithm (const diSpecimenType& spectype, const dsPLTiMeas& plti, 414 415 const dsPLToMeas& plto, dsCBCResults& cbcrslt, const dcCalibrationData& cal, int docalc = TRUE, int dotiming = TRUE, int priority = 17); t i ¬ l l Constructor for the class. // Parameters: // spectype: specimen type for the run. // plti: PLT impedance transducer measurement data. // plto: PLT optical transducer measurement data. // cbcrslt: entire set of CBC results, including numerical, alert, // scattergram, and histogram data. // cal: , Dilution and calibration factors. // docalc: sets "calcflag" to TRUE or FALSE, which determines // whether the full set of calculations will be done // for this algorithm. // dotiming: sets "TimeFlag" to TRUE or FALSE, which determines // ' whether timing values will be recorded (default is // TRUE) . // priority: used to set the LynxOS priority for the thread // containing the algorithm operations (default is 17, // prototype priority 11/7/94) . // 415 416 / / virtual -mcPLTAlgorithm( ) ,- // // Destructor for the class -- default action only. // virtual Boolean CalcResults (void) ; // // Calculates the platelet test results from the appropriate transducer // measurements. The numerical and alert results calculated include // all of the platelet-specific results, which are specified in separate // files. Returns whether this algorithm completed successfully. // virtual double GetTiming(int section); // // Returns the results (in seconds) of the run time for the specified // section of the PLT algorithm. // private: 416 417 / / Data- // Algorithm input and transducer measurements, const diSpecimenType& specimentype; const dsPLTiMeas& pltimeas; const dsPLToMeas& pltomeas; dsCBCResults& cbcresults; const dcCalibrationDataSc caldata; Boolean calcflag; // Numerical results. double pLT; // Platelet concentration from impedance // data, cells/uL. double oPLT; // Platelet concentration from optical // data, cells/uL. double pDW; // Impedance platelet distribution // width, %. double mPV; // Mean platelet volume, fL. double pCT; // Platelet crit, %. double iasMean; // Mean of optical platelet IAS values. double pssMean; // Mean of optical paltelet PSS values. double iasCv; // Coefficient of variation of // optical platelet IAS values. 417 418 double pssCv; // Coefficient of variation of // optical platelet PSS values. // Discriminants. // Optical platelets. mgLine* PLToLinRegress; // Linear regression through entire // optical data scatter. mgLine backgroundDisc; // Low PSS gate for background noise. mgLine pltLowerDisc; // Lower regression band gate mgLine pltUpperDisc; // Upper regression band gate mgLine pltRBCDisc; // Gate for upper population. // Impedance platelets. int pltiLoThresh; // Impedance platelet cell histogram // lower threshold bin. int pltiHiThresh; // Impedance platelet cell histogram // upper threshold bin. enum { pssNoiseThresh = 8 },- // Percent of pssdimen below which an // optical platelet scatter point is // considered noise. (20 / 256 ♦ 100) . 418 419 // Source: Fluids group. enum { iasNoiseThresh = 8 }; // Percent of iasdimen below which an // optical platelet scatter point is // considered noise. (20 / 256 * 100) . // Source: Fluids group. // Listmode items. mcPLTiListMode^ pltiLItem; // Pointer to impedance platelet list mode. mcPLToListMode^ pltoLltem; // Pointer to optical platelet list mode. dsListModeMeas ♦ pltiVolArray; // Array of impedance platelet list mode // volume measurements. dsListModeMeas^ pltiTimeArray; // Array of impedance platelet list mode // times between measurements. dsListModeMeas ♦ pltoIasArray; // Array of log ias transducer list mode // measurements, optical platelet. dsListModeMeas ♦ pltoPssArray; // Array of log pss transducer list mode // measurements, optical platelet. dsListModeMeas ♦ pltoTimeArray; // Array of optical 419 420 platelet list mode // times between measurements. unsigned long pltoPltCount; // Number of optical platelet scatter // points ascribed to 'platelet'. unsigned long pltoMcytCount; // Number of optical platelet scatter // points ascribed to 'microcytic rbc' . unsigned long pltoNoiseCount; // Number of optical paltelet scatter // points ascribed to 'noise'. // Algorithm internals. enum {minAllowPLTCount = 50}; // Minimum allowable number of cells // for OK statistics. // Source: Marketing enum {pltiLoModeSearchBin = 16}; // Low bin defining range in which // to search for histogram mode for // display scaling. enum {pltiHiModeSearchBin = 144}; // High bin defining range in which // to search for histogram mode for 420 421 // display scaling. enum {pltoScatSize = 256}; // Square dimension of optical platelet // scatter plot. enum {clockMil = 1000000}; // One million. Used to convert clock() // to seconds for algorithm timing. double timevalues [maxalgsection] ,- // Array of timing values. // Calculation status flags. dsNumericalResult: :NRStatus pltStat; // Enumerated status of pLT calculation. dsNumericalResult: :NRStatus mpvStat; // Enumerated status of mPV calculation. dsNumericalResult: :NRStatus pdwStat; // Enumerated status of pDW calculation. dsNumericalResult: :NRStatus pctStat; // Enumerated status of pCT calculation. dsNumericalResult: :NRStatus opltStat; // Enumerated status of oPLT calculation. dsNumericalResult: :NRStatus iasMeanStat; // Enumerated status of mean IAS calculation. dsNumericalResult: :NRStatus pssMeanStat; // Enumerated status of mean PSS calculation. dsNumericalResult: :NRStatus iasCvStat; // Enumerated status of IAS coefficient of variation. dsNumericalResult: :NRStatus pssCvStat; 421 422 // Enumerated status of PSS coefficient of variation. // Local morphology and status flags. Boolean noPLTiCells; // TRUE if impedance platelet listmode count // below minAllowPLTCount threshold. Boolean noPLToCells; // TRUE if optical platelet listmode count // below minAllowPLTCount threshold. Boolean pltilower; // TRUE if impedance pit has lower region // interference. Boolean pltiupper; // TRUE if impedance pit has upper region // interference. Boolean pltolower; // TRUE is optical pit has lower region // interference. Boolean pltoupper; // TRUE if optical pit has upper region // interference. Boolean pltiEvenTiming; // TRUE if flow/time diagnostic indicates // uniform hardware count rate in // impedance platelet stream. Boolean pltoEvenTiming; // TRUE if flow/time diagnostic indicates // uniform hardware count rate in 422 423 // optical platelet stream. Boolean pdwHiFlag; // TRUE if pdw above internal threshold. Boolean pltLoFlag; // TRUE if optical platelet concentration // below internal threshold. Boolean pltHiFlag; // TRUE if optical platelet concentration // above internal threshold. Boolean mpvHiFlag; // TRUE if mean platelet volume above // internal threshold. Boolean mcPLToMiRBC; // Morph flag. TRUE if microcytic RBCs // present in optical platelet // scatterplot. // Methods- // Level 1. void Getlnput (void) ; // // Directs the initialization of results and retrieval of // measurements. // 423 424 // void DoAlgorithm(void) ; // // Directs the processing of measurements. // void SendResults(void) ; // // Sends to storage all of the required numerical, alert, // and scattergram results for the PLT algorithm. // // Level 2. void ParamDefaults(void) ; // // Initializes the following parameters and sets their status // to 'noCalc' : // PLT, MPV, PDW, PCT, OPLT // // Also fills impedance platelet histogram with zeroes. // void ClassFlagDefaults(void) ; 424 425 / / // Initializes class-specific flags. // void GetPLTiData(void) ; // // Gets impedance platelet listmode data and puts it into local // storage. // void GetPLToData(void) ; / // Gets optical platelet listmode data and puts it into local // storage. // void DoPLTiSparse(void) ; // // Calculates impedance platelet cell concentration for specimens // with low numbers of listmode events (<minAllowPLTCount) . // void DoPLToSparse(void) ; 425 42 6 / / // Calculates optical platelet cell concentration for specimens // with low numbers of listmode events (<minAllowPLTCount) . // Boolean DoPLTiAnalysis (void) ; // // Does the PLT analysis on PLTiListMode objects, generating the // required analytical results and storing them. // // Returns TRUE if operation successful. // Boolean DoPLToAnalysis (void) ; // • // Does the PLT analysis on PLToListMode objects, generating the // required analytical results and storing them. // // Returns TRUE if operation successful. // // Level 3. Boolean PLTiProcessNumbers(const mmHist256& calcHist); 426 427 // • // Get impedance platelet numerical results and alerts. // Arguments: // calcHist: Unprocessed histogram of impedance platelet // volume measurements. // // Return values: TRUE if processing OK. // FALSE otherwise. // void MakeDisplayHist(const mmHist256& plainHist, const Boolean doFilter, const Boolean showDiscrim) ; / // Creates impedance platelet display histogram and puts it into // impedance platelet histogram storage. The histogram is // filtered using the following protocol (from cd3000 precedent) , // if doFilter = TRUE: // // 1. Average every 4 points to create a 64-bin histogram. 11 2 . Filter the 64-bin histogram with 2 passes of a boxcar filter, // 3 bins wide. // 3. Extrapolate back out to 256 bins. // // Arguments: 427 428 // // plainHist: Unfiltered histogram. // doFilter: TRUE if filter is to be applied. // FALSE otherwise. // showDiscrim: TRUE if discriminants are to be displayed. // FALSE otherwise. // void SetPLTiFlags(const Booleanfc algflag); // // Determines whether any of the alert-condition flags enumerated // in "dsAlertResultID" need to be set, indicating abnormalities. // // Arguments: // // algflag: Current algorithm flag. / void PLToNoiseGate(void) ; // // Applies gate to tag electronic noise population in optical // platelet scattergram. // void PLToRegressBandGate(void) ; 428 429 / / // Applies gate to tag noise populations representing cell debris // above and below main optical platelet cluser. // Boolean PLToFindUpperPopulation(double^ proportion); // Searches for and tags population (if any) of a cluster // indicative of microcytic red cells or large platelets in optical // platelet scattergram. // // Argument: // proportion: Proportion of surviving PLT which does not // fall into an upper population. // // Return value: // TRUE if algorithm executed OK // FALSE otherwise. void CalcPLToParams(const double porportion) ,- // // Calculates OPLT and PCT. // // Argument: 429 430 // proportion: Ratio of platelet to (platelet + upper // population) . // void SetPLToFlags(const Boolean& algflag); // // Determines whether any of the alert-condition flags enumerated // in "dsAlertResultID" need to be set, indicating abnormalities. // // Arguments: // algflag: Current algorithm flag. // void SendNumResults(void) ; // // Sends all numerical results for storage and display. // void SendAlertResults(void) ; // // Sends all alert results for storage and display. // void SendScatResults(void) // 430 43 1 // Send all optical platelet histogram results for storage and // display. / // Level 4. void BinCut(const mmHist256& calcHist); // // Performs bin thresholding on impedance platelet histogram. // // Argument: // calcHist: Raw data histogram. // void CalcPLTiParams(const mmHist256& calcHist); // // Calculates PLT, MPV, and PDW. (Impedance parameters. ) // // Argument: // calcHist: Histogram of raw data. // // Updates: Replaced by CalcPLTiConc and CalcPLTDist // 11/28/94. // 431 432 Boolean CalcPLTiConc(const mmHist256& calcHist, const int lowBin, const int hiBin) ; //- // Calculates PLT. // // Arguments: // calcHist: Histogram of raw data. // lowBin: Low bin, inclusive, marking which portion // of the histogram to include. // hiBin: High bin, inclusive, marking which portion // of the histogram to include. // // R Reeqqiuiirreemmeennttss:: // lloowwBBiinn << hiBin. // // R Reettiu -irrnn vvaalluuee:: // T TRRUUEE iiff rrequirements met, FALSE otherwise. //- Boolean CalcPLTDist(const mmHist256& calcHist, const int lowBin, const int hiBin) ; // Calculates MPV and PDW. // // Arguments: // calcHist Histogram of raw data. 432 433 // lowBin: Low bin, inclusive, marking which portion // of the histogram to include. // hiBin: High bin, inclusive, marking which portion // of the histogram to include. // // Requirements: // lowBin < hiBin. // // Return value: // TRUE if requirements met, FALSE otherwise. // void CalcPCT(void) ; // // Calculates PCT based on optical platelet concentration. // void Filter64Bin(const mmHist256& calcHist, const Boolean reflectEnd, const Boolean zeroLeft, mmHist256& filtHist) ; // // Filters a noisy histogram by the following: // 1. Reduce a 256-bin histogram to 64 bins by averaging every // four bins. 433 434 // 2. Filter the 64-bin histogram using two passes of a seven // -bin boxcar filter. // 3. Expand the 64-bin histogram back out to 256 by i // interpolation. // // Arguments: // calcHist: Histogram containing noisy input data. // reflectEnd: TRUE if filtering is done assuming reflection // of endpoints into space before and after // calcHist. // Number of endpoints = 3. // FALSE if zeroes rather than reflections are to // be assumed beyond calcHist. // zeroLeft: TRUE if first 3 points at end are to be zeroed // to eliminate low channel noise artifact. // filtHist: Filtered 256-bin histogram. // // Side effects: // If errors are made in the reduction or interpolation of // histograms, the returned histogram will be identical to // the input histogram and no filtering will have occurred. // 434 43 5 / / Level 5 . void CalcPLTiShapeParams(const mmHist256& calcHist); // // Calculates MPV and PDW based on lognormal regression of // JM Paulus, "Platelet Size in Man", BLOOD 46:321, 1975. // // Argument: // calcHist: Histogram of raw data. // mcPLTAlgorithm (const mcPLTAlgorithm&) ; // Null copy constructor: no copies allowed. mcPLTAlgorithmδc operators (const mcPLTAlgorithmfc) ; // Null assignment operator: no assignment allowed. }; #endif // _mcPLTAlgorithm_ /** * ♦ Copyright 1993 by Abbott Laboratories ♦ Source Code Control System keywords * ♦ NAME: $Source: /home/larar/printme/RCS/mcRBCAlgorithm.cc,v $ 435 43 6 $Locker: larar $ $State: Exp $ $Revision: 2.22 $ $Author: larar $ $Date: 94/11/30 12:26:18 $ Log: .. See below LANGUAGE: LynxOS Cl C++ ♦ DESCRIPTION: * This file contains the implementation for the algorithms * used to perform the RBC differential part of the CBC. * * ....$Log: mcRBCAlgorithm.cc,v $ * Revision 2.22 94/11/30 12:26:18 larar ♦ SCR #513: ♦ Added flow/time diagnostic flag. * * Revision 2.21 94/11/29 10:40:26 larar * SCR #511: ♦ Added CalcRedConc and CalcRedDist to replace CalcRBCParams. Changed ♦ some return types from Boolean to void in cases where Boolean return ♦ was inappropriate or not used. * * Revision 2.20 94/11/21 11:57:44 larar * SCR443: * Remove SCR443 switches and diagnostic switches inadvertently left in. * * Revision 2.19 94/11/17 17:10:06 larar ♦ SCR ^505: ♦ Complete sending of all red cell and hemoglobin numerical 436 437 results and ♦ status in SendNumResults . Implement overrange check on reported ♦ parameters. * ♦ Revision 2.18 94/11/17 10:49:36 larar ♦ SCR443: ♦ Changes to SetRbcFlags and SendAlertResults to accommodate new flags. * Revision 2.17 94/11/01 10:47:27 larar * SCR #467: * Fixed logic of no-patient specimen processing in DoAlgorithm( ) and ♦ DoHGBAnalysis 0. Added additional check of specimen type in * MakeDisplayHist ( ) . * * Revision 2.16 94/10/28 13:02:59 larar * SCR #413: * Added clip to max display of unsealed histograms in MakeDisplayHist () . * * Revision 2.15 94/10/27 11:22:52 larar * SCR #454: * Brought new mcRBCVolPerBin into MCV calculation. * * Revision 2.14 94/10/26 15:19:24 larar * SCR #444: * Changed test of background to test of 'calcflag' in DoAlgorithm() in * order to acommodate fix in mcCBCAlgorithm. * * Revision 2.13 94/10/26 08:04:27 larar * SCR #430: 437 438 * SCR #435: * Put in test for background specimen in DoAlgorithm() . * * Revision 2.12 94/10/25 13:28:36 larar * SCR #430: * SCR ^435: * Added DoRBCSparse() to process low count and background samples. * Expanded arguments of MakeDisplayHist 0. * * Revision 2.11 94/10/14 11:09:42 larar * SCR #413: * Replaced local scaling with mgCellAlgorithm: :ScaleDisplayHist () in * MakeDisplayHist{) . * * Revision 2.10 94/10/13 14:31:11 larar * SCR #335: * Update constructor arguments and parameter equations for new * dcCalibrationData interface. * * Revision 2.9 94/10/11 14:30:14 larar * SCR #406: ♦ Removed reference dilution ratio check from DoHGBAnalysis, * * Revision 2.8 94/09/30 11:44:38 larar * SCR #370: * Replaced NoData status with NoCalc. * Revision 2.7 94/09/27 17:52:53 larar * SCR #300: * Fixed array index error in assignment of measurement timing array. 438 43 9 * Revision 2.6 94/09/26 14:08:04 larar * SCR #300: * ml47 R4. Removed globals from argument lists. * * Revision 2.5 94/09/23 08:19:14 larar * SCR #300: * Removed extraneous globals and reorganized flagging and numerical * results to reflect status marker changes. * Revision 2.4 94/09/09 13:21:26 larar * SCR #303: * Change HGB concentration calculation to explicit calculation because * mgCellAlgorithm: Concentration does not deal with non- stream data. * * Revision 2.3 94/09/09 10:19:11 larar * SCR #303: ♦ Changes to accommodate gated/ungated switch in mgCellAlgorithm: : * Concentration. * * Revision 2. 2 94/09/08 13 : 16 : 34 larar * SCR #303 : * Changed arguments to mgCellAlgorithm: Concentration. * * Revision 2.1 94/09/01 10:41:47 larar * SCR #300: * Replaced nonlinear least squares in RBCProcessNumbers with bin * thresholding. * Added method BinCut for bin thresholding. * Rewrote CalcRBCParams to accommodate bin thresholding. 439 440 * Revision 2.0 94/08/19 15:20:29 larar * SCR #252: * Code redesigned for greader modularity. * * Revision 1.36 1994/07/22 12:10:56 larar * SCR #225: * Added calibration and dilution factors to constructor arguments. * * Revision 1.35 94/07/22 10:35:26 larar * SCR #118: * Changes made after redesign review. * Removed maxrbccells, muchoCells. * ♦ Revision 1.34 94/07/21 16:13:41 larar * SCR #118: * Changes made after redesign review. * Included mgConvergMet.h to access ReportStats structure. * Converted nonlinear least squares fitting arguments to ReportStats * structure elements in DoRBCAnalysis. * * Revision 1.33 94/07/21 07:43:43 larar * SCR #237: * Take out extraneous printfs. * * Revision 1.32 94/07/20 ' 17:53:15 larar * SCR #237: * Adjusted units conversion factors for hemoglobin parameter calculations. * * Revision 1.31 94/07/20 08:46:19 larar * SCR #219: * Pu explicit casts on several variables written to InternalLog in order 440 441 ♦ to silence new compiler warnings. ♦ SCR #239: ♦ Fixed histogram resolution at mgMaxImpedMeas / pltihistsize. ♦ ♦ Revision 1.30 94/07/18 18:03:52 larar ♦ SCR #222: ♦ Built file ID into binary using RCSid. * * Revision 1.29 94/07/07 14:50:45 larar ♦ SCR #118: ♦ Added processing of array of fitted lineshapes in CalcResults () and ♦ DoRBCAnalysis ( ) . ♦ Revision 1.28 94/06/28 17:08:54 larar ♦ SCR #204: ♦ Changed algorithms to use new mcRBCListMode class (formerly used mcRedCe. * ♦ Revision 1.27 94/06/27 13:40:51 larar ♦ SCR #194: ♦ Ongoing debugging of sparse data handling. ♦ Fixed casts in display histograms. ♦ Added more InternalLogs. ♦ SCR #208: ♦ Replaced the hardware counts used in the calculations and storage with ♦ dsCountData.FinalCount ( ) . ♦ ♦ Revision 1.26.1.1 94/06/20 22:58:13 larar ♦ SCR #194: ♦ Ongoing debugging of sparse data handling. Fixed casts in display ♦ histograms. 441 442 * Revision 1.26 94/06/17 08:59:51 larar * SCR #194: * DoRBCAnalysis: Fixed possible index error in creation of display * histogram under circumstances of zero data. * * Revision 1.25 94/06/15 22:47:41 larar * SCR #194: * Added flags for abundant and absent data and reorganized flagging and * status structures. * * Revision 1.24 94/06/14 12:14:15 larar * SCR #185: * Added low pass filtering of RBC display histogram. Quartic filter, cutoff * = 0.15 ♦ Nyquist. * SCR #188: * Used dsRBCHist.MaxCount to scale RBC display histogram. * SCR #191: * Added cieling for the number of mcRedCell instances read from listmode. * * Revision 1.23 1994/06/09 00:26:02 larar * No major changes. * * Revision 1.22 1994/06/09 00:23:49 larar * SCR #172: ♦ Rescaled result histograms to point resolution of 256; max = 255. * * Revision 1.21 1994/06/07 22:07:40 larar * SCR #171: ♦ Added explicit divisor checks to all expressions with 442 443 divides. ♦ Removed conditional sends of results and made them automatic. * * Revision 1.20 1994/06/07 00:22:38 larar ♦ SCR #170: ♦ Added check for zero peak in histogram, DoRBCAnalysis0 * ♦ Revision 1.19 1994/06/02 14:30:47 larar ♦ Permitted stuffing of histogram results for sparse data * ♦ Revision 1.18 1994/06/02 20:04:35 larar ♦ Added checks for return value of mmHist256.PeakO . * ♦ Revision 1.17 1994/05/31 18:54:48 larar ♦ SCR #156: ♦ Added dtlnternalLog messages. * ♦ Revision 1.16 1994/05/25 21:09:39 larar ♦ Fixed deletes again. ♦ Revision 1.15 1994/05/25 13:40:29 larar ♦ Removed 'delete' in CalcResults which could cause memory leak. * ♦ Revision 1.14 1994/05/24 00:38:46 larar ♦ SCR #149: ♦ Changed maxrbccells from 50OK to 5OK. ♦ Added some measurement timing checks. * ♦ Revision 1.12 1994/05/19 15:26:18 larar ♦ SCR #145: ♦ Changed casts to suppress warnings. * Revision 1.11 1994/05/12 19:59:23 larar 443 444 * Removed includes of dsNumericalResultlD.h and dsAlertResultID.h in * accordance with SCR 136. * * Revision 1.9 1994/05/12 18:08:58 larar * Split SetFlags into SetRbcFlags and SetHgbFlags. * Added status and morphology flags. * Added status processing. * * Revision 1.8 1994/05/05 20:47:32 larar * Changed IDs to match DSOS T3 code. * MT3 label. * * Revision 1.6 94/04/08 19:21:52 larar * Post-inspection changes. * Removed platelet-related arguments from constructor. * Added dynamic allocation of data in CalcResults0. * Reorganized flagging structures. * Replaced data validity checks. * Removed limit sets from SetFlags() . * Removed SendHistResults() and GetRBCData() . * Revision 1.5 94/03/25 15:06:42 larar Fleshed out pseudocode. Revision 1.4 94/03/22 07:52:29 larar Changed CalcRBCResults back to CalcResults for conformity with CBCAlgorithm Revision 1.3 94/03/21 14:57:13 larar Changed CalcResults to CalcRBCResults Revision 1.2 94/03/14 08:04:04 larar No significant changes. 444 445 Revision 1.1 94/03/11 09:59:36 larar Initial revision // Revision 1.1 1994/03/11 17:26:23 larar // Initial revision // ♦include <time.h> ♦include <math.h> ♦include "mcRBCAlgorithm.h" ♦include "dtInternalLog.h" ♦include "mgConvergMet.h" // Internal diagnostics.— static const char^ const RCSid = "$Header: mcRBCAlgorithm.ccv 2.22 94/11/30 12:26:18 larar Locked $"; static const char ♦ SourceFileName = FILE ; //♦define TIMEDIAG // If defined: writes timing information to 'rbcdiag.txt' //♦define SPOTDIAG // If defined: writes nonspecific info to 'rbcspot.txt'. / /===========================================================: mcRBCAlgorithm: :mcRBCAlgorithm (const diSpecimenType& spectype, const dsRBCMeas& rbc, const dsHGBMeas& hgbr, 445 446 const dsHGBMeas& hgbs, dsCBCResults&c cbcrslt, const dcCalibrationData& cal, int docalc, int dotiming, int priority) : specimentype (spectype), rbcmeas (rbc) , hgbrmeas(hgbr) , hgbsmeas(hgbs) , cbcresults (cbcrslt) , caldata(cal) , calcflag (docalc) // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ,- ilog « Line( LINE ) « "Top of mcRBCAlgorithm constructor. " « Flush; if (calcflag == FALSE) { ilog « Line( LINE ) « "Constructor, calcflag FALSE' « Flush; } ilog « Line( LINE ) « "Constructor. Specimen type " « specimentype.Type0 « Flush; // Internal switches, 446 447 SetTimeFlag ( (Boolean)dotiming) ; SetPriority (priority) ; mcRBCAlgorithm: :-mcRBCAlgorithm ( ) { Boolean mcRBCAlgorithm: :CalcResults (void) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of CalcResults." « Flush; // Utility variables, unsigned long i; Boolean gotData = FALSE; // Variables indicate if major sections Boolean didAlgo = FALSE; // were done. Boolean sentRes = FALSE; 447 448 // Initializations // Initialize algorithm section timing, for (i = 0; i < maxalgsection; i++) { timevalues[i] = 0.0; } // Start clock. long startclock, endclock; startclock = clockO; long start2, end2; // Time calls by bracketing them. // Initialize results and flags, and fetch measurements. start2 = clock() ; Getlnput() ; end2 = clockO ,- timevalues[getlnput] = (double) (end2 - start2) / clockMil; gotData = TRUE; // Do analysis. start2 = clock() ; DoAlgorithm() ; end2 = clock() ; timevalues[doAlgorithm] = (double) (end2 - start2) / 448 449 clockMil; didAlgo = TRUE; // Send results start2 = clock() ; SendResults () ; end2 = clock() ; timevalues[sendResults] = (double) (end2 - start2) / clockMil; sentRes = TRUE; // Clean up. delete rbcLItem; // Release memory for rbc list mode data. delete [] rbcVolArray; delete [] rbcTimeArray; ilog « Line( LINE ) « "CalcResults. End." « Flush; // End clock. endclock = clockO; timevalues[calcResults] = (double) (endclock - startclock) / clockMil; // Print diagnostics to external file. 449 450 ♦ifdef TIMEDIAG FILE *diag = fopen( "rbctimes.txt", "a" ) ; fprintf (diag, "Getlnput %6.3f\t", timevalues [getlnput] ) ; fprintf (diag, "ParamDefaults %6.3f\t", timevalues [paramDefaults] ) ; fprintf (diag, "ClassFlagDefaults %6.3f\t", timevalues [ClassFlagDefaults] ) ; fprintf (diag, "GetRBCData %6.3f\t", timevalues [getRbcData] ) ; fprintf (diag, "GetHGBData %6.3f\t" , timevalues [getHgbData] ) ; fprintf (diag, "DoAlgorithm %6.3f\t" , timevalues [doAlgorithm] ) ; fprintf (diag, "DoRBCSparse %6.3f\t", timevalues [doRbcSparse] ) ; fprintf(diag, "DoRBCAnalysis %6.3f\t", timevalues [doRbcAnalysis] ) ; fprintf(diag, "DoRBCAnalysis (hist) %6.3f\t", timevalues[doRbcAnalysis_hist] ) ; fprintf (diag, "RBCProcessNumbers %6.3f\t", timevalues [rbcProcessNumbers] ) ; fprintf(diag, "BinCut %6.3f\t" , timevalues[binCut] ) ; 450 451 fprintf (diag, "CalcRBCParams %6.3f\t" , timevalues [calcRbcParams] ) ; fprintf (diag, "SetRbcFlags %6.3f\t", timevalues [SetRbcFlags] ) ; fprintf (diag, "DoHGBAnalysis %6.3f\t", timevalues [doHgbAnalysis] ) ; fprintf (diag, "SendResults %6.3f\t", timevalues [sendResults] ) ,- fprintf (diag, "SendResults_hist %6.3f\t" , timevalues [sendResults_hist] ) ; fprintf (diag, "SendNumResults %6.3f\t" , timevalues [SendNumResults] ) ; fprintf (diag, "SendAlertResults %6.3f\t" , timevalues [SendAlertResults] ) ; fprintf (diag, "MakeDisplayHist %6.3f\n" , timevalues [makeDisplayHist] ) ; fclose (diag) ; #endif return(gotData ScSc didAlgo && sentRes); } / /=================================================== double mcRBCAlgorithm: :GetTiming (int section) { 451 452 // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of GetTiming." « Flush; if (section <= maxalgsection) { return(timevalues[section] ) ; } else return(0.0); } void mcRBCAlgorithm: :Getlnput() { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of Getlnput." « Flush; // Clock items. long startclock, endclock; // Set red blood cell and hemoglobin results to initial defaults. 452 453 startclock = clockO; ParamDefaults( ) ; endclock = clockO; timevalues[paramDefaults] = (double) (endclock - startclock) / clockMil; // Initialize class-specific flags. startclock = clockO; ClassFlagDefaults() ; endclock = clockO; timevalues[ClassFlagDefaults] = (double) (endclock - startclock) / clockMil; // Get RBC ListMode data and check initial conditions. startclock = clockO; GetRBCData() ; endclock = clock() ; timevalues[getRbcData] = (double) (endclock - startclock) / clockMil; // Get HGB data and check initial conditions. startclock = clockO; GetHGBDataO ; endclock = clockO; timevalues[getHgbData] = (double) (endclock - startclock) / clockMil; 453 454 void mcRBCAlgorithm: :DoAlgorith 0 { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of Getlnput." << Flush; // Clock items, long startclock, endclock, startclock2, endclock2; // Red blood cell algorithm. startclock2 = clockO; DoRBCAnalysis() ; endclock2 = clockO; timevalues[doRbcAnalysis] = (double) (endclock2 startclock2) / clockMil; // Hemoglobin algorithm. if (noHGBVals == FALSE) { startclock = clockO; DoHGBAnalysis() ; 454 455 endclock = clock(),- timevalues[doHgbAnalysis] = (double) (endclock - startclock) / clockMil; } } void mcRBCAlgorithm: :SendResults (void) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) << "Top of SendResults." « Flush; // Clock items. long startclock, endclock; // Send the numerical results to storage. startclock = clockO; SendNumResults () ; endclock = clockO; timevalues[SendNumResults] = (double) (endclock startclock) 455 456 / clockMil; // Send the alert results to storage. startclock = clockO; SendAlertResults ( ) ; endclock = clockO; timevalues [SendAlertResults] = (double) (endclock startclock) / clockMil; // Send display histogram. double resol; unsigned short rbchistsize = cbcresults.RBCHist () .Size 0 ; if (rbchistsize > 0) resol = mgMaxImpedMeas / rbchistsize; else resol = 1; startclock = clockO; mmHist256 displayHist (rbcVolArray, listcount, resol); endclock = clockO; timevalues[sendResults_hist] = (double) (endclock - startclock) / clockMil; if ( (noRBCCells == FALSE) ScSc (calcflag == TRUE)) { startclock = clockO; MakeDisplayHist (displayHist, TRUE, // Filter. 456 457 TRUE) ; // Show discrims. endclock = clockO; timevalues[makeDisplayHist] = (double) (endclock - startclock) / clockMil; } else { startclock = clockO; MakeDisplayHist(displayHist, FALSE, FALSE) ; endclock = clockO; timevalues[makeDisplayHist] = (double) (endclock - startclock) / clockMil; } } void mcRBCAlgorithm: :ParamDefaults0 { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of ParamDefaults." « Flush; // Initialize calculated parameters. rBC = 0.0; 457 458 rDW = 0.0, mCV = 0.0, hGB = 0.0; mCH = 0.0; mCHC = 0.0; hCT = 0.0; listcount = 0.0; hGBrNumMeas = 0.0; hGBsNumMeas = 0.0; hGBrMean = 0.0; hGBsMean = 0.0; hGBrCV = 0.0; hGBsCV = 0.0; // Initialize status to noCalc rbcStat = dsNumericalResul ::NoCalc; rdwStat = dsNumericalResult::NoCalc; mcvStat = dsNumericalResult: :NoCalc; hgbStat = dsNumericalResult: :NoCalc; mchStat = dsNumericalResult::NoCalc; mchcStat = dsNumericalResult::NoCalc; hctStat = dsNumericalResul : :NoCalc; hgbrMeanStat = dsNumericalResult::NoCalc; hgbsMeanStat = dsNumericalResult::NoCalc; hgbrCvStat = dsNumericalResult::NoCalc; hgbsCvStat = dsNumericalResult: :NoCalc; // Initialize display histogram. unsigned short i; ford = 0; i < cbcresults.RBCHist ().Size () ; i++; { 458 459 cbcresults.RBCHist O [i] = (dsHistCount) 0; } } void mcRBCAlgorithm: :ClassFlagDefaults (void) { dtlnternalLog ilog(SourceFileName) ; ilog << Line( LINE ) << "Top of ClassFlagDefaults." « Flush; // Set flags rbcSinglePeak = TRUE; rbcEvenTiming = FALSE; noRBCCells = FALSE; noHGBVals = FALSE; / /= void mcRBCAlgorithm: :GetRBCData( ) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of GetRBCData." « Flush; 459 460 // Set up listmode data arrays. rbcVolArray = new dsListModeMeas [1] ; rbcTimeArray = new dsListModeMeas [1] ; // Get listmode items. listcount = rbcmeas.List 0 -NumberCells 0 ; // Number of listmode events. rbcLIte = new mcRBCListMode(rbcmeas.List () ) ,- // Listmode object. rbcLItem->Resolution(dsRBCListMode: :VOL,0) ; //Set up zero bit shift. rbcLItem->Resolution(dsRBCListMode: :TIME,0) ; // Check number of cells and flag if too low. if (listcount < minAllowRBCCount) { ilog « Line ( LINE ) « "GetRBCData. Too few cells." « Flush; noRBCCells = TRUE; } // Get listmode data and store. // Regardless of listmode size. unsigned long il; delete [] rbcVolArray; 460 461 delete [] rbcTimeArray; rbcVolArray = new dsListModeMeas [listcount] ; rbcTimeArray = new dsListModeMeas [listcount - 1] ; for (il = 0; il < listcount; il++) { rbcVolArray[il] = rbcLItem->CellMeas (il, dsRBCListMode: :VOL) ; } fordl = 1; il < listcount; il++) { rbcTimeArray[il - 1] = rbcLItem->CellMeas (il, dsRBCListMode: :TIME) rbcLltem- >CellMeas(il - 1, dsRBCListMod e: :TIME) ; } // Internal logs. ilog « Line( LINE ) « "GetRBCData. Dilution " « rbcmeas.Count ( ) .Dilution( ) « Flush; ilog « Line ( LINE ) « "GetRBCData. Flow rate " « rbcmeas.Count ( ) .FlowRate( ) « Flush; ilog « Line( LINE ) « "GetRBCData. Meas time " « 461 462 rbcmeas.Count () .FinalTime() « Flush; ilog « Line( LINE ) « "GetRBCData. Final Count (hw count) « rbcmeas.Count () .FinalCount () « Flush; void mcRBCAlgorithm: :GetHGBData() { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of GetHGBData." « Flush; // Get data items. unsigned long hgbscount = hgbsmeas.List() .NumberCells0 ; unsigned long hgbrcount = hgbrmeas.List() .NumberCells0 ; // Check initial conditions. if ((hgbscount <= 0) II (hgbrcount <= 0)) { noHGBVals = TRUE; } 462 463 ilog << Line( LINE ) « "GetHGBData. Number of sample meas " « hgbscount << Flush; } void mcRBCAlgorithm: :DoRBCSparse0 { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of DoRBCSparse." « Flush; // Clock items. long startclock, endclock; // Set threshold values to defaults. rbcLoThresh = 0; rbcCountThresh = 0; rbcHiThresh = 255; // Report concentration based on entire listmode. // No coincidence correction. Boolean concFlag = TRUE; if ( (rbcmeas.Count() .FlowRate0 > 0.0) 463 464 ScSc (rbcmeas.Count () .Dilution0 > 0.0) ScSc (rbcmeas.Count 0.FinalTime() > 0.0) ) { concFlag = Concentration(FINAL, rbcmeas.Count ( ) , rBC, rbcStat, 1, 0.000001, caldata.CalFactor (dcCalibrationData: :RBC) , caldata.DilFactor (dcCalibrationData: :RBC) ) ; if ((rBC < rbcRangeLo) I I (rBC > rbcRangeHi)) rbcStat = dsNumericalResult: :OverRange; ilog « Line ( LINE ) « "CalcRBCSparse. rBC " « rBC « Flush; } // Compose alerts. startclock = clockO; SetRbcFlags (TRUE) ; endclock = clock( ) ; timevalues[SetRbcFlags] = (double) (startclock endclock) / clockMil; } void mcRBCAlgorithm: :DoRBCAnalysis () 464 465 { // Internal diagnostics, dtlnternalLog ilog(SourceFileName) ; ilog « Line ( LINE ) « "Top of DoRBCAnalysis." « Flush; // Clock items. long startclock, endclock; // Declare histograms. startclock = clockO; unsigned long rbchistsize = cbcresults.RBCHist 0.Size0 ; double resol; if (rbchistsize > 0) resol = mgMaxImpedMeas / rbchistsize; else resol = 1; mmHist256 calcHist (rbcVolArray, // Histogram for calculations. listcount, resol) ; endclock = clockO; timevalues[doRbcAnalysis_hist] = (double) (endclock - startclock) / clockMil; // Get numerical results and alerts. 465 466 startclock = clockO; RBCProcessNumbers(calcHist) ; endclock = clockO; timevalues[SetRbcFlags] = (double) (endclock -startclock) / clockMil; // Compose alerts. startclock = clockO; SetRbcFlags (TRUE) ,- endclock = clockO; timevalues[SetRbcFlags] = (double) (endclock - startclock) / clockMil; } / /============================================================ void mcRBCAlgorithm: :DoHGBAnalysis0 { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of DoHGBAnalysis." << Flush; // Clock items. 466 467 long startclock, endclock; // Utility variables. Boolean hgbDatFlag = TRUE; // Flag for validity of input data. // TRUE if input data OK. Boolean hgbAlgFlag = TRUE; // Flag for validity of algorithm // processing. // TRUE if algorithm processing OK. // Local constants const double mch_units_conv = 10.0; // RBC in M/uL. //HGB in g/dL. //MCH in pg. const double hct_units_conv = 0.001; // RBC in M/uL. //MCV in fL. //HCT in %. const double mchc_units_conv = 100.0; // HGB in g/dL. //HCT in %. 467 468 // Variables for statistics. double refsum = 0; double sampsum = 0; double refsum2 = 0; double sampsum2 = 0; if (noHGBVals == FALSE) { ilog « Line( LINE ) « "DoHGBAnalysis. Getting HGB counts." « Flush; for (unsigned long i = 0; i < hgbsmeas.List() .NumberCells0 ; i++) { sampsum += *hgbsmeas.List() .CellMeas(i) ; sampsum2 += ( ♦ hgbsmeas.List0.CellMeasd) ) ♦ (*hgbsmeas.List0.CellMeasd) ) ; } for (i = 0; i < hgbrmeas.List0.NumberCells0 ; i++) { refsum += ♦ hgbrmeas.List() .CellMeas(i) ; refsum2 += (*hgbrmeas.List0.CellMeas(i) ) ♦ ( ♦ hgbrmeas.List0.CellMeas(i) ) ; } ilog « Line( LINE ) « "DoHGBAnalysis. refsum " « (double)refsum « " sampsum " « (double)sampsum « Flush; if ((sampsum > 0.0) 468 469 ScSc (refsum > 0 . 0 ) ) { // Calculate hemoglobin concentration (HGB). Boolean concflag; // Returns TRUE if calculation // of concentration OK. hGB = log(refsum / sampsum) ♦ hgbsmeas.Coun () .Dilution() ♦ mcHgbMolecConst ♦ caldata.CalFactor(dcCalibrationData: :HGB) ♦ caldata.DilFactor(dcCalibrationData: :HGB) ,- if ( (hGB < hgbRangeLo) I I (hGB > hgbRangeHi) ) hgbStat = dsNumericalResult: :OverRange; else hgbStat = dsNumericalResult: :CalcOK; // In g/dL. ilog « Line( LINE ) « "DoHGBAnalysis. HGB in g/dL = " « hGB « Flush; } } // Calculate these only if patient or QC specimen. if ( ( (specimentype.Type( ) == diSpecimenType: :PatientSpecimen) II (specimentype.Type( 469 470 diSpecimenType: :QCSpecimen) ) ScSc (calcflag == TRUE) ScSc (noHGBVals == FALSE) ScSc (noRBCCells == FALSE) ) // Calculate mean cell hemoglobin (MCH) if (rBC > 0.0) { mCH = hGB * mch_units_conv / rBC; // if ((hgbStat == dsNumericalResult: :CalcOK) ScSc (rbcStat == dsNumericalResult: :CalcOK) { mchStat = dsNumericalResult: :CalcOK; } else { mchStat = dsNumericalResult::Suspect; } ilog « Line ( LINE ) « "DoHGBAnalysis. MCH in pg = " « mCH « Flush; } // Calculate hematocrit (HCT). hCT = rBC * mCV * 100.0 ♦ hct_units_conv; if ( (hCT < hctRangeLo) I I (hCT > hctRangeHi)) { hctStat = dsNumericalResult: :OverRange; } 470 471 else if ((rbcStat == dsNumericalResult : :CalcOK) ScSc (mcvStat == dsNumericalResult: :CalcOK) ) { hctStat = dsNumericalResult: :CalcOK; } else { hctStat = dsNumericalResult::Suspect; } ilog << Line ( LINE ) « "DoHGBAnalysis. HCT in % = " « hCT « Flush; // Calculate mean cell hemoglobin concentration (MCHC) . if (hCT > 0.0) { mCHC = hGB ♦ mchc_units_conv / hCT; if ((hgbStat == dsNumericalResult: :CalcOK) ScSc (hctStat == dsNumericalResult: :CalcOK) ) { mchcStat = dsNumericalResult: :CalcOK; } else { mchcStat = dsNumericalResult::Suspect; } ilog « Line( LINE ) « "DoHGBAnalysis. MCHC in g/dL = " « mCHC « Flush; } } 471 472 // Assign number of measurements hGBrNumMeas = hgbsmeas.List () .NumberCells( ) ; hGBsNumMeas = hgbrmeas.List() .NumberCells() ; // Calculate mean of measurements. if (hGBrNumMeas > 0) { hGBrMean = refsum / hGBrNumMeas; hgbrMeanStat = dsNumericalResult: :CalcOK; } if (hGBsNumMeas > 0) { hGBsMean = sampsum / hGBsNumMeas; hgbsMeanStat = dsNumericalResult: :CalcOK; } // Calculate coefficients of variation of numbers of measure // ments. double refSD = 0.0; double samSD = 0.0; if (hGBrNumMeas > 1) { refSD = (hGBrNumMeas * refsum2) - (refsum * refsum) ; refSD /= (hGBrNumMeas) * (hGBrNumMeas - 1); if (refSD > 0) refSD = sqrt(refSD) ; 472 473 } if (hGBsNumMeas > 1) { samSD = (hGBsNumMeas * sampsum2) - (sampsum * sampsum) ; samSD /= (hGBsNumMeas) * (hGBsNumMeas - 1) ; } if (hGBrMean > 0) { hGBrCV = refSD * 100; hGBrCV /= hGBrMean; hgbrCvStat = dsNumericalResult::CalcOK; } if (hGBsMean > 0) { hGBsCV = samSD ♦ 100; hGBsCV /= hGBsMean; hgbsCvStat = dsNumericalResult::CalcOK; } ilog « Line( LINE ) « "DoHGBAnalysis. Ref mean " « hGBrMean « " coeffVar " « hGBrCV « Flush; ilog « Line{ LINE ) « "DoHGBAnalysis. Sample mean " « hGBsMean « " coeffVar " « hGBsCV « Flush; // Set morphology flags. startclock = clockO; hgbDatFlag = ! (noHGBVals) ; 473 474 SetHgbFlags (hgbAlgFlag, hgbDatFlag) ; endclock = clockO; timevalues[SetHgbFlags] = (double) (endclock - startclock) / clockMil; } void mcRBCAlgorithm: :RBCProcessNumbers(const mmHist256& calcHist) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of RBCProcessNumbers" « Flush; // Clock items. double startclock, endclock; // Check measurement timing. if ( (specimentype.Type() == diSpecimenType: :PatientSpecimen) II (specimentype.Type() == diSpecimenType: :QCSpecimen) { rbcEvenTiming = FlowTimeDiag(rbcmeas.Count()) ; ilog « Line( LINE ) « "RBCProcessNumbers. rbcEvenTiming " « rbcEvenTiming 474 475 << Flush ; } // Find discriminants. if ( ( (specimentype.Type( ) == diSpecimenType: :PatientSpecimen) I I (specimentype.Type ( ) == diSpecimenType: :QCSpecimen) ) ScSc (noRBCCells == FALSE) ScSc (calcflag == TRUE) ) { startclock = clockO; BinCut (calcHist) ; endclock = clock( ) ,- timevalues[binCut] = (double) (endclock startclock) / clockMil; } else { // Threshold defaults. rbcLoThresh = 0; rbcHiThresh = 255; rbcCountThresh = 0; } // Parameter calculations, // RBC, 475 476 Boolean concFlag = TRUE; // Flag for concentration calculation. if ( (noRBCCells == TRUE) I I (calcflag == FALSE)) { concFlag = CalcRedConc (calcHist, 0, calcHist.HistRes - 1, FALSE) ; } else { concFlag = CalcRedConc(calcHist, rbcCountThresh, calcHist.HistRes 1, TRUE) ; } if (concFlag == FALSE) { rbcStat = dsNumericalResult::Suspect; } // MCV, RDW. Boolean distFlag = TRUE; // Flag for distributional calculations. if ( ( (specimentype.Type ( ) == diSpecimenType: :PatientSpecimen) I I (specimentype.Type0 == diSpecimenType: ,-QCSpecimen) ) ScSc (noRBCCells == FALSE) 476 477 ScSc (calcflag == TRUE) ) { distFlag = CalcRedDist (calcHist, rbcLoThresh, rbcHiThresh) ; } if (distFlag == FALSE) { mcvStat = dsNumericalResult::Suspect; rdwStat = dsNumericalResul ::Suspect; } } / /============================================================ void mcRBCAlgorithm: :MakeDisplayHist (const mmHist256& plainHist, const Boolean doFilter, const Boolean showDiscrim) { dtlnternalLog ilog(SourceFileName) ; ilog « Line ( LINE ) « "Top of MakeDisplayHist." « Flush; mmHist256 localHist (plainHist) ; // Working copy of histogram. unsigned short iSh; 477 478 // Apply filter. if (doFilter == TRUE) { localHist.SmBinom(l) ; } // Scale and fill result histogram. // Scaling occurs if platelet concentration exceeds a threshold, // or if the specimen type is SRP, // otherwise no scaling is done. Boolean scaleFlag = TRUE; double^ scaledNums = new double [localHist.HistRes] ; double* scaledNums2 = new double [localHist.HistRes] , • fordSh = 0; iSh < localHist.HistRes; iSh++) { scaledNums[iSh] = (double) localHist[iSh] ; } int loSearch = 0; // Search between these for mode. int hiSearch = localHist.HistRes - 1; if (rBC > rbcScaleThresh) { loSearch = rbcLoModeSearchBin; hiSearch = rbcHiModeSearchBin; } if ( (rBC > rbcScaleThresh) I I (specimentype.Type 0 == 478 479 diSpecimenType: :StdRefSpecimen) ) { scaleFlag = ScaleDisplayHist (scaledNums, scaledNums2, cbcresult s.RBCHist ( ) .MaxCount ( ) , loSearch, hiSearch) ; fordSh = 0; iSh < localHist.HistRes; iSh++) { cbcresults.RBCHist 0 [iSh] = (dsHistCount) (scaledNums2 [iSh] ) ; } } else { ilog « Line( LINE ) « "MakeDisplayHist. No scaling done." « Flush; fordSh = 0; iSh < localHist.HistRes; iSh++) { cbcresults.RBCHist 0 [iSh] = (dsHistCount) (MIN(cbcresults.RBCHist () .MaxCount() , localHist [iSh])),- } } // Fill discriminants. if (showDiscrim == TRUE) 479 480 { cbcresults.RBCHist () .Channel (cbcresults.RBCHist () .LowerThresh) = rbcLoThresh; cbcresul s.RBCHist0.Channel(cbcresults.RBCHist () .UpperThresh) = rbcHiThresh; } // Clean up. delete [] scaledNums; delete [] scaledNums2; void mcRBCAlgorithm: :SetRbcFlags (const Boolean& algflag) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of SetRbcFlags." « Flush; // Trip flags that are dependent on rbc section results. if ( algflag == TRUE ) { 480 481 ilog « Line ( LINE ) « "SetRBCResults. RBC calculations OK." « Flush; if { (rBC < rbclo) ScSc (rbcStat == dsNumericalResult::CalcOK) ) { rbcLoFlag = TRUE; ilog « Line( LINE ) « "SetRBCFlags. rbcLoFlag set." « Flush; } if ( (rBC > rbchi) ScSc (rbcStat == dsNumericalResult::CalcOK) ) { rbcHiFlag = TRUE; ilog « Line( LINE ) « "SetRBCFlags. rbcHiFlag set." « Flush; } if ( (mCV < mcvlo) ScSc (mcvStat == dsNumericalResult::CalcOK) ) { mcvLoFlag = TRUE; ilog « Line ( LINE ) « "SetRBCFlags. mcvLoFlag set." « Flush; } if ( (mCV > mcvhi) ScSc (mcvStat == dsNumericalResult: -.CalcOK) ) { mcvHiFlag = TRUE; 481 482 ilog << Line ( LINE ) << "SetRBCFlags. mcvHiFlag set." << Flush; } if ( (rDW > rdwhi) ScSc (rdwStat == dsNumericalResult::CalcOK) ) { rdwHiFlag = TRUE; ilog « Line ( LINE ) « "SetRBCFlags. rdwHiFlag set." « Flush; } } else if (algflag == FALSE) { ilog << Line ( LINE ) « "SetRBCResults. RBC calculations bad." « Flush; rbcStat = dsNumericalResult::Suspect; mcvStat = dsNumericalResult: :Suspect; rdwStat = dsNumericalResult: :Suspect; } } / /=====================================================: void mcRBCAlgorithm: :SetHgbFlags (Booleans-. algflag, Boolean& datflag) { // Internal diagnostics. 482 483 dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of SetHgbFlags." << Flush; // Trip flags that are dependent on hgb section results. if ( (datflag == TRUE) && (algflag == TRUE) ) { ilog << Line( LINE ) « "HGB calculations OK." << Flush; if ( (mCH < mchlo) ScSc (mchStat == dsNumericalResult::CalcOK) ) { mchLoFlag = TRUE; ilog « Line( LINE ) « "SetHGBFlags. mchLoFlag set." « Flush; } if ( (mCH > mchhi) ScSc (mchStat == dsNumericalResult::CalcOK) ) { mchHiFlag = TRUE; ilog « Line( LINE ) « "SetHGBFlags. mchHiFlag set." « Flush; } 483 484 if ( (mCHC < mchclo) ScSc (mchStat == dsNumericalResult: .-CalcOK) ) { mchcLoFlag = TRUE; ilog « Line( LINE ) « "SetHGBFlags. mchcLoFlag set." « Flush; } if ( (mCHC > mchchi) ScSc (mchcStat == dsNumericalResult::CalcOK) ) { mchcHiFlag = TRUE; ilog « Line( LINE ) « "SetHGBFlags. mchcHiFlag set." « Flush; } } else if (algflag == FALSE) { ilog « Line( LINE ) « "HGB calculations bad. " « Flush; hgbStat = dsNumericalResult::Suspect; mchStat = dsNumericalResult: .-Suspect; mchcStat = dsNumericalResult::Suspect; hctStat = dsNumericalResult: :Suspect; 484 485 void mcRBCAlgorithm: :SendNumResults(void) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of SendNumResults." « Flush; // Send the numerical results to storage, l i ¬ l t RBC cbcresults.Number0 [dsRBCConc] .Value(rBC) ; cbcresults.Number0 [dsRBCConc] .Stat(rbcStat) ; ilog « Line( LINE ) « "SendNumResults. RBC " « rBC « " status " « rbcStat « Flush; // MCV. cbcresults.Number() [dsMeanCorpuscularVolume] .Value(mCV) ; cbcresults.Number() [dsMeanCorpuscularVolume] .Stat (mcvStat) ; 485 486 ilog « Line( LINE ) « "SendNumResults. MCV " << mCV « " status " « mcvStat << Flush; // RDW. cbcresults.Number0 [dsRBCDistributionWidth] .Value(rDW) ,- cbcresults. umber{) [dsRBCDistributionWidth] .Stat (rdwStat) ; ilog « Line( LINE ) « "SendNumResults. RDW " « rDW « " status " « rdwStat « Flush; // HGB. cbcresults.Number() [dsHGBConc] .Value(hGB) ; cbcresuits. umber() [dsHGBConc] .Stat(hgbStat) ; ilog « Line( LINE ) « "SendNumResults. HGB " « hGB « " status " « hgbStat « Flush; // MCH. cbcresults.Number() [dsMeanCellHGB] .Value(mCH) ; cbcresults.Number() [dsMeanCellHGB] .Stat(mchStat) ; 486 487 ilog « Line( LINE ) « "SendNumResults. MCH " << mCH << " status " << mchStat « Flush; // MCHC. cbcresults.Number0 [dsMeanCellHGBConc] .Value(mCHC) ,- cbcresults.Number() [dsMeanCellHGBConc] .Stat(mchcStat) ; ilog « Line( LINE ) « "SendNumResults. MCHC " « mCHC << " status " « mchcStat « Flush; // HCT. cbcresults.Number0 [dsHematocrit] .Value(hCT) ; cbcresults.Number() [dsHematocrit] .Stat(hctStat) ; ilog « Line( LINE ) « "SendNumResults. HCT " « hCT « " status " « hctStat « Flush; // Derived statistics cbcresults.Number() [dsHGBReferenceMean] .Value(hGBrMean) ,- cbcresults.Number() [dsHGBReferenceMean] .Stat (hgbrMeanStat) ; cbcresults. umber() [dsHGBSampleMean] .Value(hGBsMean) ; 487 488 cbcresults.Number() [dsHGBSampleMean] .Stat(hgbsMeanStat) ; cbcresults.NumberO [dsHGBReferenceCV] .Value(hGBrCV) ; cbcresults.Number0 [dsHGBReferenceCV] .Stat(hgbrCvStat) ,- cbcresults.Number() [dsHGBSampleCV] .Value(hGBsCV) ; cbcresults.Number{) [dsHGBSampleCV] .Stat(hgbsCvStat) ; // Misc. listmode items. // Red cell. cbcresults.Number() [dsRBCListModeSize] .Value( rbcmeas.List0.NumberCells 0 ); cbcresults.Number() [dsRBCListModeSize] .Stat (dsNumericalResult: :CalcOK) ,- cbcresults.Number() [dsRBCUngatedCount] .Value( rbcmeas.Count() .FinalCount 0 ) ; cbcresults.Number() [dsRBCUngatedCount] .Stat (dsNumericalResult: :CalcOK) ; cbcresults.Number0 [dsRBCGatedCount] .Value( rbcmeas.Count() .FinalGatedCount() ) ; cbcresults.Number() [dsRBCGatedCount] .Stat (dsNumericalResult: :CalcOK) ; cbcresults.Number() [dsRBCCountTime] .Value( rbcmeas.Count() .FinalTime() ) ; cbcresults.Number() [dsRBCCountTime] .Stat (dsNumericalResult: :CalcOK) ; cbcresults.Number0 [dsRBCDilution] .Value( rbcmeas.Count() .Dilution0 ) ; 488 489 cbcresults.Number() [dsRBCDilution] .Stat (dsNumericalResult: :CalcOK) ; cbcresults. umber0 [dsRBCFlowRate] .Value( rbcmeas.Count( ) .FlowRate0 ) ,- cbcresults.Number0 [dsRBCFlowRate] .Stat (dsNumericalResult: :CalcOK) ; // Hemoglobin. cbcresults.Number0 [dsHGBNumberReferenceMeas] .Value (hGBrNumMeas) ; cbcresults.Number() [dsHGBNumberReferenceMeas] .Stat( dsNumericalResult::CalcOK) ; cbcresults. umber0 [dsHGBNumberSampleMeas] .Value (hGBsNumMeas) ; cbcresults.NumberO [dsHGBNumberSampleMeas] .Stat( dsNumericalResult: :CalcOK) ; } / /===================================================: void mcRBCAlgorithm: :SendAlertResults(void) { // Internal diagnostics. dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of SendAlertResults." 489 490 « Flush; // Trip general rbc morph flag, if ( (rbcLoFlag) I I (rbcHiFlag) I I (mcvLoFlag) I I (mcvHiFlag) I I (rdwHiFlag) I I (mchLoFlag) I I (mchHiFlag) I I (mchcLoFlag) I I (mchcHiFlag) ) { cbcresults.Alert0 [dsRBCMorphology] .Value( cbcresults.Alert0 [dsRBCMorphology] .Alerted) ; // Trip red cell volume anisocytosis flag. if(rdwHiFlag) { cbcresults.Alert0 [dsRBCVolumeAnisocytosis] .Value cbcresults.Alert() [dsRBCVolumeAnisocytos lerted) ; } // Trip red cell anemia flag. if (rbcLoFlag) { cbcresults.Alert O [dsRBCAnemia] .Value( cbcresults.Alert() [dsRBCAnemia] .Alerted) ,- } 490 491 // Trip red cell polycythemia flag. if (rbcHiFlag) { cbcresults.Alert0 [dsRBCPolycythemia] .Value 1 cbcresults.Alert () [dsRBCPolycythemi a] .Alerted) ; } // Trip rbc microcytic flag. if (mcvLoFlag) { cbcresults.Alert 0 [dsRBCMicrocytic] .Value( cbcresults.Alert() [dsRBCMicrocytic] .Alerted) ; } // Trip rbc macrocytic flag. if (mcvHiFlag) { cbcresults.Alert() [dsRBCMacrocytic] .Value( cbcresults.Alert0 [dsRBCMacrocytic] .Alerted) ; } // Trip flow/time impedance red cell diagnostic. if (!rbcEvenTiming) { cbcresults.Alert() [dsRBCNonuniformFlowRate] .Value( cbcresults.Alert() [dsRBCNonuniformFlowRa te] .Alerted) ,- } // Trip hgb hypochromic flag. 491 492 if ( (mchLoFlag) I I (mchcLoFlag) ) { cbcresults.Alert0 [dsHGBHypochromic] .Value( cbcresults.Alert0 [dsHGBHypochromic] .Alerted) ; // Trip hgb hyperchromic flag. if ( (mchHiFlag) I I (mchcHiFlag) ) { cbcresults.AlertO [dsHGBHyperchromic] .Value( cbcresults.Alert() [dsHGBHyperchromic] .Alerted) ; } / /= void mcRBCAlgorithm: :BinCut(const mmHist256& calcHist) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of BinCut." « Flush; // Find peak location on filtered histogram. mmHist256 filtHist(calcHist) ; filtHist.SmBinom(l) ,- 492 493 // Find peak of histogram excluding first and last bins. unsigned iSh = filtHist.HistRes - 2; int peakBin = maxlndex(filtHist) ; int peakMode = maxValue(filtHist) ; ilog « Line( LINE ) « "BinCut. peak bin " « peakBin « Flush; // Search on either side of peakBin for bins such that histogram // counts = rbcHistThresh ♦ peakMode. Use filtered histogram. // Low threshold. iSh = peakBin; while( (iSh > 0) ScSc ( (double)filtHist[iSh] > rbcHistThresh ♦ peakMode) ) { iSh—-; } rbcLoThresh = iSh; // Count threshold. // Beyond rbcLoThresh: look for additional valley or first zero. // Take the one that is farthest out. int rbcLoVal, rbcFirstZero; 493 494 rbcLoVal = filtHist.Valley(0, rbcLoThresh); iSh = rbcLoThresh; while ( (iSh > 0) ScSc (filtHist [iSh] > 0) ) { iS ~; } rbcFirstZero = iSh; (rbcFirstZero < rbcLoVal) ? (rbcCountThresh = rbcLoVal; : (rbcCountThresh = rbcFirstZero) ; // High threshold. iSh = peakBin; while( (iSh < filtHist.HistRes - 2) ScSc ( (double)filtHist[iSh] > rbcHistThresh ♦ peakMode) ) { iSh++; } rbcHiThresh = iSh; // Trap errors. // In case of error, set thresholds at ends, if (rbcLoThresh > rbcHiThresh) { rbcLoThresh = 0; rbcHiThresh = filtHist.HistRes - 1; } 494 495 void mcRBCAlgorithm: :CalcRBCParams (const mmHist256& calcHist; { dtlnternalLog ilog(SourceFileName) ; ilog « Line ( LINE ) « "Top of CalcRBCParams. " « Flush; double rbcRatio = 0.0; // Non-platelet fraction of histogram. int totalCounts = 0; // Count of entire raw data histogram. int upperCounts = 0; // Count of histogram above count thresh. if ( (rbcmeas.Count () .FlowRate( ) > 0.0) ScSc (rbcmeas.Count 0.Dilution( ) > 0.0) ScSc (rbcmeas.Count 0.FinalTime 0 > 0.0) ) // RBC in MCells / uL. totalCounts = calcHist.GetCount 0 ; upperCounts = calcHist.GetCount (rbcCountThresh, (int) (calcHist.HistRes - 1) ) ; if (totalCounts <= 0) { rbcRatio = 0.0; rbcStat = dsNumericalResult::Suspect; } else { 495 496 rbcRatio = (double) (upperCounts) / (double) (totalCounts) ,- } Boolean concFlag = TRUE; // TRUE if concentration calculation // OK. concFlag = Concentration(FINAL, rbcmeas.Count ( ) , rBC, rbcStat, rbcRatio, (double) 1.0, caldata.CalFactor (dcCalibrationData: :RBC) , caldata.DilFactor (dcCalibrationData: :RBC) ) ; // Apply coincidence correction. rBC = CoincCorrect (rBC, mcRBCSensVol, rbcmeas.Count ( ) .Dilution( ) ) ; // Scale rBC to MCells/uL. rBC *= 0.000001; // Check range. if ( (rBC < rbcRangeLo) I I (rBC > rbcRangeHi) ! rbcStat = dsNumericalResult: :OverRange; // MCV, RDW. // Get distributional statistics on cut 496 497 histogram. // mCV = mean. // rDW = coefficient of variation. double standDev; // Standard deviation, not used. calcHist.GetStats (rbcLoThresh, rbcHiThresh, mCV, standDev, rDW) ; if ( (rDW < rdwRangeLo) I I (rDW > rdwRangeHi) ) rdwStat = dsNumericalResult: :OverRange; else rdwStat = dsNumericalResult::CalcOK; // Scale MCV with volume and calibration factors. mCV = mCV ♦ mcRBCVolPerBin * caldata.CalFactor(dcCalibrationData: :MCV) * caldata.DilFactor(dcCalibrationData: :MCV) ; if ( (mCV < mcvRangeLo) I I (mCV > mcvRangeHi)) mcvStat = dsNumericalResult: :OverRange; else mcvStat = dsNumericalResult::CalcOK; } } Boolean mcRBCAlgorithm: :CalcRedConc (const mmHist256& 497 498 calcHist, const int lowBin, const int hiBin, const Boolean coinCorrFlag) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of CalcRedConc." « Flush; // Initial checks. if (lowBin >= hiBin) return(FALSE) ,- // Histogram ratios. double rbcratio = 0.0; int totalCounts = calcHist.GetCount0 ; int upperCounts = calcHist.GetCount(lowBin, hiBin); if (totalCounts <= 0! { rbcStat = dsNumericalResult::Suspect; } else { rbcratio = (double) (upperCounts) / (double ) (totalCounts ) ; 498 499 // Concentration calculation. Boolean concFlag; if ( (rbcmeas.Count () .FlowRate ( ) > 0.0) ScSc (rbcmeas.Count () .Dilution( ) > 0.0) && (rbcmeas.Count 0.FinalTime0 > 0.0) ScSc (rbcStat != dsNumericalResult::Suspect) ) { concFlag = Concentration(FINAL, rbcmeas.Count ( ) , rBC, rbcStat, rbcratio, (double) 1.0, caldata.CalFactor (dcCalibrationData: :RBC) , caldata.DilFactor (dcCalibrationData: :RBC) ) ; } // Apply coincidence correction. if (coinCorrFlag == TRUE) { rBC = CoincCorrect (rBC, mcRBCSensVol, rbcmeas.Count ( ) .Dilution0 ) ; } // Scale rBC to MCells/uL. 499 500 rBC *= 0.000001; // Check range. if ((rBC < rbcRangeLo) I I (rBC > rbcRangeHi)) rbcStat = dsNumericalResult: :OverRange; // Internal logs. ilog << Line( LINE " ) « "CalcRedConc. rBC in M/uL " « rBC « Flush; return(TRUE) ; } / /========================================================= Boolean mcRBCAlgorithm: :CalcRedDist (const mmHist256& calcHist, const int lowBin, const int hiBin) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of CalcRedDist. " « Flush; // Initial checks. 500 501 if (lowBin >= hiBin) return(FALSE) ; // MPV and PDW calculation. Boolean concFlag; if (rbcmeas.Count () .FlowRate0 > 0.0) ScSc (rbcmeas.Count () .Dilution( ) > 0.0) ScSc (rbcmeas.Count () .FinalTime ( ) > 0.0! double standDev; // Standard deviation, not used. calcHist .GetStats (rbcLoThresh, rbcHiThresh, mCV, standDev, rDW) ; rdwStat = dsNumericalResult::CalcOK; // Scale MCV. mCV = mCV * mcRBCVolPerBin * caldata.CalFactor(dcCalibrationData: :MCV) caldata.DilFactor(dcCalibrationData: :MCV) ; if ( (mCV < mcvRangeLo) I I (mCV > mcvRangeHi) ) mcvStat = dsNumericalResult: :OverRange; else mcvStat = dsNumericalResult::CalcOK; 501 502 // Internal logs. ilog « Line( LINE ) « "CalcRedDist. RDW in % " « rDW « Flush; ilog « Line( LINE ) « "CalcRedDist. MCV in fL " « mCV « Flush; return(TRUE) ; } ** * ♦ Copyright 1993 by Abbott Laboratories ♦ Source Code Control System keywords * ♦ NAME: $Source: /home/larar/printme/RCS/mcRBCAlgorithm.h,v $ ♦ $Locker: larar $ ♦ $State: Exp $ ♦ $Revision: 2.13 $ * $Author: larar $ ♦ $Date: 94/11/30 12:22:40 $ ♦ Log: .. See below * ♦ LANGUAGE: LynxOS Cl C++ 502 503 * DESCRIPTION: * This file contains the class definition for the algorithms * used to calculate the RBC part of the CBC. * * ....$Log: mcRBCAlgorithm.h,v $ * Revision 2.13 94/11/30 12:22:40 larar * SCR #513: * Renamed uneven timing flag. * * Revision 2.12 94/11/29 10:28:53 larar * SCR #511: * Added CalcRedConc and CalcRedDist. Changed some return types from Boolean * to void where Boolean return was inappropriate or not used. * * Revision 2.11 94/11/17 17:06:54 larar * SCR #505: * Add storage and status for derived statistical results. * * Revision 2.10 94/11/17 10:45:32 larar * SCR443: ♦ Added class constants and updated timing enums. Added flags and * thresholds. * * Revision 2.9 94/10/31 09:56:25 larar * SCR 465: * Change RBC threshold for display scaling from 2.0 M/uL to 1.0 M/uL. * * Revision 2.8 94/10/27 11:22:20 larar * SCR ^454: 503 504 * Changed mcRBCVolPerBin to 0.8 fL per bin. * * Revision 2.7 94/10/25 13:26:56 larar * SCR ^430: * SCR ^435: * Added DoRBCSparse() to process low count and background samples. * Expanded arguments of MakeDisplayHist0. * * Revision 2.6 94/10/21 17:12:09 larar * SCR ^435: * Change number of cells required for listmode analysis from 30 to 50. * * Revision 2.5 94/10/14 11:07:39 larar * SCR #413: * Added threshold and mode search constants for use with * mgCellAlgorithm: :ScaleDisplayHist0. * ♦ Revision 2.4 94/10/13 14:31:51 larar * Update constructor arguments for new dcCalibrationData interface. * * Revision 2.3 94/09/26 14:11:19 larar ♦ SCR ^300: * ml47 R4. Removed globals from argument lists. * * Revision 2.2 94/09/23 08:18:09 larar * SCR ^300: * Removed extraneous globals and reorganized status markers. * * Revision 2.1 94/09/01 10:43:25 larar * SCR ^300: * Added method BinCut for bin thresholding. * Changed arguments to CalcRBCParams to accommodate bin 504 505 thresholding. * ♦ Revision 2.0 94/08/19 15:22:06 larar ♦ SCR #252: * Code redesigned for greater modularity. * ♦ Revision 1.24 94/07/22 12:07:56 larar ♦ SCR #225: ♦ Added calibration and dilution factors to constructor arguments and ♦ storage. * ♦ Revision 1.23 94/07/22 10:33:14 larar ♦ SCR #118: ♦ Changes made after redesign review. ♦ Removed maxrbccells, muchocells. * ♦ Revision 1.22 94/07/21 16:20:47 larar ♦ SCR #118: ♦ Changes made after redesign review. ♦ Removed rbcfitvec. * ♦ Revision 1.21 94/07/18 17:34:42 larar ♦ SCR #219: ♦ Made destructor virtual. * ♦ Revision 1.20 94/07/07 14:47:39 larar ♦ SCR #118: ♦ Added storage for returned array of fitted lineshapes. ♦ ♦ Revision 1.19 94/06/28 17:15:06 larar ♦ SCR #204. ♦ Added SCR number. * ♦ Revision 1.18 94/06/28 17:11:26 larar 505 506 * SCR #204: * Replaced mcRedCell with mcRBCListMode; changed rbcLItem accordingly. * * Revision 1.17 94/06/27 13:29:44 larar * SCR #208: * Added 'rbcevents' to accommodate hardware count. * * Revision 1.16 94/06/15 22:50:39 larar * SCR #194: * Added flags for abundant and absent data and reorganized flagging and * status protocols. * * Revision 1.15 1994/05/23 23:55:26 larar * SCR #149: * Changed array size (enum) of RedCell pointer array from 500K to 50K. * Histogram scaling fixes. * * Revision 1.14 1994/05/19 15:26:47 larar * SCR #145: * Changed some arguments to suppress warnings. * * Revision 1.13 1994/05/12 18:10:35 larar * Split SetFlags into SetRbcFlags and SetHgbFlags. * Added status and morphology flags. * * Revision 1.12 1994/05/05 20:48:43 larar * Minor changes. * MT3 label. * * Revision 1.10 1994/04/12 21:10:15 larar * Added more documentation. * 506 507 * Revision 1.9 94/04/08 19:13:04 larar * Post-inspection changes. * Removed platelet-related include files and arguments. * Removed static arrays and dsos-related constants. * Added storage for data and algorithm flags. * Removed method SendHistResults() . * * Revision 1.8 94/03/25 15:06:58 larar * Added more constants and arguments. * * Revision 1.7 94/03/22 07:53:37 larar * Changed CalcRBCResults back to CalcResults for conformity with CBCAlgorithm * Revision 1.6 94/03/21 14:57:40 larar * Changed CalcResults to CalcRBCResults * * Revision 1.5 94/03/14 08:04:16 larar * No significant changes. ♦ * Revision 1.4 94/03/11 21:04:21 larar * Added private data and members. * * Revision 1.3 94/03/07 11:25:04 jamesb * Moved passed parameters to the constructor, made called functions virtual, * and other changes recommended at inspection. * * Revision 1.2 94/02/23 14:22:10 jamesb * Added non-default constructor for timing purposes. * * Revision 1.1 94/01/26 15:38:19 jamesb * Initial revision * 507 508 #ifndef _mcRBCAlgorithm_ ♦define _mcRBCAlgorithm_ ♦include "dtObject.h" #include "cd4000.h" ♦include "mgAlgoDefs.h" ♦include "mgLine.h" #include "diSpecimenType.h" #include "dsCBCResults.h" ♦include "dsRBCMeas.h" ♦include "dsHGBMeas.h" #include "dcCalibrationData.h" #include "mcRBCListMode.h" ♦include "mgCellAlgorithm.h" ♦include "mgRBCNonlinLS.h" ♦include "mmHist256.h" // Double and float constants, // Algorithm. const double mcRBCSensVol = 5.47521; // Red blood cell channel // sensing volume in uL. // Based on cylindrical // model. const double mcHgbMolecConst = 0.064; // Hgb molecular constant. 508 509 const double mcRBCVolPerBin = 0.8; // Volume of red cell per // histogram bin in fL. const double rbcScaleThresh = 1.0; // Red cell concentration in //M /uL above which display // scaling is to occur. const double rbcTimingHiCVar = 50.0; // High threshold for // coefficient of variation //of time between red cell I I measurements, I I Source: guess, to be I I replaced by info from I I electronics, const double rbcHistThresh = 0.04; I I Fraction of red cell // histogram mode that a count // must be in order to lie // 509 510 outside a threshold (searching // outward from the mode) . // Thresholds for morphology flagging. // Source: Young Ran Kim, 5/5/94 const double rbclo = 3.5; // Low red cell concentration threshold, // M/uL. const double rbchi = 6.3; // High red cell concentration // threshold, M/uL. Source: YRK 11/1/94, const double mcvlo = 80.0; // Low red cell volume threshold, fL. const double cvhi = 100.0; // High red cell volume threshold, fL. const double mchlo = 25; // Low mean cell hemoglobin threshold, // %. const double mchhi = 34; // High mean cell hemoglobin threshold, // %. const double mchclo = 32; // Low mean cell hemoglobin // concentration threshold, %. const double mchchi = 36; // High mean cell hemoglobin // concentration threshold, %. const double rdwhi = 13.5; // High red cell distribution width 510 511 // threshold. // Source: Young Ran Kim 10/31/94. const double hgblo = 11; // Low hemoglobin concentration // threshold, g/dL. // Range limits for accuracy. Source: 'acceptable range', Hematology // Specs 10/28/94. const double rbcRangeLo = 0.00; // Low red cell concentration range, // M/uL. const double rbcRangeHi = 7.50; // High red cell concentration range, // M/uL. const double hgbRangeLo = 1.0; // Low hemoglobin concentration range, I I g/dL. const double hgbRangeHi 23.0; // High hemoglobin concentration range, // g/dL. const double hctRangeLo 0.0; // Low hematocrit range, volume %. const double hctRangeHi 70.0; // High hematocrit range, volume %. const double mcvRangeLo 30.0; // Low red cell volume range, fL. const double mcvRangeHi 200.0; I I High red cell volume range, fL. const double rdwRangeLo 10.0; // Low red cell distribution range, %. 511 512 const double rdwRangeHi = 40.0; // High red cell distribution range, %. class mcRBCAlgorithm : public mgCellAlgorithm { public: // Data. // IDs for algorithm timing. enum rbcalgsection { calcResults, getlnput, paramDefaults, ClassFlagDefaults, getRbcData, getHgbData, doAlgorithm, doRbcSparse, doRbcAnalysis, doRbcAnalysis_hist, rbcProcessNumbers, binCut, calcRbcParams, CalcRedConc, CalcRedDist, SetRbcFlags, doHgbAnalysis, SetHgbFlags, sendResults, 512 513 sendResults_his , SendNumResults, SendAlertResults, makeDisplayHist, maxalgsection // Methods. mcRBCAlgorithm (const diSpecimenType& spectype, const dsRBCMeas& rbc, const dsHGBMeasϋ hgbr, const dsHGBMeas& hgbs, dsCBCResults& cbcrslt, const dcCalibrationDataSc cal, int docalc = TRUE, int dotiming = TRUE, int priority = 17) ; // // Constructor for the class. // // Arguments: // // spectype - specimen type for the run // rbc: RBC impedance transducer measurement data. // hgbr: HGB absorbance transducer measurement data (reference) . // hgbs: HGB absorbance transducer measurement data (sample) . // cbcrslt: entire set of CBC results, including numerical, alert, // scattergram, and histogram data. 513 514 // cal: Calibration and dilution factors. // docalc: sets "calcflag" to TRUE or FALSE, which determines whether // the full set of calculations will be done for this // algorithm. // dotiming: sets "timeflag" to TRUE or FALSE, which determines whether // timing values will be recorded (default is TRUE) . // priority: used to set the LynxOS priority for the thread containing // the algorithm operations (default is 17, prototype // priority 11/7/94) . // virtual -mcRBCAlgorithm (void) ; // // Destructor for the class -- default action only. // virtual Boolean CalcResults(void) ,- / // Calculates the red-cell test results from the appropriate transducer // measurements. The numerical and alert results calculated include // all of the RBC-specific results, which are specified in separate // files. 514 515 // // Returns TRUE if operation successful / virtual double GetTiming (int section) ,- // Returns the results (in seconds) of the run time for the specified // section of the RBC algorithm. // // Argument: // // section: Enum identifying pertinent subsection to be timed. // // private: // Data // Algorithm entry/exit and transducer measurements. const diSpecimenTypeSc specimentype; const dsRBCMeas& rbcmeas; const dsHGBMeasSc hgbrmeas; const dsHGBMeas& hgbsmeas; dsCBCResultsSc cbcresults; const dcCalibrationDataSc caldata; Boolean calcflag; 515 516 // Calculated numerical results. double rBC; // Concentration of RBCs, Mcells/uL double mCV; // Mean RBC cell volume, fL double rDW; // Red cell distribution width, % double hGB; // Hemoglobin concentration, g/dL double mCH; // Mean cell hemoglobin, pg double mCHC; // Mean cell hemoglobin // concentration, g/dL double hCT; // Hematocrit, % double hGBrNumMeas; // Number of hemoglobin reference measures. double hGBsNumMeas; // Number of hemoglobin sample measures. double hGBrMean; // Mean of hemoglobin reference measures. double hGBsMean; // Mean of hemoglobin sample measures. double hGBrCV; // Coeff of variation of hemoglobin // reference measures. double hGBsCV; // Coeff of variation of hemoglobin // sample measures. // Discriminants, unsigned rbcCountThresh; // Threshold bin above which the histogram // counts are used 516 517 to calculated RBC. unsigned rbcLoThresh; // Lower threshold bin for singlet peak. // Used to calculate MCV, RDW. unsigned rbcHiThresh; // Upper threshold bin for singlet peak. // Used to calculate MCV, RDW. // Calculation status flags, dsNumericalResult: :NRStatus rbcStat; // Enumerated status of RBC calculation. dsNumericalResult : :NRStatus hgbStat; // Enumerated status of HGB calculation. dsNumericalResult: :NRStatus mcvStat; // Enumerated status of MCV calculation. dsNumericalResult: :NRStatus mchStat; // Enumerated status of MCH calculation. dsNumericalResult: :NRStatus mchcStat; // Enumerated status of MCHC calculation. dsNumericalResult: :NRStatus hctStat; // Enumerated status of HCT calculation. dsNumericalResult: :NRStatus rdwStat; // Enumerated status of RDW calculation. dsNumericalResult: -.NRStatuε hgbrMeanStat; // Enumerated status of mean reference hemoglobin measurement. dsNumericalResult: :NRStatus hgbsMeanStat; // Enumerated status of mean sample hemoglobin measurement. dsNumericalResult: :NRStatus hgbrCvStat; // Enumerated status of coefficient of variation of reference 517 518 // hemoglobin measurement. dsNumericalResult: :NRStatus hgbsCvStat; // Enumerated status of coefficient of variation of sample // hemoglobin measurement. // Listmode items. mcRBCListMode* rbcLItem; // Pointer to red blood cell list mode. dsListModeMeas* rbcVolArray; // Array of listmode volume measurements. dsListModeMeas ♦ rbcTimeArray; // Array of listmode times between // measurements, unsigned long listcount; // Number of rbc listmode data values. // Algorithm internals. double timevalues [maxalgsection] ,- // Storage for timing results. enum {minAllowRBCCount = 50}; // Minimum allowable number of cells // for OK statistics. // Source: Marketing enum {rbcLoModeSearchBin = 32}; // Low bin defining range in which to // 518 519 search for histogram mode for // display scaling. enum {rbcHiModeSearchBin = 196}; // High bin defining range in which to // search for histogram mode for // display scaling. enum {clockMil = 1000000}; // One million. Used to convert // clockO to seconds for algorithm // timing. // Local status flags Boolean noRBCCells; // TRUE if zero rbc listmode data counts. Boolean noHGBVals; // TRUE if zero hgb measurements made. // Local morphology flags. Boolean rbcSinglePeak; // TRUE if no suspected second peak. Boolean rbcLoFlag; // TRUE if rBC below internal threshold. Boolean rbcHiFlag; // TRUE if rBC above internal threshold. Boolean mcvLoFlag; // TRUE if mCV below internal threshold. Boolean mcvHiFlag; // TRUE if mCV above 519 520 internal threshold. Boolean rdwHiFlag; // TRUE if rDW above internal threshold. Boolean mchLoFlag; // TRUE if mCH below internal threshold. Boolean mchHiFlag; // TRUE if mCH above internal threshold. Boolean mchcLoFlag; // TRUE if mCH below internal threshold. Boolean mchcHiFlag; // TRUE if mCH above internal threshold. Boolean rbcEvenTiming; // TRUE if flow/time diagnostic indicates // uniform hardware count rate in // impedance red cell stream. // Methods- // Level 1. void Getlnput(void) ; // // Directs the initialization of results and retrieval of // measurements. // void DoAlgorithm(void) ; // 520 521 // Directs the processing of measurements // void SendResults (void) ,- // // Sends to storage all of the required numerical, alert and // histogram results for RBC and hemoglobin data. // // Level 2. void ParamDefaults(void) ; // // Initializes the following red blood cell parameters to zero // and sets their status to 'noCalc': // // RBC, RDW, MCV, HGB, MCH, MCHC and HCT. // // Also initializes impedance histogram result to zeroes and // initializes hemoglobin measurement stats. // void ClassFlagDefaults(void) ; // // Initializes class-specific flags. // 521 522 void GetRBCData(void) ,- // // Gets red blood cell listmode data and puts it into local // storage. // void GetHGBData(void) ; // // Gets hemoglobin data and puts it into local storage. // void DoRBCSparse(void) ,- // // Calculates red cell concentration for specimens with low // numbers of listmode events (<minAllowRBCCount) . // void DoRBCAnalysis(void) ,- // // Does the RBC analysis on RedCell objects, generating required // analytical results and storing them. // 522 523 void DoHGBAnalysis(void) ; // // Does the hemoglobin analysis, generating required // analytical results and storing them. // void SendNumResults(void) ,- // // Sends all numerical results for storage and display. // void SendAlertResults(void) ; // // Sends all alert results for storage and display. // void MakeDisplayHist(const mmHist256Sc plainHist, const Boolean doFilter, const Boolean showDiscrim) ,- // // Creates red blood cell impedance display histogram and puts // it into result storage. A single-pass {1,2,1} filter is applied // to the histogram if doFilter = TRUE. The result is scaled 523 524 // to fit the display. // // Arguments: // plainHist: Unfiltered histogram. // doFilter: TRUE if filter is to be applied. // FALSE otherwise. // showDiscrim: TRUE if discriminants are to be displayed. // FALSE otherwise. // // Level 3. void RBCProcessNumbers (const mmHist256Sc calcHist); // // Get red blood cell numerical results and alerts. // Arguments: // calcHist: Unprocessed histogram of red blood cell // volume measurements. // void SetRbcFlags (const BooleanSc algflag); // Determines whether any of the alert-condition flags enumerated // in "dsAlertResultID" need to be set, indicating abnormalities. // // Arguments: // algflag: Current algorithm flag. 524 525 / / void SetHgbFlags (BooleanSc algflag, BooleanSc datflag); // // Determines whether any of the alert-condition flags enumerated // in "dsAlertResultID" need to be set, indicating abnormalities. // // Arguments: // algflag: Current algorithm flag. // datflag: Current data flag. // // Level 4. void BinCut (const mmHist256Sc calcHist); // // Performs bin thresholding on RBC histogram. // // Arguments: // calcHist: Histogram of raw data. // void CalcRBCParams (const mmHist256Sc calcHist); // // Calculates RBC, RDW and MCV. // // Argument: 525 526 // calcHist: Raw data histogram. // // Updates: // 11/28/94 Replaced by CalcRedConc and CalcRedDist. Boolean CalcRedConc (const mmHist256&: calcHist, const int lowBin, const int hiBin, const Boolean coinCorrFlag) ; // Calculates RBC. // // Arguments: // calcHist: Raw data histogram. // lowBin: Low bin, inclusive, marking which // portion of the histogram to include. // hiBin: High bin, inclusive, marking which // portion of the histogram to include. // coinCorrFlag: TRUE if coincidence correction to be // performed, FALSE otherwise. // // Requirements: lowBin < hiBin. // // Returns: TRUE if requirements met, FALSE if not. 526 527 Boolean CalcRedDist (const mmHist256Sc calcHist, const int lowBin, const int hiBin) ; I I - // Calculates RDW and MCV. // // Arguments: // calcHist Raw data histogram. // lowBin: Low bin, inclusive, marking which // portion of the histogram to include. // hiBin: High bin, inclusive, marking which // portion of the histogram to include. // // Requirements lowBin < hiBin. // // Returns: TRUE if requirements met, FALSE if not. // mcRBCAlgorithm (const mcRBCAlgorithmSc) ; // Null copy constructor: no copies allowed. mcRBCAlgorithmSc operator= (const mcRBCAlgorithmSc); // Null assignment operator: no assignment allowed. }; 527 528 #endif // _mcRBCAlgorithm_ /** * * Copyright 1993 by Abbott Laboratories * Source Code Control System keywords * * NAME: $Source: /usr2/home/jamesb/build/m/RCS/mcWBCAlgorithm.cc,v $ * $Locker: jamesb $ * $State: Exp $ * $Revision: 1.36 $ * $Author: jamesb $ * $Date: 94/11/15 14:11:01 $ * Log: .. See below * LANGUAGE: LynxOS Cl C++ * DESCRIPTION: * This file contains the implementation for the algorithms * used to perform the WBC differential part of the CBC. * * ....$Log.- mcWBCAlgorithm.ee,v $ * Revision 1.36 94/11/15 14:11:01 jamesb * SCR 500: * Changed "all" to "ias" in reporting neutrophil mean for IAS. * * Revision 1.35 94/11/14 15:26:51 jamesb * SCR 498: * Added analysis of FL3 histograms for 3 populations, and 528 529 sending results * out to the InternalLog file. * * Revision 1.34 94/11/01 10:51:23 jamesb * SCR 445: * Made further refinements in "FindMGLine" routine for abnorma1 samp1es. * * Revision 1.33 94/10/26 10:15:52 jamesb ♦ SCR 435: * Lowered the minimum number of cells for a full analysis to 50. * SCR 445: * Changed the range and default angles for neutrophil- eosinophil * separations to match change in optics. Changed the "FindMGLine" * routine to handle abnormal prototype samples better. * ♦ Revision 1.32 94/10/18 17:38:14 jamesb * SCR 425: * Added an additional cutout so that the general concentration function * will still calculate concentrations on low-count or background samples. * * Revision 1.31 94/10/18 13:59:57 donp * SCR 390: * Added Blast flag to SetFlags() . Broke out the build of histograms for diag- * nostics and morphology flagging from GetFinalCounts() and incorporated * into a separate function, DoFinalPopEval() . The final WBC populations are * processed in this function as individual populations or as 529 530 combinations of * 2 or more populations. These histograms are then processed in DoStats ( ) , * using a linear function of weighted terms to determine the presence * of blasts. * * Revision 1.30 94/10/17 14:14:04 jamesb * SCR 335: * Changed algorithm interface and calibration-factor usage to match changes * in calibration-data interface. * * Revision 1.29 94/10/13 13:11:37 jamesb * SCR 393: * Changed calls to scattergram discriminants to match change in interface. * SCR 409: * Changed labeling rules so that high-FL3 cells (except NRBCs) are * retained for the rest of the analysis. * * Revision 1.28 94/10/10 16:58:16 jamesb * SCR 389: * Added code to detect resistant RBCs and set flags for this and NRBCs. * New: * Added calls to "Valid" for WBC discriminants so they will be displayed. * * Revision 1.27 94/09/22 11:36:00 jamesb * SCR 354: * Added a limit check for line extension in "FindMGLine". * ♦ Revision 1.26 94/09/07 09:47:17 jamesb 530 531 * SCR 308: * Added calculations for mean and v. for selected measurements for * lymphocyte and neutrophil populations. * * Revision 1.25 94/07/21 15:55:43 jamesb * SCR 225: * Added dil. and cal. factors to interface, and to concentration calculation. * * Revision 1.24 94/07/19 16:19:41 jamesb * SCR 219: * Changed to use "mgPi" instead of "M_PI". * * Revision 1.23 94/07/14 12:29:05 jamesb * SCR 222: * Added RCS ID string. * * Revision 1.22 94/06/29 17:03:29 jamesb ♦ New: * Added all discriminant-line information sent to "Results". * * Revision 1.21 94/06/22 11:31:47 jamesb * SCR 178, 179, 204: * Revised to use new "m^ListMode" classes instead of "m^Cell" classes, and * the cell-type enumeration in "dsCellPopulation.h" . Removed T2-compatibility * definitions (T2 version is not used any more) . * Revision 1.20 94/06/16 16:45:13 jamesb * SCR 194: * Changed "Stat" calls to numerical results for "Suspect" or "NoCalc" cases. 531 532 * Revision 1.19 94/06/14 14:58:25 jamesb * SCR 195: * Added diagnostic printouts to "InternalLog" for WBC concentration * calculations, to look for errors in numbers reported from analyzer. * * Revision 1.18 94/06/09 17:27:48 jamesb * Fixed some problems in calculating absolute concentrations. * * Revision 1.17 94/06/08 14:54:30 jamesb * SCR 156: * Added diagnostic messages sent to "InternalLog" to monitor progress. * * Revision 1.16 94/05/26 14:28:13 jamesb * Restored to T3-compatibility (commented out "T2"). * ♦ Revision 1.15 94/05/23 17:25:14 jamesb * Changed to dynamic allocation for white-cell data; added timing diagnostics. * * Revision 1.14 94/05/19 16:40:06 jamesb ♦ SCR 145: * Added dummy use of "alertresult" to get rid of warning. * Changed some Boolean return values to void, where no real choice exists. * * Revision 1.13 94/05/17 11:54:06 jamesb * Fixed basophil % calculation; modified some search limits. * Restored ability to be T2-compatible, when necessary. * * Revision 1.12 94/05/12 12:47:06 michaelf * Removed references to dsNumericalResultlD.h and 532 533 dsAlertResultlD.h. * ♦ Revision 1.11 94/05/11 17:18:58 jamesb ♦ Re-advanced to T3 compatibility; added numerical calculations (WBC ♦ concentration, etc.) and sending them to dsNumericalResults. * ♦ Revision 1.10 94/05/10 17:21:24 jamesb ♦ Reverted to T2 compatibility to allow running test-harness program for now. * ♦ Revision 1.9 94/05/05 17:15:01 jamesb ♦ Updated to match changes in "T3" version of "d" subsystem and "Point" ♦ definitions; filled in "Setdefaults" function. * ♦ Revision 1.8 94/05/03 10:49:15 jamesb ♦ Filled in the rest of the basic 5-part differential analysis; added ♦ deletion of white-cell array to remove "memory leak" for repeated runs. * ♦ Revision 1.7 94/04/21 16:57:20 jamesb * Added analysis for neutrophils, eosinophils, monocytes, and lymphocytes. * ♦ Revision 1.6 94/04/14 20:09:45 jamesb ♦ Added more analysis functions, and diagnostic data dump to disk file. * ♦ Revision 1.5 94/04/01 13:38:01 jamesb ♦ Added more algorithm calculations in "CalcResults". * ♦ Revision 1.4 94/03/22 10:33:03 jamesb 533 534 * Filled in some calculations in "GetWBCData" and SendWBCResults" . * * Revision 1.3 94/03/07 11:47:00 jamesb * Changed function calls to match changes in class definition; used "set" * instead of assignment in constructor; removed some unused functions. * * Revision 1.2 94/02/23 14:23:53 jamesb * Filled in more detail in code and comment sections. * Revision 1.1 94/01/26 15:35:14 jamesb * Initial revision #include <types.h> #include <timeb.h> ♦include <lsqfit.h> ♦include "dtlnternalLog.h" ♦include "dsWBCMeas.h" ♦include "mcWBCAlgorithm.h" ♦include "mmHist256.h" ♦include "mmScatter.h" static const char^ const RCSid = "$Header: mcWBCAlgorithm.ccv 1.36 94/11/15 14:11:01 jamesb Locked $"; static const char^ SourceFileName = FILE ; // Send results out to diagnostic files, if DIAGS is defined: ♦define DIAGS 534 535 static const unsigned long mincount = 50; static const int smbcount = 3; static const int histmax = mmHist256: :HistRes - 1; static const int maxscat = 255; static const int WR_defval = 100; static const int RD_defval = 45; static const int MG_defval = 11; static const int NE_defval = 22, static const int LM_defval = 140; static const int LN_defval = 50; static const int LB_defval = 90; mcWBCAlgorithm: :mcWBCAlgorithm(const diSpecimenTypeSc spectype, const dsWBCMeasSc wbc, dsCBCResultsSc cbcrslt, const dcCalibrationDataSc cal, int docalc, int dotiming, int priority) : specimentype (spectype) , wbcmeas (wbc) , cbcresults (cbcrslt) , caldata(cal) , calcflag(docalc) { dtlnternalLog log(SourceFileName) ; log << Line ( LINE ) << "Creating WBC algorithm class" « Flush; SetTimeFlag( (Boolean)dotiming) ,- SetPriority(priority) ; } 535 53 6 mcWBCAlgorithm: :-mcWBCAlgorithm() { dtlnternalLog log(SourceFileName) ,- log « Line( LINE ) << "Deleting WBC algorithm class" « Flush; } Boolean mcWBCAlgorithm: :CalcResults(void) { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) << "Entering WBC algorithm 'CalcResults' function" « Flush; struct timeb tm; ftime(&tm) ; double start = tm.time + (double)tm.millitm / 1000; GetWBCData(wbcmeas.List 0 ) ,- ftime(&tm) ; double stop = tm.time + (double)tm.millitm / 1000; timevalues[getdata] = stop - start; ftime(Sctm) ; start = tm.time + (double)tm.millitm / 1000; DoWBCAnalysis() ; ftime(Sctm) ; stop = tm.time + (double)tm.millitm / 1000; timevalues[doanalysis] = stop - start; ftime(&tm) ,- start = tm.time + (double)tm.millitm / 1000; Boolean algstat = SendWBCResults(cbcresults) ; 536 537 ftime (Sctm) ,- stop = tm.time + (double) tm.millitm / 1000; timevalues [sendresults] = stop - start; // Clean up allocated storage space: delete (wbclist) ; delete (MGLine.Point) ; ♦ifdef DIAGS // Print out timing values: FILE* fp = fopenCwbctime.txt", "w"); if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file 'wbctime.txt' .\n") ; } else { fprintf (fp, "Section-time values:\n"); fprintf (fp, "\tGet data: %6.3f sec.\n", GetTiming(getdata) ) ; fprintf (fp, "\tDo analysis: %6.3f sec.\n", GetTiming(doanalysis) ) ; fprintf (fp, "\tSend results: %6.3f sec.\n", GetTiming(sendresults) ) ; fclose (fp) ; } ♦endif log « Line( LINE ) << "Finished WBC analysis; exiting 'CalcResults' function" « Flush; return (algstat) ; } 537 538 double mcWBCAlgorithm: :GetTiming(int section) { if (section < maxalgsect) return (timevalues[section] ) ; else return (0.0); } void mcWBCAlgorithm: :GetWBCData(const dsWBCListModeSc listdata) { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) << "Entering 'GetWBCData' function" « Flush; // Get the listmode count from dsWBCListMode: listcount = listdata.NumberCells 0 ; // Create storage for white-cell data: wbclist = new mcWBCListMode(listdata) ; // Initialize listmode data, setting each cell type to "unknown" : for (unsigned long i = 0; i < listcount; i ++) wbclist->CellPopulation(dsWBCUnknown, i) ; } void mcWBCAlgorithm: :DoWBCAnalysis (void) { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) 538 539 << "Entering 'DoWBCAnalysis' function" « Flush; // Initial validity check: if less than the minimum number of cells, // or if it is a background or SRP specimen type, // set all values to defaults and skip the full analysis: if (listcount < mincount) calcflag = FALSE; if ( ! calcflag) { SetDefaults() ; return; } // Separate the cells into "high"- and "low"-FL3 populations. FindFl3Cells() ; // Separate the "high"-FL3 population into NRBC, fragile- white, and // dead-cell populations, using ALL and PSS. AnalyzeFl3Cells() ; // Find the separation line between the mononuclear and granulocytic // cell groups, using ALL vs. PSS. FindMGLine() ; // Find the separation line between the neutrophils and eosinophils, // using PSS vs. DSS, and label the cells in these two populations. FindNELine() ; // Find the separation lines between lymphocytes and 539 540 monocytes, and // between lymphocytes and stroma, in IAS vs. ALL, and label // the cells in these populations. FindLymphLines() ; // Find the separation lines between lymphocytes and basophils, and // between basophils and "noise", in IAS vs. ALL, and label the cells // in these populations. FindBasoLines() ; // Calculate the total WBC concentration, and the concentration and // percentage of each labeled sub-population of WBCs, and NRBC's. GetFinalCounts(TRUE) ; // Determine whether any of the alert-condition flags enumerated in // "dsAlertResultID" need to be set, indicating abnormalities. SetFlags0 ,- } Boolean mcWBCAlgorithm: :SendWBCResults(dsCBCResultsSc cbcresult) { dtlnternalLog log(SourceFileName) ,- log « Line( LINE ) << "Entering 'SendWBCResults' function" « Flush; // Send the numerical results to storage: 540 541 SendNumResults (cbcresult.Number0 ) ; // Send the alert results to storage: SendAlertResults(cbcresult.Alert() ) ,- // Send the scattergram results to storage: Boolean algstat = SendScatResults(cbcresult.WBCScat ()) ; return (algstat) ; } void mcWBCAlgorithm: :SetDefaults (void) { // Set everything to default values and return: GetFinalCounts(FALSE) ; WRLine.Reset( (double)WR_defval) ,- WR_dflt = TRUE; RDLine.Reset( (double)RD_defval) ; RD_dflt = TRUE; MGLine.Length = 65; MGLine.Point = new mgRealPoint[MGLine.Length] ; for (int i = 0; i < MGLine.Length; i ++) { MGLine.Point[i] .x = i; MGLine.Point[i] .y = MG_defval; } MG_dflt = TRUE; NELine.Reset( (double)NE_defval, 0.0) ; NE_dflt = TRUE; 541 542 LMLine.Reset(0.0, (double)LM_defval) ; LM_dflt = TRUE; LNLine.Reset(0.0, (double)LN_defval) ; LN_dflt = TRUE; LBLine.Reset( (double)LB_defval) ; LB_dflt = TRUE; double bnval = LNLine.Intercept0 + (LMLine.Intercept0 - LNLine.Intercept O / 3; BNLine.Reset(0.0, bnval); BN_dflt = TRUE; arBands = dsAlertResult: :NonAlerted; arBlasts = dsAlertResul : :NonAlerted; arIGs = dsAlertResult: :NonAlerted; arNRBCs = dsAlertResult: :NonAlerted; arRRBCs = dsAlertResult: :NonAlerted; void mcWBCAlgorithm: :FindFl3Cells(void) { // Build up a histogram, in FL3, of all the WBCs: mmHist256 fl3hist; wbclist->Resolution(dsWBCListMode: :FL3, 0) ,- for (unsigned long i = 0; i < listcount; i ++) f13hist.AddCount( (int)wbclist->CellMeas(i, dsWBCListMode: :FL3) ) ; // Smooth this histogram: mmHist256 smhist = fl3hist.SmBinom(smbcount) ; 542 543 // Look for a valley in the histogram for a separation line: int minfl3 = 80; int maxfl3 = 125; int fl3val = smhist.Valley(minf13, maxfl3); // If no valley is found, use a default value: WR_dflt = FALSE; if ((fl3val <= minf13) I I (fl3val >= maxfl3)) { fl3val = WR_defval; WR_dflt = TRUE; } // Set value of white-red discriminant line, based on this valley: WRLine.Reset( (double) f13val) ; // Label everything above this line as "NRBCs", for now: for d = 0; i < listcount; i ++) if ( (wbclist->CellMeas(i, dsWBCListMode: :FL3) ) > fl3val) wbclist->CellPopulation(dsWBCNRBC, i) ; } void mcWBCAlgorithm: :AnalyzeFl3Cells(void) { // Set the "dead-cell" cutoff in PSS, and the discriminant line: int pss_val = RD_defval; RDLine.Reset (0.0, pss_val) ; // Build up a histogram of the "NRBCs" (high-FL3 cells) in ALL: 543 544 mmHist256 allhist; wbclist->Resolution(dsWBCListMode: :ALL, 8) ; for (unsigned long i = 0; i < listcount; i ++) if (wbclist->CellPopulation(i) == dsWBCNRBC) allhist.AddCount ( (int)wbclist->CellMeas d, dsWBCListMode: :ALL) ) ; // Smooth this histogram: mmHist256 smhist = allhist.SmBinom(smbcount) ; // Find the peak in the lower part of this histogram; if this // is too high, change the labels back to "unknown": const int min_all = 25; const int max_all = 125; const int all_val = 75; if (smhist.Peak(min_all, max_all) > all_val) { for (i = 0; i < listcount; i ++) if (wbclist->CellPopulation(i) == dsWBCNRBC) wbclist->CellPopulation(dsWBCUnknown, i) ; } else { // Re-label everything above the "dead" line as "unknown" : wbclist->Resolution(dsWBCListMode: :PSS, 8) ; for (i = 0; i < listcount; i ++) { if ( (wbclist->CellMeas(i, dsWBCListMode: :PSS) > pss_val) ScSc (wbclist->CellPopulation(i) == dsWBCNRBC)) { wbclist->CellPopulation(dsWBCUnknown, i) ,- } 544 545 void mcWBCAlgorithm: :FindMGLine (void) { // Build up a 2-dimensional histogram (64x64 boxes), in ALL vs. PSS, // of all the remaining "unknown" cells: mmScatter hist2d(64, 64); const int max2d = hist2d.Xbins 0 - 1; wbclist->Resolution(dsWBCListMode: :ALL, 6) ; wbclist->Resolution(dsWBCListMode: :PSS, 6) ; for (unsigned long i = 0; i < listcount; i ++) if (wbclist->CellPopulation(i) == dsWBCUnknown) hist2d.AddCount ( (int) (wbclist->CellMeas (i, dsWBCListMode: :ALL) ) , (int) (wbclist->CellMeas (i, dsWBCListMode: :PSS) )) ; // Smooth this histogram with a 3x3 smoothing filter: mmScatter smhist = hist2d.Smooth3 ( ) ; // Find the neutrophil peak (use the default center if no peak is found) : const int n_all = 38; const int n_pss = 22; const int nrange = 10; int min_x = n_all - nrange; int max_x = n_all + nrange; int min_y = n_pss - nrange; int max_y = n_pss + nrange; MG_dflt = FALSE; mglntPoint npeak = smhist.Max(min_x, max_x, min_y, 545 546 max_y) ; if ( (npeak.x <= min_x) I I (npeak.x >= max_x) (npeak.y <= min_y) I I (npeak.y >= max_y) ) { npeak.x = n_all; npeak.y = n_pss; MG_dflt = TRUE; } // Find the monocyte peak, using the location of the neutrophil peak // to find the center to search from; use default, if no peak is found: const int m_all = (int) ( (double)npeak.x * 0.45 + 26.2); const int m__pss = (int) ( (double)npeak.y ♦ 0.16 + 5.3); const int mrange = 5; min_x = m_all - mrange; max_x = MIN((m_all + mrange), max2d) ,- min_y = MAX((m_pss - mrange), 1); max_y = MIN((m_pss + mrange), (npeak.y / 2)); mglntPoint mpeak = smhist.Max(min_x, max_x, min_y, max_y) ; if ( (mpeak.x <= min_x) I I (mpeak.x >= max_x) I I (mpeak.y <= min_y) I I (mpeak.y >= max_y) ) { mpeak.x = m_all; mpeak.y = m_pss; MG_dflt = TRUE; } // Search along the line between these two peaks for a valley; use a // default value if a good one is not found: mglntPoint mn_limit; mn_limit.y = mpeak.y + 2 * (npeak.y - mpeak.y) / 3; 546 547 mn_limit.x = npeak.x + (mpeak.x - npeak.x) / 3; mglntPoint mnval = smhist.Valley(mpeak, mn_limit); int mn_pss = mpeak.y + (npeak.y - mpeak.y) / 3; int mn_all; if (mpeak.x == npeak.x) mn_all = mpeak.x; else { double mnslope = (double) (npeak.y - mpeak.y) / (npeak.x - mpeak.x) ; mn_all = mpeak.x + (int) ( (double) (mnval.y - mpeak.y) / mnslope + 0.5); } if ((((mnval.y - mpeak.y) + (mpeak.x - mnval.x) ) <= 2) I ( ( (mn_limit.y - mnval.y) + (mnval.x - mn_limit.x)) <= 2)) { mnval.x = mn_all; mnval.y = mn_pss; MG_dflt = TRUE; } // Extend the separation line in both directions to the edge of the plot, // looking for the minimum-density path each way: MGLine.Length = max2d + 2; MGLine.Point = new mgRealPoint[MGLine.Length] ; short x = mnval.x; short y = mnval.y; short limit = MIN( (mpeak.x + 5), (max2d - 1) ) ; for ( ; x <= limit; x ++) { MGLine.Point [x] .x = 4 * x; MGLine.Point[x] .y = 4 * y; int sumO = smhist.GetCount(x + 1, y) + 547 548 smhist.GetCount (x + 2, y) ; int sumi = smhist.GetCount (x + 1, y + 1) + smhist.GetCount (x + 2, y + 1) ; int sum2 = smhist.GetCount (x + 1, y + 2) + smhist.GetCount (x + 2, y + 2); if (sumi < sumO) { y ++; if (sum2 < sumi) y ++; } } for ( ; x < MGLine.Length; x ++) { MGLine.Point [x] .x = 4 * x; MGLine.Point[x] .y = 4 * y; } MGLine.Point[MGLine.Length - 1] .x = maxscat; for (x = mnval.x, y = mnval.y; x >= npeak.x; x --) { MGLine.Point [x] .x = 4 * x; MGLine.Point[x] .y = 4 * y; int sumO = smhist.GetCount (x - 1, y) + smhist.GetCoun (x - 2, y) ; int sumi = smhist.GetCount (x - 1, y - 1) + smhist.GetCount (x - 2, y - 1); int sum2 = smhist.GetCount (x - 1, y - 2) + smhist.GetCount (x - 2, y - 2); if ((sumi < sumO) ScSc (y > 5)) { y --; if ( ( sum2 < sumi ) ScSc (y > 5 ) ) y - - ; } } 548 549 for ( ; x >= 0; x --) { MGLine.Point [x] .x = 4 * x; MGLine.Point [x] .y = 4 * y; } // Label cells below the line as "mononuclear": wbclist->Resolution(dsWBCListMode: :ALL, 6) ; wbclist->Resolution(dsWBCListMode: :PSS, 8) ; for (i = 0; i < listcount; i ++) { if (wbclist->CellPopulation(i) == dsWBCUnknown) { x = wbclist->CellMeas (i, dsWBCListMode: :ALL) ; y = wbclist->CellMeas (i, dsWBCListMode: :PSS) ; if (y < (int)MGLine.Point [x] .y) wbclist->CellPopulation(dsWBCMonoNuclear, i) ,- } } ♦ifdef DIAGS // Check on conclusions: FILE* fp = fopen( "mgline.txt" , "w" ) ; if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file 'mgline.txt ' . \n" ) ; } else { fprintf (fp, "Mono-Gran Line Parameters: \n" ) ; fprintf (fp, "\tNeutrophil peak: ALL = %2d, PSS = %2d (Defaults: %2d, %2d)\n", 549 550 npeak.x, npeak.y, n_all, n__pss) ; fprintf (fp, "\tMonocyte peak: ALL = %2d, PSS = %2d (Defaults: %2d, %2d)\n", mpeak.x, mpeak.y, m_all, m_pss) ; fprintf (fp, "\tNeut-mono valley: ALL = %2d, PSS = %2d (Defaults: %2d, %2d)\n", mnval.x, mnval.y, mn_all, mn_pss) ,- if (MG_dflt) fprintf(fp, "\t (Default value(s) used)\n"); fprintf(fp, "\nALL-PSS 2-D Histogram: \n" ) ; for (int y = 63; y >= 0; y --) { for (int x = 0; x < 64; x ++) fprintf(fp, "%d\t", smhist.GetCount (x, y) ) ; fprintf (fp, "\n"); } fprintf(fp, "\nMGLine Histogram: \n" ) ; mmHist256 mghist; int base = 100; for (int j = 0; j < MGLine.Length; j ++) for (int k = 0; k < MGLine.Length; k ++) for (int n = 0; n < smhist.GetCount (j , k) ; n ++) mghist.AddCount ( (int) (base + k - (MGLine.Point[j] .y / 4))); for (j = 0; j < histmax; j ++) fprintf(fp, "%d\t%d\n", j, mghist[j]); fclose (fp) ; } ♦endif } 550 551 void mcWBCAlgorithm: :FindNELine (void) { // Build up an angular histogram in PSS vs. DSS, using all the remaining // "unknown" cells (only granulocytes, by now) : mmHist256 anghist; wbclist->Resolution(dsWBCListMode: :PSS, 0) ; wbclist->Resolution(dsWBCListMode: :DSS, 0) ; for (unsigned long i = 0; i < listcount; i ++) { if (wbclist->CellPopulation(i) == dsWBCUnknown) { double tangent = (double) (wbclist->CellMeas (i, dsWBCListMode: :DSS) ) / (double) (wbclist->CellMeas (i, dsWBCListMode: :PSS) ) ; double angle = 180 * atan(tangent) / mgPi; anghist.AddCount ( (int) (angle + 0.5)); } } // Smooth this histogram: mmHist256 smhist = anghist.SmBinom(smbcount) ; // Look for a valley in this histogram: int min_ang = 10; int max_ang = 31; int ne_ang = smhist.Valley(min_ang, max_ang) ; // If no valley was found, use a default value: NE_dflt = FALSE; if ( (ne_ang <= min_ang) I I (ne_ang >= max_ang) ) { ne_ang = NE_defval; 551 552 NE_dflt = TRUE; } // Set the slope of the discriminant line to match this angle: double tangent = tan( (double)ne_ang * mgPi / 180.0); NELine.Reset (tangent, 0.0); // Label all cells above the line as eosinophils, below as neutrophils: for (i = 0; i < listcount; i ++) { if (wbclist->CellPopulation(i) == dsWBCUnknown) { int x = wbclist->CellMeas (i, dsWBCListMode: :PSS) ; int y = (int) (tangent * x + 0.5); if (wbclist->CellMeas (i, dsWBCListMode: :DSS) > y) wbclist->CellPopulation(dsWBCEosinophil, i) ; else wbclist->CellPopulation(dsWBCNeutrophil, i) ; } } ♦ifdef DIAGS // Check on data in histograms: FILE* fp = fopenCneh.txt", "w"); if (!fp) { fprintf(stderr, "\nWarning: Unable to open output file 'neh.txt' . \n" ) ; } else { fprintf (fp, "Neut-Eo histogram (original & smoothed) : \n") ; for (int j = 0; j <= 90; j ++) 552 553 { fprintf (fp, "%d\t", j); fprintf (fp, "%d\t", anghist[j] ); fprintf (fp, "%d\n", smhist[j]),- } fprintf (fp, "XnAlgorithm results: \n" ) ; fprintf (fp, "\tNeut-Eo division: %d degrees\n", ne_ang) ; if (NE_dflt) fprintf (fp, "\t (Default value used)\n"); fclose (fp) ,- } #endif } void mcWBCAlgorithm: :FindLymphLines (void) { // Build up a histogram in ALL, using all the "mononuclear" cells: mmHist256 ALLhist; wbclist->Resolution(dsWBCListMode: :ALL, 8) ; for (unsigned long i = 0; i < listcount; i ++) if (wbclist->CellPopulation(i) == dsWBCMonoNuclear) ALLhist.AddCount ( (int)wbclist->CellMeas(i, dsWBCListMode: :ALL) ) ; // Smooth the histogram: mmHist256 smALLhist = ALLhist.SmBinom(smbcount) ,- // Look for a valley, above the lymphocytes, for the lymphocyte-monocyte // separation line: int min_all = 100; int max_all = 160; 553 554 int lmval = smALLhist.Valley(min_all, max_all); // If no valley was found, use a default value: LM_dflt = FALSE; if ((lmval <= min_all) I I (lmval >= max_all)) { lmval = LM_defval; LM_dflt = TRUE; } LMLine.Reset(0.0, (double)lmval) ; // Look for a valley, below the lymphocyte peak, for the // lymphocyte-stroma separation: min_all = 45; max_all = 75; int lnval = smALLhist.Valley(min_all, max_all) ; int lpeak = smALLhist.Peak(min_all, lmval); double lmean, lstd, lev; smALLhist.GetStats(0, lmval, lmean, lstd, lev) ,- // If no valley was found, use a default value: LN_dflt = FALSE; if ( (lnval <= min_all) I I (lnval >= max_all) ) { lnval = LN_defval; LN_dflt = TRUE; } LNLine.Reset(0.0, (double)lnval) ; // Label mononuclear cells above the upper line as monocytes; below the // lower one, as stroma; between the lines, leave as "mononuclear": for (i = 0; i < listcount; i ++) { 554 555 if (wbclist->CellPopulationd) == dsWBCMonoNuclear) { if (wbclist->CellMeas d, dsWBCListMode: :ALL) > lmval) wbclist->CellPopulation(dsWBCMonocyte, i) ; else if (wbclist->CellMeas d, dsWBCListMode: :ALL) < lnval) wbclist->CellPopulation(dsWBCStroma, i) ; } } #ifdef DIAGS // Check on data in histograms: FILE* fp = fopenClmh.txt", "w" ) ; if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file ' l h.txf .\n") ; } else { fprintf (fp, "Lymph-Mono histogram (original Sc smoothed) :\n" ) ; for (int j = 0; j < 256; j ++) { fprintf (fp, "%d\t", j); fprintf (fp, "%d\t", ALLhist [j] ); fprintf (fp, "%d\n", smALLhist[j] ) ,- } fprintf (fp, "\nAlgorithm results: \n" ) ; fprintf (fp, "\tLymph-Stroma line: %6d\n", lnval); if (LN_dflt) fprintf (fp, "\t (Default value used)\n"); fprintf (fp, "\tLymph-Mono line: %6d\n", lmval); if (LM_dflt) 555 556 fprintf(fp, "\t(Default value used)\n"); fprintf(fp, "\tALL peak: %6d\n", lpeak); fprintf (fp, "\tALL mean: %6.2f\n", lmean) fprintf(fp, "\tALL std. dev. : %6.2f\n", lstd); fprintf(fp, "\tALL cv.: %6.2f\n", lev); fclose(fp) } #endif } void mcWBCAlgorithm: :FindBasoLines(void) { // Build up a a histogram in IAS, using all remaining "mononuclear" cells: mmHist256 IAShist; wbclist->Resolution(dsWBCListMode: :IAS, 8) ; for (unsigned long i = 0; i < listcount; i ++) if (wbclist->CellPopulation(i) == dsWBCMonoNuclear) IAShist.AddCount( (int)wbclist->CellMeas(i, dsWBCListMode: :IAS) ) ; // Smooth the histogram: mmHist256 smIAShist = IAShist.SmBinom(smbcount) ; // Look for a valley for the lymphocyte-basophil separation line: int min_ias = 70; int max_ias = 110; int lpeak = smIAShist.Peak(0, histmax) ; int lbval = smIAShist.Valley(min_ias, max_ias) ; double lmean, lstd, lev; smIAShist.GetStats(0, max_ias, lmean, lstd, lev); // If no valley was found, use a default value, based on 556 557 lymphocyte mean // and s.d. (if there are enough lymphocytes) : LB_dflt = FALSE; int lcount = smIAShist.GetCount () ; if ( bval <= min_ias) I I (lbval >= max_ias) ) { if (lcount > mincount) lbval = (int) (lmean + 2.5 * lstd + 0.5); else lbval = LB_defval; LB_dflt = TRUE; } LBLine.Reset ( (double) lbval) ; // Label the remaining mononuclear cells left of the lymphocyte-basophil // line as lymphocytes, and build an ALL histogram with the rest: mmHist256 ALLhist; wbclist->Resolution(dsWBCListMode::ALL, 8); wbclist->Resolution(dsWBCListMode: :IAS, 8) ; for (i = 0; i < listcount; i ++) { if (wbclist->CellPopulation(i) == dsWBCMonoNuclear) { if (wbclist->CellMeas (i, dsWBCListMode: :IAS) < lbval) wbclist->CellPopulation(dsWBCLymphocyte, i) ; else ALLhist.AddCount ( (int)wbclist->CellMeas (i, dsWBCListMode: :ALL) ) ; } } // Smooth the histogram: 557 558 mmHist256 smALLhist = ALLhist.SmBinom(smbcount) ; // Find the basophil-RRBC separation line in ALL: int min_all = (int) (LNLine.Intercept () + (LMLine.Intercept O - LNLine.Intercept 0 ) / 4); int max_all = (int) (LNLine.Intercept () + 3 * (LMLine.Intercept 0 - LNLine.Intercept 0 ) / 4); int bnval = smALLhist.Valley(min_all, max_all) ; int rpeak = smALLhist.Peak(0, histmax); double rmean, rstd, rev; smALLhist.GetStats (0, histmax, rmean, rstd, rev); // If no valley was found, use a default value: BN_dflt = FALSE; if ((bnval <= min_all) I I (bnval >= max_all)) { bnval = (int) (LNLine.Intercept () + (LMLine.Intercept 0 - LNLine.Intercept 0 ) / 2); BN_dflt = TRUE; } BNLine.Reset(0.0, (double)bnval) ; // Label the remaining mononuclear cells above the basophil-noise // line, as basophils; and below this line, as "noise" (probably RRBCs) : wbclist->Resolution(dsWBCListMode: :ALL, 8); for d = 0; i < listcount; i ++) { if (wbclist->CellPopulationd) == dsWBCMonoNuclear) { if (wbclist->CellMeas d, dsWBCListMode: :ALL) > 558 559 bnval) wbclist->CellPopulation(dsWBCBasophil, i) ; else wbclist->CellPopulation(dsWBCNoise, i) ; } } ♦ifdef DIAGS // Check on data in histograms: FILE* fp = fopenClbh.txt", "w" ) ,- if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file 'lbh.txf .\n") ; } else { fprintf (fp, "Lymph-Baso histogram (original Sc smoothed) : \n" ) ; for (int j = 0; j <= histmax; j ++) { fprintf (fp, "%d\t", j); fprintf (fp, "%d\t", IAShist[j]); fprintf (fp, "%d\n", smIAShist[j ]) ; } fprintf (fp, "\nAlgorithm results:\n" ) ; fprintf (fp, "\tLymph-Baso line: %6d\n", lbval); if (LB_dflt) fprintf (fp, "\t (Default value used)\n"),- fprintf (fp, "\tIAS peak: %6d\n" , lpeak); fprintf (fp, "\tIAS mean: %6.2f\n", lmean); fprintf (fp, "\tIAS std. dev. : %6.2f\n", lstd); fprintf (fp, "\tIAS c. v. : %6.2f\n", lev); fclose(fp) ; } 559 560 fp = fopenObnh.txt", "w" ) ; if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file 'bnh.txt' .\n") ,- } else { fprintf (fp, "Baso-Noise histogram (original Sc smoothed) : \n" ) ; for (int j = 0; j <= histmax; j ++) { fprintf (fp, "%d\t", j); fprintf(fp, "%d\t", ALLhist[j]) ; fprintf (fp, "%d\n", smALLhist[j] ) ; } fprintf (fp, "\nAlgorithm results:\n") ; fprintf (fp, "\tBaso-Noise line: %6d\n", bnval); if (BN_dflt) fprintf(fp, "\t (Default value used)\n"); fprintf(fp, "\tALL peak: %6d\n", rpeak) ; fprintf (fp, "\tALL mean: %6.2f\n", rmean); fprintf (fp, "\tALL std. dev. : %6.2f\n", rstd); fprintf (fp, "\tALL cv.: %6.2f\n", rev); fclose (fp) ; } ♦endif } void mcWBCAlgorithm: :GetFinalCounts (Boolean validcounts) { // Determine what percentage of events are white cells: int lymphs = 0; 560 561 int monos = 0, int basos = 0, int neuts = 0; int eos = 0; int stroma = 0; int noise = 0; int nrbcs = 0; int fragile = 0; int dead = 0; for (unsigned long i = 0; i < listcount; i ++) { switch (wbclist->CellPopulation(i) ) { case dsWBCLymphocyte: lymphs ++; break; case dsWBCMonocyte: monos ++; break; case dsWBCBasophil: basos ++; break; case dsWBCNeutrophil: neuts ++; break; case dsWBCEosinophil: eos ++; break; case dsWBCStroma: stroma ++; break; case dsWBCNoise: noise ++; break; case dsWBCNRBC: 561 562 nrbcs ++; break; case dsWBCFragile: fragile ++; break; case dsWBCDead: dead ++; break; default: case dsWBCUnknown.- case dsWBCMonoNuclear: break; // Calculate the total WBC concentration: const dsCountDataSc countdata = wbcmeas.Count 0 ; double wbcs = lymphs + monos + basos + neuts + eos + fragile + dead; double wbcfract = 0.0; if (! validcounts) wbcfract = 1.0; else if (listcount > 0) wbcfract = wbcs / listcount; Boolean concstat = Concentration(mgCellAlgorithm: :FINAL, countdata, WbcConc, WbcStat, wbcfract, 0.001, // unitsFactor, to get K/uL caldata.CalFactor(dcCalibrationData: :WBC) , caldata.DilFactor(dcCalibrationData: :WBC) ) ; 562 563 // Calculate the concentration and percentage in each sub-population: if ( (wbcs > 0) ScSc (validcounts) ScSc (concstat) ) { LymphPct = 100.0 * (double) (lymphs + fragile) / wbcs; LymphConc = LymphPct ♦ WbcConc / 100.0; LymphStat = dsNumericalResult::CalcOK; MonoPct = 100.0 ♦ (double)monos / wbcs; MonoConc = MonoPct ♦ WbcConc / 100.0;; MonoStat = dsNumericalResult: -.CalcOK; BasoPct = 100.0 * (double)basos / wbcs; BasoConc = BasoPct * WbcConc / 100.0;; BasoStat = dsNumericalResult::CalcOK; NeutPct = 100.0 * (double) (neuts + dead) / wbcs; NeutConc = NeutPct * WbcConc / 100.0;; NeutStat = dsNumericalResult::CalcOK; EosPct = 100.0 * (double)eos / wbcs EosConc = EosPct * WbcConc / 100.0; EosStat = dsNumericalResult::CalcOK NrbcPct = 100.0 * (double)nrbcs / wbcs; NrbcConc = NrbcPct * WbcConc / 100.0;; NrbcStat = dsNumericalResult::CalcOK; StromaPct = 100.0 * (double)stroma / wbcs; NoisePct = 100.0 * (double)noise / wbcs; FragilePct = 100.0 * (double) fragile / wbcs; DeadPct = 100.0 * (double)dead / wbcs; } else 563 564 { LymphPct = MonoPct = BasoPct = NeutPct = EosPct = NrbcPct = 0.0; StromaPct = NoisePct = FragilePct = DeadPct = 0.0; LymphConc = MonoConc = BasoConc = NeutConc = EosConc = NrbcConc = 0.0; LymphStat = MonoStat = BasoStat = NeutStat = EosStat NrbcStat = dsNumericalResult::NoCalc; } // Check for adequate numbers of cells in each sub- population: const int minsubpop = 50; if (neuts < minsubpop) NeutStat = dsNumericalResult: .-Suspect,- if (lymphs < minsubpop) LymphStat = dsNumericalResult: :Suspect; if (monos < minsubpop) MonoStat = dsNumericalResult::Suspect; DoFinalPopEval () ; } void mcWBCAlgorithm: :DoFinalPopEval ( void ) { Lym.all.mn = 104.0; // These are default settings for each of the Ly .ias.mn = 74.0; // mean and cv values for each population. Lym.pss.mn = 15.0; // Some of mn and cv's are set to defaults Lym.dss.mn = 0.0; // other than zero. These defaults represent 564 565 Lym.fl3.mn = 0.0 // target values for normal wbc populations, Mon.all.mn = 173.0; // (see D.Peters book 48014 ppl0+) . The Mon.ias.mn = 99.0; // reason for this is to allow the linear Mon.pss.mn = 43.0; // function in SetFlags0 to continue its Mon.dss.mn = 0.0; // best guess when there is not sufficient Mon.f13.mn = 0.0; // information in one of the poplations. Neu.all.mn = 140.0; Neu.ias.mn = 150.0; Neu.pss.mn = 125.0; Neu.dss.mn = 28.0; Neu.fl3.mn = 0.0; LymMon.all.mn 118.0; Ly Mon.ias.mn 79.0; LymMon.pss.mn 21.0; LymMon.dss.mn 0.0 LymMon.fl3.mn 0.0 WCells.all.mn 0.0 WCells.ias.mn 0.0 WCells.pss.mn 0.0 WCells.dss.mn 0.0 WCells.fl3.mn 42.0; Lym.all.cv = 0.0 Lym.ias.cv = 0.0 Lym.pss.cv = 0.0 Lym.dss.cv = 0.0 Ly .fl3.cv = 0.0 Mon.all.cv = 0.0 Mon.ias.cv = 0.0 565 566 Mon.pss.cv = 0 .0 Mon.dss.cv = 0 0 Mon. f13.cv = 0 0 Neu.all.cv = 0 0 Neu.ias.cv = 0 0 Neu.pss.cv = 0 0 Neu.dss.cv = 0 0 Neu.fl3.cv = 0 0 LymMon.all cv = 0.0 LymMon.ias cv = ( ).0 LymMon.pss cv = ( ).0 LymMon.dss cv = c ).0 LymMon.f13 cv = c ).0 WCells.all cv = c ).0 WCells.ias cv = c ).0 WCells.pss.cv = c ).0 WCells.dss.cv = c ).0 WCells.fl3.cv - c ).0 // Calculate diagnostic results, morphology characteristics and send // to storage: // Build up the diagnostic histograms for each population: mmHist256 n_allhist; mmHist256 n_iashist mmHist256 n_psshist mmHist256 n_dsshist mmHist256 n_fl3hist mmHist256 l_allhist mmHist256 l_iashist mmHist256 l_fl3hist mmHist256 m allhist 566 567 mmHist256 m_iashist; mmHist256 m_psshist; mmHist256 m_fl3hist; mmHist256 lm_allhist; mmHist256 lm_iashist; mmHist256 lm_psshist; mmHist256 wcells_f13hist; wbclist->Resolution(dsWBCListMode: :ALL, 8) wbclist->Resolution(dsWBCListMode: :IAS, 8) wbclist->Resolution(dsWBCListMode::PSS, 8) wbclist->Resolution(dsWBCListMode: :DSS, 8) wbclist->Resolution(dsWBCListMode: :FL3, 0) for (unsigned long i = 0; i < listcount; i ++) { dsWBCPopulation celltype = wbclist- >CellPopulation(i) ; // Used in population diagnostics, if (celltype == dsWBCNeutrophil) { n_allhist.AddCount ( (int)wbclist->CellMeas d, dsWBCListMode: :ALL) ) ; n_iashist.AddCount ( (int)wbclist->CellMeas (i, dsWBCListMode: :IAS) ) ; n__psshist.AddCount ( (int)wbclist->CellMeas (i, dsWBCListMode: :PSS) ) ; n_dsshist.AddCount ( dnt)wbclist->CellMeas (i, dsWBCListMode: :DSS) ) ; n_fl3hist.AddCount ( (int)wbclist->CellMeas d, dsWBCListMode: :FL3) ) ; } // Used in population diagnostics and abnormal morphology flagging. else if (celltype == dsWBCLymphocyte) { l_allhist .AddCount ( dnt)wbclist->CellMeas d, 567 568 dsWBCListMode: :ALL) ) ; l_iashis .AddCount ( (int)wbclist->CellMeasd, dsWBCListMode: :IAS) ) ; l_fl3hist.AddCoun ( (int)wbclist->CellMeas d, dsWBCListMode: :FL3) ) ; } // Used in abnormal morphology flagging, else if (celltype == dsWBCMonocyte) { m_allhis .AddCount( (int)wbclist->CellMeasd, dsWBCListMode: :ALL) ) ; m_iashist.AddCoun ( (int)wbclist->CellMeas d, dsWBCListMode: :IAS) ) ; m_psshist.AddCount ( (int)wbclist->CellMeas (i, dsWBCListMode: :PSS) ) ; m_fl3hist.AddCount ( (int)wbclist->CellMeas d, dsWBCListMode: :FL3) ) ; } // Used in abnormal morphology flagging. if ((celltype == dsWBCLymphocyte) I I (celltype == dsWBCMonocyte) ) { lm_allhist.AddCount ( (int)wbclist->CellMeas(i, dsWBCListMode: :ALL) ) ; lm_iashist.AddCount ( (int)wbclist->CellMeas(i, dsWBCListMode: :IAS) ) ; lm_psshist.AddCount ( (int)wbclist->CellMeas(i, dsWBCListMode: :PSS) ) ; } // Used in abnormal morphology flagging. if ( (celltype == dsWBCLymphocyte) I I (celltype == dsWBCMonocyte) I I (celltype == dsWBCBasophil) I I (celltype == dsWBCEosinophil) I I (celltype == dsWBCNeutrophil) ) 568 569 wcells_fl3hist.AddCount( (int)wbclist->CellMeas (i, dsWBCListMode: :FL3) ) ; } } // Calculate mean and cv. for each histogram, and send to storage: if ( NeutStat == dsNumericalResult::CalcOK ) { DoPopStats( n_allhist, Neu.all.mn, Neu.all.cv DoPopStats( n_iashist, Neu.ias.mn, Neu.ias.cv DoPopStats( n_psshist, Neu.pss.mn, Neu.pss.cv DoPopStats( n_dsshist, Neu.dss.mn, Neu.dss.cv DoPopStats( n_fl3hist, Neu.fl3.mn, Neu.fl3.cv } if( LymphStat == dsNumericalResult::CalcOK ) { DoPopStats( l_allhist, Lym.all.mn, Lym.all.cv ) DoPopStats( l_iashist, Lym.ias.mn, Lym.ias.cv ) DoPopStats( l_fl3hist, Lym.fl3.mn, Lym.fl3.cv ) } if( MonoStat == dsNumericalResult::CalcOK ) { DoPopStats( m_allhist, Mon.all.mn, Mon.all.cv ) DoPopStats( m_iashist, Mon.ias.mn, Mon.ias.cv ) DoPopStats( m_psshist, Mon.pss.mn, Mon.pss.cv ) DoPopStats( m_fl3hist, Mon.fl3.mn, Mon.fl3.cv ) } if( LymphStat == dsNumericalResult::CalcOK ScSc MonoStat == dsNumericalResult::CalcOK ) 569 570 { DoPopStats ( lm_allhist, LymMon.all.mn, LymMon.all.cv ); DoPopStats ( lm_iashist, LymMon.ias.mn, LymMon.ias.cv ); DoPopStats ( lm_psshist, LymMon.pss.mn, LymMon.pss.cv if( LymphStat == dsNumericalResult::CalcOK Sc MonoStat == dsNumericalResult::CalcOK ) { DoPopStats( wcells_fl3hist, WCells.fl3.mn, WCells.f13.cv ) ; } // Send out diagnostic results for FL3 distributions: dtlnternalLog log(SourceFileName) ; char outstr[100] ,- sprintf(outstr, "Neutrophils: FL3 mean = %6.2f; cv. = %6.2f", Neu.fl3.mn, Neu.f13.cv) ,- log « Line ( LINE ) « outstr « Flush; sprintf (outstr, "Monocytes: FL3 mean = %6.2f; cv. = %6.2f", Mon.fl3.mn, Mon.fl3.cv); log « Line ( LINE ) « outstr « Flush; sprintf (outstr, "Lymphocytes: FL3 mean = %6.2f; cv. = %6.2f", Lym.fl3.mn, Lym.fl3. cv) ; log « Line ( LINE ) « outstr << Flush; } void mcWBCAlgorithm: :DoPopStats (const mmHist256& hist, 570 571 doubleSc mean , doubles-, cv ) { double stdev,- hist.GetStats ( 2, histmax - 1, mean, stdev, cv ) ,- } void mcWBCAlgorithm: :SetFlags (void) { dtlnternalLog log (SourceFileName) ; // *** RRBC Flag *** (for "hard-to-lyse" samples) : arRRBCs = dsAlertResult: :NonAlerted; // RRBCs(l) : Look for a time-dependent decay in the count rate: const double minslope = -1.0; const dsCountDataSc countdata = wbcmeas.Count 0 ,- int ncounts = (int) countdata.Size0 - 1; double countslope = 0.0; if (ncounts > 10) { DoubleVec xval (ncounts, 0.0); DoubleVec yval(ncounts, 0.0); for (int n = 0; n < ncounts; n ++) { xval[n] = n + 1; yval[n] = countdata.Count (n + 1) - countdata.Count (n) ; } LeastSqFit lsf (xval, yval); countslope = lsf.slope (),- if (countslope < minslope) arRRBCs = dsAlertResult::Alerted; 571 572 // RRBCs(2) : Check the percentage of "noise" events: double maxnoise = 5.0; if (NoisePct > maxnoise) arRRBCs = dsAlertResult::Alerted; // RRBCs(3) : Look for distortions in the shape of the "lymphocyte" cluster: double min_mean = 80.0; double max_cv = 20.0; if ((LymphStat == dsNumericalResult::CalcOK) ScSc ( (Lym.all.mn < min_mean) I I (Lym.ias.cv > max_cv) ) ) { arRRBCs = dsAlertResult::Alerted; } // Send diagnostics to InternalLog file: log « Line( LINE ) << "RRBC flag: Slope of 'CountData': " « countslope « Flush; log « Line ( LINE ) << "RRBC flag: Percentage of 'Noise' : " « NoisePct « Flush; log « Line( LINE ) « "RRBC flag: Lymphocyte mean (ALL) : " « Lym.all.mn « Flush; log « Line ( LINE ) « "RRBC flag: Lymphocyte cv. (IAS): " « Lym.ias.cv « Flush; if (arRRBCs == dsAlertResult::Alerted) log « Line ( LINE ) « "RRBC flag SET (alerted) " « Flush; // Determine whether the "NRBC" flag should be set: 572 573 const double max_NrbcPct = 1.0; if (NrbcPct >= max_NrbcPct) arNRBCs = dsAlertResult::Alerted; else arNRBCs = dsAlertResult: :NonAlerted; // ** ♦ Blast Flag ♦♦♦ // Analyze the lymphocyte, monocyte and f13-wbc cell (including fragile // and dead cell) populations to determine the "blast" flag status. // The following method uses a linear function based on the weights of // various inputs. This function was determined with use of a set of // 120 blast (>1%) samples, 149 non-blast abnormal samples, and 120 normal // samples. The details may be obtained from DonPeters Notebook ^48,014 // page 10+. double DiscrimFnc_blast = 0.0; // initialize Function output const double wt_MonoPct = 0.030352; // Coeff. weight for %Mono's. const double wt_LymALLmn = 0.013182; // Coeff. weight for LymALL mean. const double wt_MonALLιrm = 0.016766; // Coeff. weight for MonALL mean. const double wt_MonALLcv = 0.152739; // Coeff. weight for MonALL cv . const double wt_MonIAScv = -0.041058; // Coeff. weight for MonlAS cv . const double wt_MonPSSmn = -0.051015; // Coeff. weight for MonPSS mean . const double wt_MonPSScv = 0.028661; // Coeff. weight 573 574 for MonPSS cv . const double wt_LymMonPSScv = •0.029609; // Coeff. weight for L-MPSS cv . const double wt_WCellsFL3mn = 0.024813; // Coeff. weight all WBC fl3 mean const double BlstConst = -3.874633; // Constant term. arBlasts = dsAlertResult: :NonAlerted; DiscrimFnc_blast = ( wt_MonoPct ♦ MonoPct! + wt_LymALLmn ♦ Lym.a11.mn + wt_MonALLmn * Mon.all.mn + wt_MonALLcv * Mon.a1Lev + wt_MonIAScv * Mon.ias.cv + wt_MonPSSmn ♦ Mon.pss.mn + wt_MonPSScv ♦ Mon.pss.cv + wt_LymMonPSScv * LymMon.pss.cv ) + wt_WCellsFL3mn * WCells.f13.mn ) + BlstConst; if( DiscrimFnc_blast > 0.0 ) arBlasts = dsAlertResult::Alerted; log « Line( LINE ) << "Blast Flag - MonoPct: " « MonoPct « Flush; log « Line( LINE__) << "Blast Flag - Lym.all.mn: " « Lym.all.mn « Flush; log « Line( LINE ) << "Blast Flag - Mon.all.mn: " « Mon.all.mn « Flush; log « Line( LINE ) « "Blast Flag - Mon.all.cv: " « Mon.all.cv « Flush; 574 575 log << Line ( LINE ) << "Blast Flag - Mon.ias.cv: " << Mon. ias.cv << Flush; << "Blast Flag - Mon.pss.mn: " << Mon.pss.mn « Flush; log « Line( LINE ) << "Blast Flag - Mon.pss.cv: " << Mon.pss.cv « Flush; log « Line( LINE ) << "Blast Flag - LymMon.pss.cv: " « LymMon.pss.cv << Flush; log << Line( LINE ) << "Blast Flag - WCells. f13.mn: " « WCells. fl3.mn « Flush; log « Line( LINE ) << "Blast Flag - DiscrimFnc_blast: " << DiscrimFnc_blast « Flush; // *** variant Lymph Flag ♦♦♦ // Analyze the lymphocyte population to determine the "variant lymphocyte" // flag status: arVLs = dsAlertResult: :NonAlerted; // ♦♦♦ IG and BAND Flags * ♦♦ // Analyze the neutrophil population to determine the "band" and "immature // granulocytes" flags status: arBands = dsAlertResult: :NonAlerted; arIGs = dsAlertResult: :NonAlerted; #ifdef DIAGS // Check on data used for flagging: FILE^ fp = fopenCflags.txt", "w" ) ,- 575 576 if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file 'flags.txt'.\n") ,- } else { fprintf(fp, "Resistant RBC flag:\n"); fprintf(fp, "\tSlope of 'CountData': %6.2f cells/sec\n", countslope); fprintf(fp, "\tPercent of 'Noise': %6.2f%%\n", NoisePct) ,- fprintf(fp, "\tLymph mean (ALL): %6.2f\n", Lym.all.mn) ,- fprintf(fp, "\tLymph cv. (IAS): %6.2f\n", Lym.ias.cv) ; if (arRRBCs == dsAlertResult: :Alerted) fprintf(fp, "\tResistant RBC flag SET\n\n"); else fprintf(fp, "\tResistant RBC flag NOT SET\n\n"); fclose(fp) ; } #endif } void mcWBCAlgorithm: :SendNumResults(dsNumericalResultSetSc numresult) { // Send the numerical results to storage: numresult[dsWBCConc] .Value(WbcConc) ; numresult[dsWBCConc] .Stat(WbcStat) ; numresult[dsLymphocyteCone] .Value(LymphConc) ; numresult[dsLymphocyteCone] .Stat(LymphStat) ; 576 577 numresult dsLymphocytePct] .Value (LymphPct) ; numresult dsLymphocytePct] .Stat (LymphStat) ; numresult dsMonocyteConc] .Value (MonoConc) ; numresult dsMonocyteConc] .Stat (MonoStat) ; numresult dsMonocytePct] .Value(MonoPct) ; numresult dsMonocytePct] .Stat (MonoStat) ; numresult dsBasophilConc] .Value(BasoConc) ; numresult dsBasophilConc] .Stat (BasoStat) ; numresult dsBasophilPct] .Value (BasoPct) ; numresult dsBasophilPct] .Stat (BasoStat) ; numresult dsNeutrophilConc] .Value(NeutConc) ; numresult dsNeutrophilConc] .Stat (NeutStat) ; numresult dsNeutrophilPct] .Value (NeutPct) ; numresult dsNeutrophilPct] .Stat (NeutStat) ; numresult dsEosinophilConc] .Value(EosConc) ; numresult dsEosinophilConc] .Stat (EosStat) ; numresult dsEosinophilPct] .Value(EosPct) ; numresult dsEosinophilPct] .Stat (EosStat) ; // NOTE: Don't report NRBC results unless >= 1%: if (NrbcPct >= 1.0) { numresult[dsNucleatedRBCCone] .Value(NrbeConc) ; numresult[dsNucleatedRBCPerWBC] .Value(NrbcPct) ; } else 577 578 { numresult[dsNucleatedRBCCone] .Value(0.0) ; numresult[dsNucleatedRBCPerWBC] .Value(0.0) ,- } numresult[dsNucleatedRBCCone] .Stat (NrbcStat) ; numresult[dsNucleatedRBCPerWBC] .Stat(NrbcStat) ; const dsCountDataS- countdata = wbemeas.Count() ; numresult[dsWBCListModeSize] .Value(listcount) ; numresult[dsWBCListModeSize] .Stat (dsNumericalResult: :CalcOK) ; numresult[dsWBCUngatedCount] .Value(countdata.FinalCount 0 ) ; numresult[dsWBCUngatedCount] .Stat(dsNumericalResult: :CalcOK) ; numresult[dsWBCGatedCount] .Value(countdata.FinalCount0 ) ; numresult[dsWBCGatedCount] .Stat(dsNumericalResult: :CalcOK) ,- numresult[dsWBCCountTime] .Value(countdata.FinalTime0 ) ; numresult[dsWBCCountTime] .Stat(dsNumericalResult: :CalcOK) ; numresult[dsWBCDilution] .Value(countdata.Dilution0 ) ,- numresult[dsWBCDilution] .Stat (dsNumericalResult: :CalcOK) ; numresult[dsWBCFlowRate] .Value(countdata.FlowRate() ) ,- numresult[dsWBCFlowRate] .Stat(dsNumericalResult: :CalcOK) ; // Calculate diagnostic results and send to storage: if ((LymphStat == dsNumericalResul ::CalcOK) &Sc (NeutStat == dsNumericalResult::CalcOK) ) 578 579 { // Report mean and cv. for each histogram: numresult [dsWBCNeutrophilMean_ALL] .Value (Neu.all.mn) ; numresult [dsWBCNeutrophilMean_ALL] .Stat (dsNumeriealResu It: :CalcOK) ; numresult [dsWBCNeutrophilCV_ALL] .Value (Neu.all.cv) ; numresult [dsWBCNeutrophilCV_ALL] .Sta (dsNumericalResul t: :CalcOK) ; numresult [dsWBCNeutrophilMean_IAS] .Value (Neu.ias.mn) ; numresult [dsWBCNeutrophilMean_IAS] .Stat (dsNumeriealResu It: :CalcOK); numresul [dsWBCNeutrophilCV_IAS] .Value (Neu.ias.cv) ; numresult [dsWBCNeutrophilCV_IAS] .Stat (dsNumericalResul t: :CalcOK) ; numresult [dsWBCNeutrophilMean_PSS] .Value (Neu.pss.mn) ; numresult [dsWBCNeutrophilMean_PSS] .Stat (dsNumeriealResu It: :CalcOK) ; numresult[dsWBCNeutrophilCV_PSS] .Value (Neu.pss.cv) ,- numresult[dsWBCNeutrophilCV_PSS] .Stat (dsNumericalResul t: :CalcOK) ; numresult[dsWBCNeutrophilMean_DSS] .Value (Neu.dss.mn) ; numresult [dsWBCNeutrophilMean_DSS] .Stat (dsNumeriealResu It: :CalcOK) ; numresult[dsWBCNeutrophilCV_DSS] .Value (Neu.dss.cv) ; 579 580 numresult [dsWBCNeutrophilCV_DSS] .Stat (dsNumericalResul t: :CalcOK) ; numresult [dsWBCNeutrophilMean_FL3] .Value(Neu. f13.mn) ; numresult [dsWBCNeutrophilMean_FL3] .Stat(dsNumeriealResu It: .-CalcOK) ; numresult[dsWBCNeutrophilCV_FL3] .Value (Neu. f13.cv) ; numresult [dsWBCNeutrophilCV_FL3] .Stat (dsNumericalResul t: :CalcOK) ; numresult[dsWBCLymphocyteMean_ALL] .Value(Lym.all.mn) ,- numresult [dsWBCLymphocyteMean_ALL] .Stat (dsNumeriealResu It: :CalcOK) ; numresult[dsWBCLymphocyteCV_ALL] .Value(Lym.all.cv) ; numresult [dsWBCLymphocyteCV_ALL] .Stat (dsNumericalResul t::CalcOK); numresult[dsWBCLymphocyteMean_IAS] .Value(Lym.ias.mn) ; numresult [dsWBCLymphocyteMean_IAS] .Stat (dsNumeriealResu It: :CalcOK); numresult[dsWBCLymphocyteCV_IAS] .Value (Lym.ias.cv) ; numresult[dsWBCLymphocyteCV_IAS] .Stat (dsNumericalResul t: :CalcOK) ; } else { numresult[dsWBCNeutrophilMean_ALL] .Value(0) ; numresult [dsWBCNeutrophilMean_ALL] .Stat (dsNumeriealResu 580 581 It: :NoCalc) ; numresult [dsWBCNeutrophilCV_ALL] .Value (0) ; numresult [dsWBCNeutrophilCV_ALL] .Stat (dsNumericalResul t: :NoCalc) ; numresult [dsWBCNeutrophilMean_IAS] .Value (0) ; numresult [dsWBCNeutrophilMean_IAS] .Stat (dsNumeriealResu It: :NoCalc); numresult [dsWBCNeutrophilCV_IAS] .Value (0) ; numresult [dsWBCNeutrophilCV_IAS] .Stat (dsNumericalResul t: :NoCalc) ; numresult[dsWBCNeutrophilMean_PSS] .Value (0) ; numresult [dsWBCNeutrophilMean_PSS] .Stat (dsNumeriealResu It: :NoCalc) ; numresult [dsWBCNeutrophilCV_PSS] .Value (0) ; numresult [dsWBCNeutrophilCV_PSS] .Stat (dsNumericalResul t: :NoCalc) ; numresult[dsWBCNeutrophilMean_DSS] .Value(0) ; numresult [dsWBCNeutrophilMean_DSS] .Stat (dsNumeriealResu It: :NoCalc) ; numresult [dsWBCNeutrophilCV_DSS] .Value (0) ; numresult [dsWBCNeutrophilCV_DSS] .Stat (dsNumericalResul t: :NoCalc) ; numresult [dsWBCNeutrophilMean_FL3] .Value (0) ; 581 582 numresult[dsWBCNeutrophilMean_FL3] .Stat(dsNumeriealResu It: :NoCalc) ; numresult[dsWBCNeutrophilCV_FL3] .Value(0) ; numresult[dsWBCNeutrophilCV_FL3] .Stat(dsNumericalResul t: .-NoCalc) ; numresult[dsWBCLymphocyteMean_ALL] .Value(0) ; numresult[dsWBCLymphocyteMean_ALL] .Stat (dsNumeriealResu It: :NoCalc) ; numresult[dsWBCLymphocyteCV_ALL] .Value(0) ; numresult[dsWBCLymphocyteCV_ALL] .Stat (dsNumericalResul t::NoCalc); numresult[dsWBCLymphocyteMean_IAS] .Value(0) ; numresult[dsWBCLymphocyteMean_IAS] .Stat(dsNumeriealResu lt::NoCalc); numresult[dsWBCLymphocyteCV_IAS] .Value(0) ; numresult[dsWBCLymphocyteCV_IAS] .Stat(dsNumericalResul t: :NoCalc) ; } #ifdef DIAGS // Check on data sent to "results": FILE Λ fp = fopenOdata.txt", "w"); if (!fp) { fprintf(stderr, "\nWarning: Unable to open output file 'data.txt' .\n") ,- } else 582 583 fprintf (fp, "WBC Cone: %6.2f K/uL\n", numresult[dsWBCConc] .Value ( ) ) ; fprintf (fp, "Lymphocytes: %6.2f K/uL %4.1f%%\n", numresult [dsLymphocyteCone] .Value ( ) , numresult [dsLymphocytePct] .Value 0 ) ; fprintf (fp, "Monocytes: %6.2f K/uL %4.1f%%\n", numresult [dsMonocyteConc] .Value{ ) , numresult [dsMonocytePct] .Value 0 ) ; fprintf (fp, "Basophils: %6.2f K/uL %4.1f%%\n", numresult [dsBasophilConc] .Value ( ) , numresult [dsBasophilPct] .Value 0 ) ; fprintf (fp, "Neutrophils: %6.2f K/uL %4.1f%%\n", numresult[dsNeutrophilConc] .Value 0 , numresult [dsNeutrophilPct] .Value ( ) ) ; fprintf (fp, "Eosinophils: %6.2f K/uL %4.1f%%\n", numresult [dsEosinophilConc] .Value0 , numresult [dsEosinophilPct] .Value 0 ) ; fprintf(fp, "NRBCs: %6.2f K/uL %4.If%%\n\n" , numresult [dsNucleatedRBCCone] .Value ( ) , numresult[dsNucleatedRBCPerWBC] .Value( ) ) ; fprintf (fp, "Stroma: %4.1f%%\n", StromaPct) ; fprintf (fp, "Noise: %4.1f%%\n", NoisePct) ; fprintf (fp, "Fragile cells: %4.1f%%\n", FragilePct) ,- fprintf(fp, "Dead cells: %4.1f%%\n", DeadPct) ; fclose (fp) ,- } fp = fopen Cdiags . txt " , "w" ) ; if ( ! fp) 583 584 { fprintf (stderr, "\nWarning: Unable to open output file 'diags.txt ' . \n" ) ; } else { fprintf (fp, "Neutrophils -- ALL: mean = %6.2f, cv. = %6.2f\n", Neu.all.mn, Neu.all.cv); fprintf (fp, "Neutrophils -- IAS: mean = %6.2f, cv. = %6.2f\n", Neu.ias.mn, Neu. ias.cv); fprintf (fp, "Neutrophils -- PSS: mean = %6.2f, cv. = %6.2f\n", Neu.pss.mn, Neu.pss.cv); fprintf(fp, "Neutrophils -- DSS: mean = %6.2f, cv. = %6.2f\n", Neu.dss.mn, Neu.dss.cv); fprintf (fp, "Neutrophils -- FL3 : mean = %6.2f, cv. = %6.2f\n\n » , Neu.fl3.mn, Neu.fl3.cv); fprintf (fp, "Monocytes ALL: mean = %6.2f, cv. = %6.2f\n", Mon.all.mn, Mon.all.cv) ; fprintf (fp, "Monocytes IAS: mean = %6.2f, cv. = %6.2f\n", Mon.ias.mn, Mon.ias.cv); fprintf (fp, "Monocytes PSS: mean = %6.2f, cv. = %6.2f\n", Mon.pss.mn, Mon.pss.cv); fprintf (fp, "Monocytes FL3 : mean = %6.2f, cv. = %6.2f\n\n", Mon.fl3.mn, Mon.fl3.cv); 584 585 fprintf (fp, "Lymphocytes -- ALL: mean = %6.2f, cv. %6.2f\n", Lym.all.mn, Lym.all.cv); fprintf (fp, "Lymphocytes -- IAS: mean = %6.2f, cv. %6.2f\n", Lym.ias.mn, Lym.ias.cv); fprintf (fp, "Lymphocytes -- FL3 : mean = %6.2f, cv. %6.2f\n", Lym.fl3.mn, Lym.fl3.cv); fclose (fp); } #endif } void mcWBCAlgorithm: :SendAlertResults (dsAlertResultSetSc alertresult) { // Send the alert results to storage: alertresult [dsBand] .Value(arBands) ; alertresult [dsBlast] .Value (arBlasts) ,- alertresult [dslmmatureGranulocyte] .Value (arIGs) ; alertresult [dsVariantLymphocyte] .Value(arVLs) ; alertresult [dsNucleatedRBC] .Value(arNRBCs) ; alertresult [dsRBCResistant] .Value (arRRBCs) ; } Boolean mcWBCAlgorithm: :SendScatResults (dsWBCScatSc scatresult) { unsigned long maxwbcscat = MIN(listcount, scatresult.MaxCells 0 ) ; Boolean algstat = TRUE; 585 586 // Send the scattergram results to storage: wbclist->Resolution(dsWBCListMode: :ALL, 8) ; wbclist->Resolution(dsWBCListMode: :ALLW, 8) ; wbclist->Resolution(dsWBCListMode: :IAS, 8) wbclist->Resolution(dsWBCListMode::PSS, 8) wbclist->Resolution(dsWBCListMode: :DSS, 8) wbclist->Resolution(dsWBCListMode: :FL3, 0) for (unsigned long i = 0; i < maxwbcscat; i ++) { dsWBCScatMeas cellmeas; cellmeas.all = (dsScatMeas)wbclist->CellMeas (i, dsWBCListMode: :ALL) ; cellmeas.allw = (dsScatMeas)wbclist->CellMeas (i, dsWBCListMode: :ALLW) ; cellmeas.ias = (dsScatMeas)wbclist->CellMeas (i, dsWBCListMode: :IAS) ; cellmeas.pss = (dsScatMeas)wbclist->CellMeas d, dsWBCListMode: :PSS) ; cellmeas.dss = (dsScatMeas)wbclist->CellMeas (i, dsWBCListMode: :DSS) ; cellmeas.f13 = (dsScatMeas)wbclist->CellMeas (i, dsWBCListMode: :FL3) ; dsWBCPopulation type = wbclist->CellPopulationd) ; algstat = algstat cS scatresult.AddCell(Sccellmeas, type) ; } // Send the discriminant values (only if it's a valid sample) : if (calcflag) { // Mononuclear-Granulocyte discriminant (ALL/PSS) : dsScatDiscriminantSc mgdisc = scatresult.Discriminant (dsWBCSeat: :MononuclearGranulocyte) 586 587 for ( int j = 0 ; j < MGLine . Length; j ++ ) { mgRealPoint mgpoint: = MGLine.Point [j ] ; mgdisc.AddPoint ( (dsScatMeas)mgpoint.x, (dsScatMeas)mgpoint.y) ; } // Lymphocyte-Stroma discriminant (IAS/ALL) : dsScatDiscriminantSc lsdisc = scatresult.Discriminant (dsWBCSeat: :LymphocyteStroma) ; lsdisc.AddPoint (0, (dsScatMeas)LNLine.Intercept0 ) ; mgRealPoint lslbpoint = LNLine.Intersec (LBLine) ; lsdisc.AddPoint ( (dsScatMeas) lslbpoint.x, (dsScatMeas) lslbpoint.y) ,- // Lymphocyte-Monocyte discriminant (IAS/ALL) : dsScatDiscriminantSc lmdisc = scatresult.Discriminant (dsWBCSeat: :LymphocyteMonocyte) ; lmdisc.AddPoint (0, (dsScatMeas)LMLine.Intercept () ) ; lmdisc.AddPoint (maxscat, (dsScatMeas)LMLine.Intercept 0 ) ; // Lymphocyte-Basophil discriminant (IAS/ALL) : dsScatDiscriminantSc lbdisc = scatresult.Discriminant (dsWBCSeat: :LymphocyteBasophil) ; lbdisc.AddPoint( (dsScatMeas)LBLine.XInt{) , 0) ; mgRealPoint lmlbpoint = LMLine.Intersect (LBLine) ,- lbdisc.AddPoint ( (dsScatMeas) (lmlbpoint.x) , (dsScatMeas) (lmlbpoint.y) ) ; // Basophil-Noise discriminant (IAS/ALL) : dsScatDiscriminantSc bndisc = 587 588 scatresult.Discriminant (dsWBCSea : :BasophilNoise) ; mgRealPoint bnlbpoint = BNLine.Intersect (LBLine) ; bndiscAddPoint ( (dsScatMeas) (bnlbpoint.x) , (dsScatMeas) (bnlbpoint.y) ) ; bndisc.AddPoint (maxscat, (dsScatMeas) (bnlbpoint.y) // Neutrophil-Eosinophil discriminant (PSS/DSS) : dsScatDiscriminantSc nedisc = scatresult.Discriminant (dsWBCSeat: :NeutrophilEosinophil) ,- nediscAddPoint (0, 0); nedisc.AddPoint (maxscat, (dsScatMeas) (maxscat ♦ NELine.Slope0 + 0.5)); // White cell-NRBC discriminant (FL3/ALL) : dsScatDiscriminantSc wrdisc = scatresult.Discriminant (dsWBCSeat: :WBC_NRBCBlast) ; wrdisc.AddPoint ( (dsScatMeas)WRLine.XInt 0 , 0); wrdisc.AddPoint ( (dsScatMeas)WRLine.XInt ( ) , maxscat) ; // NRBC-Dead cell discriminant (FL3/PSS) : dsScatDiscriminantSc rddisc = scatresult.Discriminant (dsWBCSeat: :NRBCBlast_Dead) ; mgRealPoint rdwrpoint = RDLine.Intersect (WRLine) ; rddisc.AddPoint ( (dsScatMeas) (rdwrpoint.x) , (dsScatMeas) (RDLine.Intercept 0 ) ) ; rddisc.AddPoint (maxscat, (dsScatMeas) (RDLine.Intercept 0 ) ) ; } #ifdef DIAGS // Check on data sent to "results": 588 589 FILE* fp = fopen ("scat.txt", "w" ) ; if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file 'scat.txt' .\n" ) ; } else { fprintf (fp, "ALL\tALL_W\tIAS\tDSS\tFL3\tPSS\tTYPE\n") ; for (i = 0; i < maxwbcscat; i ++) { const dsWBCScatMeas* newmeas = scatresult.CellMeas d) ; fprintf (fp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", newmeas->all, newmeas->allw, newmeas- >ias, newmeas->dss, newmeas->f13 , newmeas- >pss, scatresult.CellPopulation(i) ) ,- } fclose (fp) ; } #endif return (algstat) ; } /** * * Copyright 1993 by Abbott Laboratories * Source Code Control System keywords * 589 590 * NAME: $Source: /home/michaelf/R2- 13/inc/RCS/mcWBCAlgorithm.h,v $ * $Locker: $ * $State: Exp $ * $Revision: 1.15 $ * $Author: donp $ * $Date: 94/10/18 13:56:42 $ * Log: .. See below LANGUAGE: LynxOS Cl C++ * DESCRIPTION: * This file contains the class definition for the algorithms * used to perform the WBC differential part of the CBC. * * ....$Log: mcWBCAlgorithm.h,v $ * Revision 1.15 94/10/18 13:56:42 donp * SCR390 * Added Blast flag. Modified private members from individual variables to * a struct of variables used for diagnostics and morphology flagging. Added * two private functions; DoFinalPopEval () and DoPopStats() . * * Revision 1.14 94/10/17 14:28:42 jamesb * SCR 335: * Changed algorithm interface and calibration-factor usage to match changes * in calibration-data interface. * * Revision 1.13 94/10/10 17:00:10 jamesb * SCR 389: * Added data members to store information needed for RRBC 590 591 and NRBC flags. * * Revision 1.12 94/07/21 15:58:23 jamesb * SCR 225: * Added dil. and cal. factors to interface to WBCAlgorithm. * * Revision 1.11 94/06/22 11:44:51 jamesb * SCR 178, 179, 204: * Revised to use "m*ListMode" classes instead of "m*Cell" classes. * * Revision 1.10 94/06/16 16:46:40 jamesb * SCR 194: * Added "Stat" variable for each numerical result to report status (OK or not) . ♦ Revision 1.9 94/05/23 17:27:41 jamesb ♦ Changed "wbclist" to a pointer to allow dynamic allocation of white cells. * ♦ Revision 1.8 94/05/19 16:41:31 jamesb ♦ Changed some Boolean return values to "void", where no real choice of ♦ return values existed. * Revision 1.7 94/04/21 16:59:38 jamesb * Added flags to show default conditions taken. * * Revision 1.6 94/04/11 14:51:09 jamesb ♦ Removed "#include mgPoint.h" (no longer exists) * * Revision 1.5 94/03/22 10:42:03 jamesb * Changed the structure of "wbclist". * * Revision 1.4 94/03/07 11:35:24 jamesb 591 592 * Moved passed parameters to the constructor, made called functions virtual, * and made other changes recommended at the inspection. * * Revision 1.3 94/02/23 14:21:29 jamesb * Added null copy constructor and assignment operator. * * Revision 1.2 94/01/31 13:49:43 jamesb * Added more descriptive text to comments about public functions. * * Revision 1.1 94/01/26 15:39:03 jamesb * Initial revision #ifndef _mcWBCAlgorithm_ #define _mcWBCAlgorithm_ #include "mgAlgoDefs.h" ♦include "mgLine.h" ♦include "dsWBCMeas.h" ♦include "mcWBCListMode.h" ♦include "diSpecimenType.h" ♦include "dsCBCResults.h" ♦include "dcCalibrationData.h" ♦include "mgCellAlgorithm.h" class mcWBCAlgorithm : public mgCellAlgorithm { public: mcWBCAlgorith (const diSpecimenType& spectype, const dsWBCMeas& wbc, 592 593 dsCBCResultsSc cbcrslt, const dcCalibrationDataSc cal, int docalc = 1, int dotiming = 0, int priority = 0) ; // Constructor for the class. // Parameters: // spectype - reference to specimen-type data for the run // wbc - reference to WBC optical-transducer measurement data // cbcrslt - reference to entire set of CBC results, including numerical, // alert, scattergram, and histogram data // cal - reference to calibration factors // docalc - sets "calcflag" to TRUE or FALSE, which determines whether // the full set of calculations will be done for this algorithm. // dotiming - sets "timeflag" to TRUE or FALSE, which determines whether // timing values will be recorded (default is FALSE) . // priority - used to set the LynxOS priority for the thread containing // the algorithm operations (default is 0, normal priority) . virtual -mcWBCAlgorithm0 ; // Destructor for the class -- default action only. virtual Boolean CalcResults(void) ; // Calculates the white-cell test results from the appropriate transducer // measurements. The numerical, alert, and graphical 593 594 results calculated // include all of the WBC-specific results, which are specified in separate // files. Returns whether this algorithm completed successfully. virtual double GetTiming(int section); // Returns the results (in seconds) of the run time for the specified // section of the WBC algorithm. private: const diSpecimenTypeSc specimentype; const dsWBCMeasSc wbcmeas; dsCBCResultsSc cbcresults; const dcCalibrationDataSc caldata; Boolean calcflag; mcWBCListMode* wbclist; // Storage for white-cell listmode data unsigned long listcount; // Number of listmode data values // Numerical results: double WbcConc; // Total concentration of WBCs, in K/uL dsNumericalResult: .-NRStatus WbcStat; // Status of WBC calculation double LymphConc; // Concentration of lymphocytes, in K/uL double LymphPct; // Percent of WBCs represented by lymphocytes dsNumericalResult::NRStatus LymphStat; // Status of lymphocyte calculations double MonoConc; // Concentration of monocytes, in K/uL 594 595 double MonoPct; // Percent of WBCs represented by monocytes dsNumericalResult ::NRStatus MonoStat; // Status of monocyte calculations double BasoConc; // Concentration of basophils, in K/uL double BasoPct; // Percent of WBCs represented by basophils dsNumericalResult::NRStatus BasoStat; // Status of basophil calculations double NeutConc; // Concentration of neotrophils, in K/uL double NeutPct; // Percent of WBCs represented by neutrophils dsNumericalResult::NRStatus NeutStat; // Status of neutrophil calculations double EosConc; // Concentration of eosinophils, in K/uL double EosPct; // Percent of WBCs represented by eosinophils dsNumericalResult::NRStatus EosStat; // Status of eosinophil calculations double NrbeConc; // Concentration of nucleated RBCs, in K/uL double NrbcPct; // Percent of WBCs represented by NRBC' s dsNumericalResult::NRStatus NrbcStat; // Status of NRBC calculations double StromaPct; // Percent of "stroma" (not reported) double NoisePct; // Percent of "noise" (not reported) double FragilePct; // Percent of "fragile" cells (not reported) double DeadPct; // Percent of "dead" cells 595 596 (not reported) //Population statistics; to be used for diagnostics and flagging. struct Stats { double mn; // population mean channel location double cv; // population cv in percent }; struct PopStats { Stats all // mean of ALL population Stats ias // mean of IAS population Stats pss // mean of PSS population Stats dss // mean of DSS population Stats fl3 // mean of FL3 population }; PopStats Lym; // Lymphocyte population statistics PopStats Mon; // Monocyte population statistics PopStats Neu; // Neutrophil population statistics PopStats LymMon; // LymMon population stats for blast flag. PopStats WCells; // 5 part cells plus fragile and dead cells // that are used to determine FL3 statistics. 596 597 // Alert results: dsAlertResult: :ARValue arBands; // Status of "bands" flag dsAlertResult: :ARValue arBlasts; // Status of "blasts" flag dsAlertResult: :ARValue arIGs; // Status of "immature granulocytes" flag dsAlertResult: :ARValue arVLs; // Status of "variant lymphocytes" flag dsAlertResult: :ARValue arNRBCs; // Status of "nucleated RBCs" flag dsAlertResult: :ARValue arRRBCs; // Status of "resistant RBCs" flag // Lines for scattergram discriminants: mgPolyLine MGLine; // Discriminant line between mononuclear and // granulocytic cells, in ALL vs. PSS Boolean MG_dflt; // Default value used for mono-gran line mgLine NELine; // Discriminant line between neutrophils and // eosinophils, in PSS vs. DSS Boolean NE_dflt; // Default value used for neut-eo line mgLine LMLine; // Discriminant line between lymphocytes and // monocytes, in IAS vs. ALL Boolean LM_dflt; // Default value used for lymph-mono line mgLine LNLine; // Discriminant line between lymphocytes and // noise (stroma), in IAS vs. 597 598 ALL Boolean LN_dflt; // Default value used for lymph-noise line mgLine LBLine; // Discriminant line between lymphocytes and // basophils, in IAS vs. ALL Boolean LB_dflt; // Default value used for lymph-baso line mgLine BNLine; // Discriminant line between basophils and // noise2, in IAS vs. ALL Boolean BN_dflt; // Default value used for baso-noise2 line mgLine WRLine; // Discriminant line between white cells and // NRBCs (or blasts), in FL3 vs. ALL Boolean WR_dflt; // Default value used for white-red line mgLine RDLine; // Discriminant line between NRBCs (or blasts) // and dead cells, in FL3 vs. PSS Boolean RD_dflt; // Default value used for red-dead line // Internal performance monitoring: enum wbcalgsect { getdata, doanalysis, sendresults, maxalgsect }; 598 599 double timevalues[maxalgsect] ; // Storage for timing results. // Second-level functions, called by "mcCalcWBCResults" : void GetWBCData(const dsWBCListModeSc listdata); // Gets the necessary listmode WBC transducer measurements and // translates them into the forms appropriate for the WBC analysis. // Parameters: // listdata - reference to WBC listmode data for this run void DoWBCAnalysis(void) ; // Does the complete WBC differential analysis, generating all the // required analytical results and storing them locally. Boolean SendWBCResults(dsCBCResultsSc cbcresult); // Sends to storage all of the required numerical, alert, // and scattergram results for the completed WBC differential. // Returns whether this operation completed successfully. // Parameters: // cbcresult - entire set of CBC results, including numerical, alert, // scattergram, and histogram data // Third-level functions, called by second-level functions: void SetDefaults (void) ; // If this sample has less than the minimum number of cells, or is a 599 600 // background sample, sets everything to default values. void FindFl3Cells(void) ; // Separates the cells into "high"- and "low"-FL3 populations. void AnalyzeFl3Cells(void) ; // Separates the "high"-FL3 population into NRBC, fragile-white, and // dead-cell populations, using ALL and PSS. void FindMGLine(void) ; // Finds the separation line between the mononuclear and granulocytic // cell groups, using ALL vs. PSS. void FindNELine(void) ; // Finds the separation line between the neutrophils and eosinophils, // using PSS vs. DSS, and labels the cells in these two populations. void FindLymphLines(void) ,- // Finds the separation lines between lymphocytes and monocytes, and // between lymphocytes and "noise" (stroma), in IAS vs. ALL, and labels // the cells in these populations. void FindBasoLines(void) ; // Finds the separation lines between lymphocytes and basophils, and // between basophils and "noise2", in IAS vs. ALL, and labels the cells // in these populations. 600 601 void GetFinalCounts (Boolean validcounts); // Calculates the total WBC concentration, and the concentration and // percentage of each labeled sub-population of WBCs, and NRBC ' s. // Parameters: // validcounts -- whether there is enough listmode data for valid results. void DoFinalPopEval ( void ) ,- // Build up population histograms to be used for diagnostic and morphology // statistics. This funcion calls DoPopStats for this purpose. void DoPopStats { const mmHist256Sc hist, doubleSc mean, doubleSc cv ) ,- // Performs statitistics calculations on each WBC cell population. This is // used for calculation diagnostic results as well as population // characteristics for morphology flagging. // Parameter: // hist - histogram projection for population under consideration. // mean - mean channel location for the population. // cv - percent cv for the population. // std - standard deviation. void SetFlags (void) ; // Determines whether any of the alert-condition flags enumerated in // "dsAlertResultID" need to be set, indicating 601 602 abnormalities. void SendNumResults (dsNumer calResultSetSc numresult); // Sends all numerical results for storage and display. // Parameters: // numresult - reference to CBC numerical-results object for this run void SendAlertResults (dsAlertResultSetSc alertresult); // Sends all "alert" results for storage and display. // Parameters: // alertresult - reference to CBC alert-results object for this run Boolean SendScatResults (dsWBCScatSc scatresult); // Sends all WBC scattergram results for storage and display. // Returns whether this operation completed successfully. // Parameters: // scatresult - reference to WBC scattergram-results object for this run mcWBCAlgorithm(const mcWBCAlgorithmSc) ,- // Null copy constructor -- no copies allowed. mcWBCAlgorithmSc operator=(const mcWBCAlgorithmS); // Null assignment operator -- no assignment allowed. ); ♦endif // _mcWBCAlgorithm_ ** * ♦ Copyright 1993 by Abbott Laboratories 602 603 * .Source Code Control System keywords * * NAME: $Source: /home/larar/printme/RCS/mgCellAlgorithm.cc,v $ * $Locker: $ * $State: Exp $ * $Revision: 1.14 $ * SAuthor: larar $ * $Date: 94/11/30 17:22:44 $ * Log: .. See below LANGUAGE: LynxOS Cl C++ ♦ DESCRIPTION: ♦ This file contains the implementation for a generalized algorithm ♦ class, from which the specific classes which calculate test results ♦ can be derived. * ♦ ....$Log: mgCellAlgorithm.ccv $ ♦ Revision 1.14 94/11/30 17:22:44 larar ♦ SCR ^513: ♦ Fixed logic error in FlowTimeDiag in processing of blank samples. * ♦ Revision 1.13 94/11/30 12:31:35 larar * SCR ^513: ♦ Added method FlowTimeDiag to check if hardware count rate follows uniform ♦ distribution. * * Revision 1.12 94/11/10 14:02:00 jamesb 603 604 * SCR 491 : * Changed "SetPriority" to reset priority only if a non- default value sent. * * Revision 1.11 94/10/27 16:28:24 larar * SCR #413: * Add to ScaleDisplayHist() processing for cases of two peaks of equal height. * * Revision 1.10 94/10/27 14:38:51 jamesb * SCR 452: * Changed the "Concentration" function to return 0.0, if appropriate. * * Revision 1.9 94/10/18 12:31:49 larar * SCR #413: * Fix warning in ScaleDisplayHist. * * Revision 1.8 94/10/14 10:46:19 larar ♦ SCR 413: * Added ScaleDisplayHist0 for scaling display histograms. * * Revision 1.7 94/09/28 10:26:55 larar * SCR #360: * Added methods ReduceResolution and Interpolate. * * Revision 1.6 94/09/08 13:51:09 donp * Added argument and switch statement to Concentration method to allow * the distinction between FinalCount 0 and FinalGatedCount() from * dsCountData. * SCR315 * * Revision 1.5 94/09/08 08:15:35 larar 604 605 * SCR #309: * Added method GenericFilter. * * Revision 1.4 94/09/01 15:47:50 donp * Modified Concentration function. This function now calculates the concent- * tration off the hardware counter values directly. The argument list was * rearanged to allow for default values. The return type has been changed to * a Boolean to acknowlege any errors found. The numerical data status is also * passed as an argument. Limit tests were implemented for some of the parms. * SCR303 * * Revision 1.3 94/08/19 15:36:05 larar * SCR #252: * Added methods to calculate concentration and coincidence correction. * * Revision 1.2 94/07/14 12:15:17 jamesb * SCR 225: * Added RCS ID string. * New: * Added system calls to get or set process priority. * Revision 1.1 94/03/17 13:57:57 jamesb * Initial revision ♦include <types.h> #include <pthread.h> 605 606 #include <rw/dvech> // Rogue Wave Math.h++ #include <rw/lsqfit.h> #include "mgCellAlgorithm.h" #include "dtInternalLog.h" static const char* const RCSid = "SHeader: mgCellAlgorithm.cc,v 1.14 94/11/30 17:22:44 larar Exp $"; static const char* SourceFileName = FILE ; mgCellAlgorithm: :mgCellAlgorithm(int dotiming, int priority) timeflag(dotiming) , lynxpriority(priority) mgCellAlgorithm: :-mgCellAlgorithm( { } Boolean mgCellAlgorithm: :TimeFlag(void) { return (timeflag) ; } void mgCellAlgorithm: :SetTimeFlag(Boolean flag; { timeflag = flag; 606 607 int mgCellAlgorithm: :GetPriority (void) { lynxpriority = pthread_getprio (pthread_self ( ) ) ; return (lynxpriority) ; } void mgCellAlgorithm: :SetPriority(int priority) { if (priority > 0) { lynxpriority = priority; int retval = pthread_setprio(pthread_self ( ) , priority) ; dtlnternalLog log(SourceFileName) ; if (retval >= 0) { log « Line( LINE ) « "SetPriority: priority was " « retval « " , now set to " « priority << Flush; } else { log « Line ( LINE ) « "SetPriority: pthread_setprio returned ERROR: " « retval « Flush; } } } Boolean mgCellAlgorithm: Concentration(int counttype, 607 608 const dsCountDataS countdata. doubleSc Concentration, dsNumericalResult: :NRStatusSc status, const double popRatio, const double unitsFactor, const dcCalibrationFactor calFactor, const dcCalibrationFactor dilFactor) { double MeasTime = countdata.FinalTime( ); double FRate = countdata.FlowRate ( ); double Dil = countdata.Dilution( ); dcCalibrationData caldata; dsCountValue totalcount; switch( counttype ) { case FINAL: totalcount = countdata.FinalCount ( ); break; case GATED: totalcount = countdata.FinalGatedCount ( ) ; break; } // Let's play it safe and initialize values to 0.0 and status to NoCalc: status = dsNumericalResult: :NoCalc; Concentration = 0.0; 608 609 dtlnternalLog log(SourceFileName) ; log « Line( LINE ) << "Concentration: Hardware count: " << totalcount << Flush; log « Line ( LINE ) << "Total time: " << MeasTime « " sec" « Flush; log << Line ( LINE ) << "Flow rate: " « FRate « " uL/sec" « Flush; log « Line{ LINE ) << "Dilution factor: " « Dil « Flush; log « Line( LINE ) << "Population ratio: " << popRatio « Flush; log « Line ( LINE ) << "Units factor: " « unitsFactor « Flush; log « Line( LINE ) « "Calibration factor: " « calFactor « Flush; log « Line( LINE ) << "Dilution factor: " « dilFactor « Flush; // Test that the cal and dil Factors are valid. Boolean CalRange = caldata.InRange ( calFactor ) ,- Boolean DilRange = caldata.InRange( dilFactor ); if ((totalcount >= 0) cS (MeasTime > 0.0) ScSc (Dil >= 0.0) ScSc (FRate > 0.0) ScSc (popRatio >= 0.0) &5c (popRatio <= 1.0) Sc (unitsFactor >= 0.0) ScSc CalRange ScSc DilRange) { Concentration = (popRatio * unitsFactor * calFactor * dilFactor * totalcount * Dil) / ( FRate * MeasTime ) ,- log « Line( LINE ) 609 610 << "Concentration: " « (Concentration / unitsFactor) « " cells/uL" « Flush; if( Concentration >= 0.0 ) { status = dsNumericalResult: .-CalcOK; return( TRUE ) ; } else { status = dsNumericalResult::NoCalc; return( FALSE ) ; } } else { log « Line( LINE ) « "Concentration NOT calculated" « Flush; return( FALSE ) ; } double mgCellAlgorithm: :CoincCorrect (const double uncorrectedQ, const double effectVolume, const double dilRatio,' { double returnedVal = 0.0; double operand = 0.0; if (dilRatio > 0) { 610 611 operand = - (uncorrectedQ) * (effectVolume) / dilRatio; } else return(uncorrectedQ) ; if (operand > 0.0) returnedVal = uncorrectedQ * (2 - exp(operand) ) ; else if ( operand > log( (double)2.0) ) returnedVal = 0.0; else returnedVal = uncorrectedQ; return(returnedVal) ; void mgCellAlgorithm: :GenericFilter(const double* filter, const double* dat, const unsigned int numpass, const int filterLength, const int datLength, double* filterResult) { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) « "Top of GenericFilter" « Flush; 611 612 unsigned short iSh; // Transfer input to local array. double* loealDat = new double [datLength] ; fordSh = 0; iSh < datLength; iSh++) { loealDat [iSh] = dat.ish]; } log << Line ( LINE ) « "GenericFilter. loealDat assigned." « Flush; // Find filter midpoint bin. int midPoint = (int) floor( (double) (filterLength - 1) / 2.0); log « Line( LINE ) « "Generic Filter. Midpoint " « midpoint « Flush; // Find sum of filter elements for weighted average, double filtSum = 0.0; fordSh = 0; iSh < filterLength; iSh++) { filtSum += filterfiSh]; } // Cycle through passes. double* filtSpace = new double [ (2 * filterLength) + datLength] ; unsigned short cycle = 0; unsigned short iSh2; 612 613 for (cycle = 0; cycle < numpass; cycle++ { // Create filter space. fordSh = 0; iSh < filterLength; iSh++) { filtSpacefiSh] = 0.0; } fordSh = filterLength; iSh < (filterLength + datLength) ; iSh++) { filtSpace [iSh] = loealDat [iSh - filterLength] ; } fordSh = datLength + filterLength; iSh < (2 * filterLength + datLength); iSh++) { filtSpace[iSh] = 0.0; } // Filter. fordSh = 0; iSh < datLength; iSh++) { filterResult [iSh] = 0.0; for dSh2 = 0; iSh2 < midPoint + 1; iSh2++) { filterResult [iSh] += filtSpace[iSh + filterLength - iSh2] * filter[midPoint - iSh2] ,- } for dSh2 = 1; iSh2 < (filterLength - midPoint); 613 614 iSh2++) { filterResult [iSh] += filtSpace [iSh + filterLength + iSh2] ♦ filter[midPoint + iSh2] ; } if (filtSum > 0) { filterResult[iSh] /= filtSum; loealDat [iSh] = filterResult [iSh] ; // Update array to filter. } // Clean up. delete [] filtSpace; delete [] loealDat; Boolean mgCellAlgorithm: :ReduceResolution(const double* inputArray, const int inputSize, double* outputArray, int outputSize] { dtlnternalLog log(SourceFileName) ; 614 615 log << Line( LINE ) << "Top of ReduceResolution." « Flush; // Check conditions, if ( (inputSize <= 0) I I (outputsize <= 0) I I dnputSize < outputsize) I I (ceil( (double) (inputSize / outputsize)) != floor( (double) dnputSize / outputsize))) ) { log « Line( LINE ) « "ReduceResolution. Input condition violated. « Flush; return(FALSE) ; } // Fill outputArray. int groupSize = inputSize / outputsize; unsigned short iSh, iSh2; fordSh = 0; iSh < outputsize; iSh++) { outputArray[iSh] = 0; for(iSh2 = 0; iSh2 < groupSize; iSh2++) { outputArray[iSh] += inputArray[iSh2 + iSh ♦ groupSize] ; } outputArray[iSh] /= groupSize; } return(TRUE) ; 615 616 Boolean mgCellAlgorithm: :Interpolate(const double* inputArray, const int inputSize, const int interpPoints, double* outputArray) { dtlnternalLog log(SourceFileName) ; log << Line( LINE ) « "Top of Interpolate" « Flush; // Check initial condition. if (dnputSize <= 0) II (interpPoints == 0)) { log « Line( LINE ) « "Interpolate. Bad initial condition. " « Flush; retur (FALSE) ; } // Perform interpolation. double fraction = 1.0 / interpPoints; unsigned short iSh, iSh2; fordSh = 0; iSh < dnputSize - 1); iSh++) { for(iSh2 = 0; iSh2 < interpPoints; iSh2++) { outputArray[iSh2 + interpPoints * iSh] = ((1.0 - (iSh2 * fraction)) * inputArray[iSh] ) + ( (iSh2 * fraction) * inputArray[iSh + 1]),- 616 617 } } return(TRUE) ; } Boolean mgCellAlgorithm: :ScaleDisplayHist (const double* inHist, double^ outHist, const int maxResol, const int loSearchBin, const int hiSearchBin) { dtlnternalLog log(SourceFileName) ,- log « Line ( LINE ) « "Top of ScaleDisplayHist." « Flush; // Check mode search conditions. Boolean conditionFlag = TRUE; if (loSearchBin >= hiSearchBin) { conditionFlag = FALSE; } // Find mode using mmHist256 objects. unsigned short iSh; mmHist256 searchHist; 617 618 fordSh = 0; iSh < searchHist.HistRes; iSh++! { searchHist[iSh] = (int) inHist [iSh] ; } int peakVal = 0; int peakLoc = 0; if (conditionFlag == TRUE) { iSh = loSearchBin; while( (iSh < hiSearchBin - 1) ScSc (searchHist.PeakdSh, hiSearchBin) <= 0 ) { iSh++; } peakLoc = searchHist.Peak(iSh, hiSearchBin); if (peakLoc >= loSearchBin) { peakVal = (int ) inHist [peakLoc] ; log « Linet LINE ) « "ScaleDisplayHist. peakLoc " << peakLoc « Flush; log « Line ( LINE ) « "ScaleDisplayHist. peakVal " << peakVal « Flush; } if (peakVal <= 0) { conditionFlag = FALSE; 618 619 // Scale and assign returned histogram. fordSh = 0; iSh < searchHist.HistRes; iSh++) { if (conditionFlag == TRUE) { outHistfiSh] = (double) (mgDisplayFract * maxResol * inHist [iSh] / peakVal) ; } else { outHist[iSh] = inHist[iSh] ; } } return(conditionFlag) ; } Boolean mgCellAlgorithm: :FlowTimeDiag(const dsCountDataSc countlnfo) { dtlnternalLog ilog(SourceFileName) ; ilog « Line( LINE ) « "Top of FlowTimeDiag." « Flush; Boolean goodFlow = TRUE; // Return value. // Create vectors of cumulative counts and times. unsigned iSh; unsigned numPoints = 0; 619 620 if (countlnfo.Size 0 > 4) // Need three points east squares. { numPoints = (unsigned)countlnfo.Size( ) - 1; goodFlow = TRUE; } else { goodFlow = FALSE; ilog « Line ( LINE ) « "FlowTimeDiag. Too few points." « Flush; } if (goodFlow == TRUE) { DoubleVec flowTime(numPoints, 0.0); DoubleVec cumulCount (numPoints, 0.0); fordSh = 0; iSh < numPoints; ish++) { flowTime [iSh] = iSh + 1; cumulCount[iSh] = countlnfo.Count (iSh + 1); } if (cumulCount [numPoints - 1] == 0) { goodFlow = FALSE; } if (goodFlow == TRUE) { 620 621 // Perform least squares fit. LeastSqFit lsf (flowTime, cumulCount); // Return decision based on correlation coefficient. if (lsf.correlationCoeff ( ) < flowTimeDiagThresh) { goodFlow = FALSE; ilog « Line( LINE ) « "FlowTimeDiag. Bad flow statistics. " « Flush; } } } return(goodFlow) ,- } ** * * Copyright 1993 by Abbott Laboratories * Source Code Control System keywords * * NAME: $Source: /home/larar/printme/RCS/mgCellAlgorithm.h,v $ * $Locker: $ 621 622 $State: Exp $ $Revision: 1.10 $ $Author: larar $ $Date: 94/11/30 12:37:26 $ Log: .. See below LANGUAGE: LynxOS Cl C++ * DESCRIPTION: ♦ This file contains the class definition for a generalized algorithm ♦ class, from which the specific classes which calculate test results ♦ can be derived. * ♦ ....$Log: mgCellAlgorithm.h,v $ ♦ Revision 1.10 94/11/30 12:37:26 larar ♦ SCR #513: ♦ Added method FlowTimeDiag to check if hardware count rate follows uniform ♦ distribution. * ♦ Revision 1.9 94/10/14 10:45:20 larar ♦ SCR #413: ♦ Added ScaleDisplayHist 0 for scaling display histograms. * ♦ Revision 1.8 94/09/28 10:28:54 larar ♦ SCR #360: ♦ Added methods ReduceResolution and Interpolate. * ♦ Revision 1.7 94/09/08 13:52:50 donp ♦ Added argument and switch statement to Concentration method to allow ♦ 622 623 * the distinction between FinalCount () and FinalGatedCount fromth * Added enum FinalCountType. * SCR315 * * Revision 1.6 94/09/08 08:17:33 larar * SCR #309: * Added method GenericFilter. * * Revision 1.5 94/09/01 15:53:59 donp * Modified Concentration function. This function now calculates the concent- * tration off the hardware counter values directly. The argument list was ♦ rearanged to allow for default values. The return type has been changed to * a Boolean to acknowlege any errors found. The numerical data status is also * passed as an argument. Limit tests were implemented for some of the parms. * SCR303 * * Revision 1.4 94/08/19 15:37:32 larar * SCR #252: ♦ Added methods to calculate concentration and coincidence correction. * * Revision 1.3 94/03/07 11:39:17 jamesb * Made all public functions virtual to match derived classes, and made * other changes recommended at the inspection. * * Revision 1.2 94/02/23 14:15:19 jamesb * Added null copy constructor and assignment operator. * 623 624 * Revision 1.1 94/01/26 15:40:25 jamesb * Initial revision #ifndef _mgCellAlgorithm_ #define _mgCellAlgorithm_ #include "cd4000.h" #include "dtObject.h" #include "dsListMode.h" #include "dcCalibrationData.h" #include "mmHist256.h" #include "dsCountData.h" ttinclude "dsNumericalResult.h" // Non-integer constants. const double mgDisplayFract = 0.70; $ // Fraction of full display scale // that a displayed histogram mode // should be. const double flowTimeDiagThresh 0.90; // If the correlation coefficient // of least squares fit through // (cumulative hardware count vs. // time falls below this, trigger // flow/time diagnostic flag. 624 625 class mgCellAlgorithm : public dtObject { public: mgCellAlgorithm (int dotiming = 0, int priority = 0) ; // Constructor for the base class, which includes parameters to determine // whether the run time of any inherited algorithm class will be // recorded while it is running (for performance analysis) . // Parameters: // dotiming - sets "TimeFlag" to TRUE or FALSE, which determines whether // timing values will be recorded (default is FALSE) . // priority - used to set the LynxOS priority for the thread containing // the algorithm operations (default is 0, normal priority) . -mgCellAlgorithm ( ) ,- // Destructor -- default action only. virtual Boolean CalcResults (void) = 0; // Calculates the algorithm test results from the appropriate transducer // measurements. The numerical and alert results calculated include // all of the algorithm-specific results, which are specified in separate // files. Returns whether this algorithm completed successfully. virtual double GetTiming (int section) = 0; 625 626 // Returns the results (in seconds) of the run time for the specified // section of a specific algorithm. // Each algorithm is responsible for setting up an array of timing // values appropriate to its own architecture, and providing the // functions to put the proper timing values into this array. protected: enum FinalCountType { FINAL, GATED }; Boolean TimeFlag (void) ,- // Returns the value of "timeflag", indicating whether timing values // should be recorded for each part of the algorithm. void SetTimeFlag (Boolean flag) ; // Sets "timeflag" to TRUE (record timing values) or FALSE. int GetPriority (void) ; // Returns the current LynxOS priority. void SetPriority (int priority) ; // Sets the LynxOS priority for the thread containing the algorithm // operations to "priority" (0 is normal priority) . 626 627 Boolean mgCellAlgorithm: Concentration( int counttype, const dsCountDataSc countdata, doubleSc Concentration, dsNumericalResult: :NRStatusSc status, const double popRatio = 1.0, const double unitsFactor = 1.0, const dcCalibrationFactor calFactor = 1.0, const dcCalibrationFactor dilFactor = 1.0 ) ; // Returns TRUE if sucessful. The dilution ratio, count time and flow // rate (from countdata) are tested for lower limits but not upper // limits. The popRatio , calFactor and dilFactor's are tested for both // lower and upper limits. The unitsFactor is only tested for a lower // limit. It is the responsiblity of the developer to pass a reasonable // upper limit for unitsFactor. // counttype: either FINAL or UNGATED. // countdata: ratio, count time and flowrate. // Concentration: return of concentration result. // status: numerical result status. // popRatio: Proportion of events in population of interest. // unitsFactor: Adjusts the units for reporting concentration. // calFactor: Calibration factor. 627 628 // dilFactor: Dilution factor. double CoincCorrect ( const double uncorrectedQ, const double effectVolume, const double dilRatio) ; // Performs transducer coincidence correction and returns a // coincidence-corrected quantity (i.e. RBC count) . // uncorrectedQ: Uncorrected quantity in absolute counts. // effectVolume: Effective sensing volume in uL. // dilRatio: Dilution ratio of stream. void GenericFilter( const double* filter, const double* dat, const unsigned int numpass, const int filterLength, const int dataLength, double* filterResult); // Filters an array of doubles using a nonspecific filter. // Filter length may be greater than data length. // Assumes that resulting array is of same length as input // data array. // If filter is zero: result is set to zero. // filter: Array containing filter. // dat: Array containing data to filter. // numpass: Number of filter passes. II filterLength: Length of filter array. II dataLength: Length of data array. I I filterResult: Resulting filtered array. 628 629 Boolean ReduceResolution(const double* inputArray, const int inputSize, double* outputArray, int outputsize) ; // Creates an outputArray by averaging the elements of inputArray // at regular intervals. // Arguments: // inputArray: Array providing elements to average. // inputSize: Number of elements in inputArray. // outputArray: Array made of averages of elements of inputArray. // outputsize: Number of elements in outputArray. // // Conditions: // inputSize >= outputsize. // Both inputSize and outputsize > 0. // inputSize is an integer multiple of outputsize. // // Return value: // TRUE if operation OK, FALSE if any of the conditions above // are violated. In this case the contents of outputArray are not // guaranteed. Boolean Interpolate (const double* inputArray, const int inputSize, const int interpPoints, double* outputArray) ; // Creates an outputArray by interpolating 629 630 interPoints-1 points // between the elements of inputArray. // Arguments: // inputArray: Array providing elements for interpolation. // inputSize: Number of elements in inputArray. // interpPoints: Number of elements in outputArray per // element in inputArray. (Number of interpolated // points is interpPoints - 1. ) // outputArray: Array made by interpolating between elements // of inputArray. // Conditions: // 1) Number of elements in outputArray = inputSize * interpPoints. // The last element of inputArray is not explicitly transferred // to outputArray. This condition is not explicitly // checked. // 2) inputSize > 0. // 3) interpPoints > 0. // Returns: // TRUE if operation OK, FALSE if conditions 2) or 3) violated, // in which case the contents of outputArray are not guaranteed. Boolean ScaleDisplayHist(const double* inHist, double* outHist, const int maxResol, 630 631 const int loSearchBin, const int hiSearchBin) ; // Scales a display impedance histogram such that the highest histogram // point is mgDisplayFract * mode, where mode is the maximum count // between bins loSearchBin and hiSearchBin, inclusive. // // Arguments: // inHist: Input histogram. The mode is found from this // histogram. // outHist: Resulting scaled histogram, // of inHist = size of outHist. // maxResol: Maximum resolution of histogram in vertical // dimension. // loSearchBin: Bin marking lower end of range in which to // search for mode of inHist. // hiSearchBin: Bin marking upper end of range in which to // search for modeof inHist. // // Unchecked assumptions: // Both inHist and outHist are of size 256 bins // // Conditions: // loSearchBin < hiSearchBin. // histogram mode is nonzero. I I II Returns 631 632 // TRUE if operation OK, FALSE if the above conditions are // violated. // outHist returns inHist unsealed if the conditions are violated. Boolean FlowTimeDiag(const dsCountDataSc countlnfo); // Checks whether a measurement stream has a flow rate which follows // a uniform distribution within a 95% confidence interval . // // Arguments: // countlnfo: Reference to count data. // // Returns: // TRUE if assumption of uniform distribution is OK. // FALSE if assumption violated or no measurements present. private: Boolean timeflag; int lynxpriority; double cone; mgCellAlgorithm (const mgCellAlgorithmSc); // Null copy constructor -- no copies allowed. mgCellAlgorithmSc operator= (const mgCellAlgorithmSc) ; // Null assignment operator -- no assignment allowed. >; #endif // _mgCellAlgorithm_ 632 633 * * * _ . * Copyright 1993,95 by Abbott Laboratories * Source Code Control System keywords * * NAME: $Source: /usr3/FileServer/usr/eds/rtc/RCS/mrRETCAlgorithm.cc,v $ * $Locker: $ * $State: R4 $ * $Revision: 2.8 $ * $Author: eds $ * $Date: 95/03/28 11:13:55 $ * Log: .. See below * LANGUAGE: GNU g++ ♦ DESCRIPTION: ♦ This file contains the implementation for all the algorithms ♦ used to calculate reticulocyte test results. * ♦ .... $Log: mrRETCAlgorithm.ee,v $ ♦ Revision 2.8 95/03/28 11:13:55 eds ♦ Reset scaling factor from lx back to 5x in SendHistResults ♦ ♦ Revision 2.7 95/03/24 16:03:28 eds ♦ SCR 699: Fixed bug in FindRETCs member function. ♦ 1) Do not look for an RBC peak in the default RETC Zone if an RBC peak exists in its expected location. ♦ 2) Do not search for a valley between the RBC peak and the 633 634 RETC peak beyond the RETC peak. * Also: Some re-formatting, adding more comments, and changing the names of the cursor data members to better reflect their purpose. * Revision 2.6 95/03/22 16:42:15 eds * SCR 697. Range Checking. * Ensured that the HFR cursor would not move outside the RBC Gate. * Ensured that the retcresults.RETCHis 0 histogram would not be scaled to ZER. * * Revision 2.5 95/03/21 10:27:27 eds * SCR 689: Process RETC Background. * Installed DoBackground member function. * Installed BACKGROUND manifest for testing backgrounds. * Moved RETC concentration into RetieConc member function. * Installed 'counts.diag' diagnostic output file. * Also, some format changes. * Revision 2.4 95/02/22 13:44:23 jamesb * SCR 633: * Added a default setting for the high-fluorescence-region discriminant line. * * Revision 2.3 95/02/06 14:47:31 jamesb * SCR 600: * Commented out "#define DIAGS" for production version of code. ♦ Revision 2.2 95/02/03 11:56:21 jamesb ♦ SCR 524: ♦ Replaced "ftime" with "ge timeofday" (for new compiler) ♦ SCR 600: ♦ Changed reticulocyte method to "FLl-derivative" method. 634 635 * * Revision 2.1 95/01/10 09:34:54 michaelf * SCR 524: * Update the Language line * * Revision 1.17 94/12/09 13:30:15 jamesb * SCR 541: * Added calculations for means and c.v.'s for RBCs and reticulocytes. * Revision 1.16 94/10/18 17:24:31 jamesb * SCR 359: * Added a function to send raw data summaries to results. * ♦ Revision 1.15 94/10/17 14:15:32 jamesb * SCR 335: * Changed algorithm interface and calibration-factor usage to match changes * in calibration-data interface. * * Revision 1.14 94/10/13 13:10:13 jamesb * SCR 393: * Changed calls to scattergram discriminants to match change in interface. * * Revision 1.13 94/10/11 16:01:21 jamesb * SCR 388: * Added more protection against bizarre samples, and bad return values ♦ from "mmHist256" routines. * * Revision 1.12 94/09/30 13:44:47 Johns * SCR 373: * Enable calculations for standard reference specimens. The calculations 635 63 6 ♦ in this case are the same as for background specimens. * ♦ Revision 1.11 94/09/28 17:34:38 jamesb ♦ SCR 364, 365: ♦ Change calculations to produce reticulocyte results in K/uL; ♦ change search for RBC peak to start with channel 5 and avoid possible ♦ channel-0 (non-fluorescent) "peaks" on some machines. * ♦ Revision 1.10 94/09/21 14:51:47 jamesb ♦ SCR 353: ♦ Added more diagnostic statements, and checks on values returned from "Peak". * ♦ Revision 1.9 94/09/21 12:33:28 jamesb ♦ SCR 353: ♦ Added more diagnostic statements, sent to InternalLog. * Revision 1.8 94/08/25 11:59:52 jamesb ♦ Fixed display error introduced by R3 change. * ♦ Revision 1.7 94/08/24 14:25:06 jamesb ♦ Incorporated suggestions from R2 and R3 reviews. * ♦ Revision 1.6 94/08/22 17:28:01 jamesb ♦ Recalibrated HFR cutoff with new set of normal files. * ♦ Revision 1.5 94/07/29 10:38:19 jamesb * Added code to send all results to storage. * ♦ Revision 1.4 94/07/21 16:25:52 jamesb ♦ SCR 225: ♦ Added dil. and cal. factors to RETCAlgorithm interface. 636 637 * Revision 1.3 94/07/14 12:32:15 jamesb * SCR 222: * Added RCS ID string. * * Revision 1.2 94/05/12 16:07:23 jamesb * Fixed several incompatibilities with class definition and includes. * Revision 1.1 94/05/12 14:40:39 michaelf * Initial revision #include <stdio.h> ♦include <types.h> ♦include "dtlnternalLog.h" ♦include "mrRETCAlgorithm.h" static const char* const RCSid = "$Header: mrRETCAlgorithm.ccv 2.8 95/03/28 11:13:55 eds R4 $"; static const char* SourceFileName = FILE // Send results out to diagnostic files, if DIAGS is defined: // ♦define DIAGS // ♦define BACKGROUND // WARNING: It MUST always be the case that // RR_defval + HFR_offset < RW_defval. static const unsigned long mincount = 500; static const int smbcount = 3; static const int histMax = mmHist256::HistRes - 1; static const int histRes = mmHist256::HistRes; 637 638 static const int RP_dfltCursor = 170 static const int RW_dfltCursor = 200 static const int RR_dfltCursor = 120 static const int HFR offset = 24; mrRETCAlgorithm: .-mrRETCAlgorith (const diSpecimenTypeSc spectype, const dsRETCMeasSc retc, const dsCBCResultsSc cbcrslt, dsRETCResultsSc retcrslt, const dcCalibrationDataSc cal, int dotiming, int priority) : specimentype(spectype) , retcmeas(retc) , cbcresults(cbcrslt) , retcresults(retcrslt) , caldata(cal) { SetTimeFlag( (Boolean)dotiming) ; SetPriority(priority) ; dtlnternalLog log(SourceFileName) ; log « Line( LINE ) « "Creating reticulocyte algorithm class" « Flush; } mrRETCAlgorithm: :-mrRETCAlgorithm() { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) « "Deleting reticulocyte algorithm class" « Flush; 638 639 Boolean mrRETCAlgorithm: :CalcResults(void) { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) << "Entering reticulocyte algorithm 'CalcResults' function" « Flush; // Get the specimen-type data for this sample; skip doing full // calculations if it's a background sample; return a failure // if it's an improper type: if ( (specimentype.Type() == diSpecimenType: :PatientSpecimen) ScSc (specimentype.Patient() == diSpecimenType: :Human) ) calcflag = TRUE; else if (specimentype.Type0 == diSpecimenType: :QCSpecimen) calcflag = TRUE; else if (specimentype.Type0 == diSpecimenType: :BackgroundSpecimen) { calcflag = FALSE; doBackground = TRUE; } else if (specimentype.TypeO == diSpecimenType: :StdRefSpecimen) calcflag = FALSE; else return (FALSE) ; ♦ifdef BACKGROUND 639 640 log << Line( LINE ) << "fake-background" « Flush; calcflag = FALSE; doBackground = TRUE; #endif // Send raw summary results for all measurements: log « Line( LINE ) << "Sending reticulocyte raw-data summary" « Flush; SendRawSummary() ; double start = GetSysTime() ; GetRETCData(retcmeas.List 0 ) ; double stop = GetSysTime() ,- timevalues[getdata] = stop - start; if( doBackground ) { start = GetSysTime{) ; DoBackground() ; stop = GetSysTime0 ; timevalues[doanalysis] = stop - start; } else { start = GetSysTime0 ; DoRETCAnalysis() ,- stop = GetSysTime() ,- timevalues[doanalysis] = stop - start; start = GetSysTime() ; SendRETCResults() ; stop = GetSysTi eO; timevalues[sendresults] = stop - start; 640 641 // Clean up listmode storage: delete (retclist); #ifdef DIAGS // Print out timing values: FILE* fp = fopen( "retctime.diag" , "w"); if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file 'retctime.diag' .\n") ; } else { fprintf (fp, "Section-time values:\n"); fprintf (fp, "\tGet data: %6.3f secΛn", GetTiming(getdata) ) ; if( doBackground ) { fprintf(fp, "\tDo background: %6.3f secΛn", GetTiming(doanalysis) ) ; } else { fprintf (fp, "\tDo analysis: %6.3f secΛn", GetTiming(doanalysis) ) ; } fprintf (fp, "XtSeήd results: %6.3f secΛn", GetTiming (sendresults) ) ; fclose (fp) ; } ♦endif log « Line ( LINE ^ ) « "Finished reticulocyte analysis; exiting 'CalcResults' function" 641 642 « Flush; return (TRUE) ; } void mrRETCAlgorithm: :SendRawSummary(void) { dsRawRETCSummarySc rawretc = retcresults.RawRETC ( ) ; rawretc.Extract (retcmeas) ; } double mrRETCAlgorithm: :GetTiming(int section) { if (section < maxalgsect) return (timevalues [section] ) ; else return (0.0) ; } double mrRETCAlgorithm: :GetSysTime(void) { struct timeval tm; struct timezone tz; gettimeofday(Sctm, Sctz) ; return ( (double) tm.tv_sec + (double) tm.tv_usec / 1000000); } void mrRETCAlgorithm: :GetRETCData (const dsRETCListModeSc listdata) 642 643 dtlnternalLog log(SourceFileName) ; log << Line( LINE ) << "Entering 'GetRETCData' function" << Flush; // Get the listmode count from dsRETCListMode: listcount = listdata.NumberCellsO ; // Create storage for listmode data: retclist = new mrRETCListMode(listdata) ; // Initialize listmode data, setting each cell type to "unknown" : for (unsigned long i = 0; i < listcount; i ++) retclist->CellPopulation(dsRETCUnknown, i); } void mrRETCAlgorithm: :DoRETCAnalysis(void) { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) « "Entering 'DoRETCAnalysis' function" « Flush; // Initial validity check: if less than the minimum number of cells // or RBC concentration is less than 1 M/uL then set all values to // defaults and skip the full analysis. double rbcconc = 0.0; if( Sccbcresults != NULL ) rbcconc = cbcresults.Number() [dsRBCConc] .Value0 ,- 643 644 ♦ifdef DIAGS if ( listcount < mincount ) calcflag = FALSE; ♦else if ( (listcount < mincount) I I rbcconc < 1 ) calcflag = FALSE; ♦endif if (! calcflag) { char outstr[100]; sprintf (outstr, "Listmode count is %d; RBC is %5.2f; Setting default values.", (int) listcount, rbcconc ); log « Line ( LINE ) « outstr « Flush; SetDefaults( ) ; return; } // Locate and label the platelets, using the IAS histogram: FindPLTs () ; // Locate and label the WBCs, using the FLl histogram: FindWBCsO; // Locate and label the reticulocytes, using the FLl histogram: FindRETCs ( ) ; // Calculate the concentration and percentage of reticulocytes, and RMI: GetFinalCounts(calcflag) ; } 644 645 void mrRETCAlgorithm: :DoBackground(void) { dtlnternalLog log (SourceFileName) ; log « Linet LINE ) << "Entering 'DoBackground' function" « Flush; SetDefaults ( ) ; // Run through the listmode to collect the counts // in both the RBC Gate and in the RETC Zone: retclist->Resolution(dsRETCListMode: :IAS, 0) ; retclist->Resolution(dsRETCListMode: :FL1, 0) ; unsigned short ias, fll; gatedcount = 0; retccount = 0; for( unsigned long i = 0; i < listcount; i++ ) { ias = (dsScatMeas)retclist->CellMeasd, dsRETCListMode: :IAS) ; fll = (dsScatMeas)retclist->CellMeas (i, dsRETCListMode: :FLl) ; if( ias >= RP_dfltCursor ScSc fll <= RW_dfltCursor ) { gatedcount++; // count events in RBC gate if( fll >= RR_dfltCursor ) { retccount++; // count events in RETC Zone } } // Calculate % reticulocytes double retcpct = 0.0; 645 646 if( gatedcount > 0 ) { retcpct = 100.0 * (double)retccount / (double)gatedcount; } // Calculate reticulocyte concentration: CalcReticConc( retcpct ) ; } void mrRETCAlgorithm: :SendRETCResults(void) { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) << "Entering 'SendRETCResults' function" « Flush; // Send the numerical results to storage: SendNumResults(retcresults.Number0 ) ; // Send the scattergram results to storage: SendScatResults(retcresults.RETCScat 0 ) ; // Send the histogram results to storage: if( !doBackground ) SendHistResults(retcresults.RETCHist0 ) ; } void mrRETCAlgorithm: :SetDefaults(void) { // Set everything to default values and return: GetFinalCounts(FALSE) ; RPLine.Reset( (double)RP_dfItCursor) ; 646 647 RP_dflt = TRUE; RWLine.Reset (0.0, (double)RW_dfItCursor) ; RWcursor = RW_dfItCursor; RW_dflt = TRUE; RRcursor = RR_dfItCursor,- HFRcursor = RR_dfItCursor + HFR_offset; RR_dflt = TRUE; } void mrRETCAlgorithm: :FindPLTs (void) { // Build up the IAS histogram: retclist->Resolution(dsRETCListMode: :IAS, 0) ; for (unsigned long i = 0; i < listcount; i ++) IAS_hist.AddCount ( (int)retclist->CellMeas (i, dsRETCListMode: :IAS) ) ; // Smooth this histogram: mmHist256 smhist = IAS_hist.SmBinom(smbcount) ; for (int j = 0; j < histRes; j ++) IAS_smhist[j ] = smhist[j]; // Look for a valley in the histogram for a separation line: int min = 150; int max = 190; int iasval = IAS_smhist .Valley(min, max); // If no valley is found, use a default value: RP_dflt = FALSE; if ( (iasval <= min) I I (iasval >= max) ) { 647 648 iasval = RP_dfItCursor; RP_dflt = TRUE; } // Set value of red cell-platelet discriminant line, based on this valley: RPLine.Rese ( (double) iasval) ; // Label everything below this line as "platelets": for (i = 0; i < listcount; i ++) { if ( (retclist->CellMeas d, dsRETCListMode: :IAS) ) < iasval) { retclist->CellPopulation(dsRETCPLT, i); } } ♦ifdef DIAGS // Check on data in histogram: FILE* fp = fopen("ias.diag", "w") ; if (!fp) { fprintf (stderr, "NnWarning: Unable to open output file 'ias.diag' .\n") ,- } else { fprintf (fp, "Reticulocyte Log-IAS histogram (smoothed) :\n") ; for (j = 0; j < 256; j ++) { fprintf (fp, "%d\t", j) ; fprintf (fp, "%d\n", IAS_smhist[j] ) ; } 648 649 fprintf (fp, "XnAlgorithm results: \n" ) ; fprintf (fp, "\tPlatelet-Red cell division: %5d\n" iasval) ; if (RP_dflt) fprintf (fp, "\t (Default value used)\n"); fclose (fp) ; } ♦endif } void mrRETCAlgorithm: :FindWBCs (void) { // Build up the FLl histogram: retclist->Resolution(dsRETCListMode::FLl, 0) ; for (unsigned long i = 0; i < listcount; i ++) if (retclist->CellPopulation(i) == dsRETCUnknown) FLl_hist.AddCount ( (int)retclist->CellMeas (i, dsRETCListMode: :FL1) ) ; // Smooth this histogram: mmHist256 smhist = FLl_hist.SmBinom(smbcount) ; for (int j = 0; j < histRes; j ++) FLl_smhist[j] = smhist[j]; // Look for a valley in the histogram for a separation line: int min = 175; int max = 225; int fllval = FLl_smhist.Valley(min, max); // If no valley is found, use a default value: RW_dflt = FALSE; if ((fllval <= min) I I (fllval >= max)) { 649 650 fllval = RW_dfItCurso ; RW_dflt = TRUE; } // Set value of red cell-white cell discriminant line, based on this valley: RWLine.Reset (0.0, (double) fllval) ; RWcursor = (int)RWLine.Intercept 0 ,- // Label everything above this line as "WBCs": for (i = 0; i < listcount; i ++) { if ( ( (retclist->CellMeas(i, dsRETCListMode: :FLl) ) > fllval) ScSc (retclist->CellPopulation(i) == dsRETCUnknown) ) { retclist->CellPopulation(dsRETCWBC, i) ; } } } void mrRETCAlgorithm: :FindRETCs (void) { const double peakFract = 0.60; // fraction of peak to begin scan const int mask = 5; // ignore all channels below this value int fract = 0; // initial altitude of scan int currChan = 0; // current channel for an iteration int rbcPeak = mgFailure; // channel ♦ of RBC peak // Zero out the white-cell part of the FLl histogram: 650 651 fort currChan = RWcursor; currChan < histRes; currChan++ ) FLl_hist [currChan] = FLl_smhist [currChan] = 0; //// // Find the RBC peak in the FLl histogram: // 1) ignore all channels below the mask (to avoid confusion // between a saturated channel and the RBC peak) // 2) do not allow the RBC peak to be within the default RETC Zone // (to avoid confusion between any RETC peak and the RBC peak // in those high-RETC samples where the RETC mode may be // numerically greater than the RBC mode) //// rbcPeak = FLl_smhist.Peak( mask, RR_dfItCursor ) ,- //// // Set the RRcursor: //// if ( rbcPeak <= mask ) { RR_dflt = TRUE; RRcursor = RR_dfItCursor; } else { RR_dflt = FALSE; // set initial altitude of the scan 651 652 fract = (int) (FLl_smhist [rbcPeak] ♦ peakFract) ; // set the initial channel # of the scan currChan = rbcPeak; while ( (FLl_smhist [currChan] > fract) ScSc (currChan < RWcursor) ) { currChan++; } // scan for the first plateau beyond the // initial channel ♦ and set the RRcursor for( ,- currChan < RWcursor; currChan++ ) { if ( ( (FLl_smhist [currChan] - FLl_smhist[currChan- 1] ) >= -1) ScSc ( (FLl_smhist [currChan+1] - FL1_smhist [currChan] ) >= -1) ) { RRcursor = currChan; break; } } } // Label every unlabeled event above // the RRcursor as reticulocytes and // every unlabled event on or below // the RRcursor as red blood cells: for( unsigned long i = 0; i < listcount; i++ ) { 652 653 if( retclist->CellPopulation(i) == dsRETCUnknown ) { if ( (retclist->CellMeas (i, dsRETCListMode: :FLl) > RRcursor ) retclist->CellPopulation(dsRETC, i) ; else retclist->CellPopulation(dsRETCRBC, i) ; } } ♦ifdef DIAGS // Check on data in histogram: FILE* fp = fopen( "fll.diag", "w"); if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file 'fll.diag' .\n") ,- } else { fprintf (fp, "Reticulocyte Log-FLl histogram (smoothed) : \n" ) ; for (int j = 0; j < 256; j ++) { fprintf (fp, "%d\t", j); fprintf (fp, "%d\n", FLl_smhist[j] ) ; } fprintf (fp, "XnAlgorithm results:\n" ) ; fprintf (fp, "\tRed cell-White cell division: %5d\n", RWcursor); if (RW_dflt) fprintf (fp, "\t (Default value used)\n"); fprintf (fp, "\tRed cell-Reticulocyte division: %5d\n", RRcursor); fprintf(fp, "\t ('FLl-derivative' method used) \n" ) ,- 653 654 fclose (fp) ,- } ♦endif } void mrRETCAlgorithm: :GetFinalCounts (Boolean validcounts) { dtlnternalLog log(SourceFileName) ; char outstr[100] ; // If not a valid sample or if a // background set default values: if (1 validcounts) { RetcConc = RetcPct = 0.0; RPStat = RCStat = dsNumericalResult: :NoCalc; RMI = 0.0; RMIStat = dsNumericalResult::NoCalc; log « Line( LINE ) « "Reticulocyte defaults set" « Flush; return; // Count total red cells and reticulocytes: gatedcount = FLl_hist.GetCount (0, RWcursor); retccount = FLl_hist.GetCount (RRcursor, RWcursor); // Set HFR limit, based on Bruce Davis-type calibration: HFRcursor = RRcursor + HFR_offset; HFRcursor = MIN( HFRcursor, RWcursor ); unsigned long hfrcount = FLl_hist.GetCount (HFRcursor, RWcursor) ,- 654 655 // Calculate % reticulocytes: if (gatedcount > mincount) { RetcPct = 100.0 * (double)retccount / (double) gatedcount; RPStat = dsNumericalResult::CalcOK; } else { RetcPct = 0.0; RPStat = dsNumericalResult: :NoCalc; sprintf (outstr, "Gated count is %d; %%R is 0.", (int)gatedcount) ; log « Line ( LINE ) « outstr « Flush; } // Calculate RMI: if ((gatedcount > mincount) ScSc (retccount > 0)) { RMI = 100.0 * (double)hfrcount / (double)retccount; RMIStat = dsNumericalResult: :CalcOK; } else { RMI = 0.0; RMIStat = dsNumericalResult::NoCalc; } log « Line( LINE ) << "GetFinalCounts: listmode: " « listcount « " ,- gated: " << gatedcount « " ; HFR: " « hfrcount « Flush; sprintf (outstr, "GetFinalCounts: RETC percentage: 655 656 %5.2f%%; RMI: %5.2f%%", RetcPct, RMI) ; log << Line ( LINE ) << outstr « Flush; CalcReticConc ( RetcPct void mrRETCAlgorithm: :CalcReticConc ( double retcpct ) { dtlnternalLog log(SourceFileName) ; char outstr[100]; // Calculate absolute concentration of reticulocytes: if (Sccbcresults != NULL) { log « Line( LINE ) « "GetFinalCounts: CBCResults* valid: Using impedance RBC result" « Flush; double rbcconc = cbcresults.Number0 [dsRBCConc] .Value 0 ; dsNumericalResult: :NRStatus rbcstat = cbcresults.Number() [dsRBCConc] .StatO ; if ((rbcconc == 0) I I (rbcstat == dsNumericalResult: :NoData) I I (rbcstat == dsNumericalResult: :NoCalc) ) { RetcConc = 0.0; RCStat = rbcstat; } else { RetcConc = rbcconc * retcpct * 10.0; // to get cone in K/uL 656 657 RCStat = rbcstat; } sprintf (outstr, "RBC concentration: %5.2f M/uL; RETC concentration: %5.2f K/uL", rbcconc, RetcConc) ; log « Line ( LINE ) « outstr « Flush; } else { log « Line( LINE_) << "GetFinalCounts: CBCResults* NULL: Using RETC hardware count" << Flush; const dsCountDataSc countdata = retcmeas.Count 0 ; dsCountValue totalcount = countdata.FinalCount 0 ; double dilution = countdata.Dilution0 ; // dimensionless factor double flowrate = countdata.FlowRate0 ; // in ul/sec double time = countdata.FinalTime0 ; // in sec double volume = flowrate * time; // in ul double totaleonc = 0.0; double rbcconc = 0.0; double rbcfract = 0.0; if (volume > 0.0) { totaleonc = totalcount * dilution / volume; // in cells/ul rbcfract = (double)gatedcount / (double) listcount; rbcconc = rbcfract * totaleonc / 1000000; // to get cone in M/uL RetcConc = rbcconc * retcpct * 10.0; // to get cone, in K/uL 657 658 RCStat = dsNumericalResul ::CalcOK; } else { RetcConc = 0.0; RCStat = dsNumericalResult::NoCalc; } ♦ifdef DIAGS // print-out counts and intermediates FILE* fp = fopen( "counts.diag" , "w"); if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file ' counts.diag' . \n" ) ,- } else { fprintf (fp, ΛtListmode %lu\n", listcount) ; fprintf (fp, \tRBCGate: %lu\n" , gatedcount) ; fprintf (fp, 1 \tRETCZone %lu\n", retccount) ; fprintf (fp, \tdilution %5.9f\n" dilution) ; fprintf (fp, "\tflowrate %5.9f\n" flowrate) ; fprintf (fp, "\ttime: %5.9f\n" time) ,- fprintf (fp, 1 \tvolume: %5.9f\n" volume) ; fprintf (fp, '\ttotalconc: %5.9f\n" totaleonc) ; fprintf (fp, 1 \trbcconc: %5.9f\n" rbcconc) ; fprintf (fp, 1 \trbcfract: %5.9f\n" rbcfract) ; fprintf (fp, ΛtRetcConc: %5.9f\n" RetcConc) ; fprintf (fp, \tRCStat: %lu\n" , (unsigned long)RCStat) ; fclose (fp) ; } ♦endif } 658 659 void mrRETCAlgorithm: :SendNumResults (dsNumericalResultSetSc numresult) { // Send the numerical results to storage: numresult [dsRETCConc] .Value(RetcConc) ; numresult [dsRETCConc] .Stat (RCStat) ; numresult [dsRETCPct] .Value(RetcPct) ; numresult [dsRETCPct] .Stat (RPStat) ; numresult[dsRETCMaturityIndex] .Value (RMI) ; numresult [dsRETCMaturityIndex] .Stat (RMIStat) ; const dsCountDataSc countdata = retcmeas.Count 0 ; numresult[dsRETCListModeSize] .Value(listcount) ; numresult [dsRETCListModeSize] .Stat (dsNumericalResul t: :CalcOK) ; numresult [dsRETCUngatedCount] .Value (countdata.FinalCount 0 ) ,- numresult [dsRETCUngatedCount] .Stat (dsNumericalResul t: :CalcOK) ; numresult [dsRETCGatedCount] .Value (countdata.FinalCount () ) ; numresult [dsRETCGatedCount] .Stat (dsNumericalResult: :CalcOK) ; numresult[dsRETCCountTime] .Value (countdata.FinalTime ( ) ) ; 659 660 numresult [dsRETCCountTime] .Stat (dsNumericalResult: :CalcOK) ; numresult [dsRETCDilution] .Value (countdata.Dilution() ) ,- numresult [dsRETCDilution] .Stat (dsNumericalResult: :CalcOK) ; numresult [dsRETCFlowRate] .Value(countdata.FlowRate ( ) ) ; numresult [dsRETCFlowRate] .Stat (dsNumericalResult: :CalcOK) ; // Calculate and send diagnostic results: if (i calcflag) { numresult [dsRBCMean_IAS] .Value (0) ; numresult [dsRBCMean_IAS] .Stat (dsNumericalResult: :NoCalc) ; numresult[dsRBCCV_IAS] .Value(0) ,- numresult [dsRBCCV_IAS] .Stat (dsNumericalResult: :NoCalc) ; numresult [dsRETCMean_FLl] .Value(0) ; numresult [dsRETCMean_FLl] .Stat (dsNumericalResult: :NoCalc) ; numresult[dsRETCCV_FLl] .Value(0) ; numresult [dsRETCCV_FLl] .Stat (dsNumericalResult: .-NoCalc) ; } else { double mean, sd, cv; IAS_hist.GetStats ( (int)RPLine.XInt 0 , histMax, mean, sd, cv) ; numresult [dsRBCMean_IAS] .Value(mean) ; 660 661 numresult [dsRBCMean_lAS] .Stat (dsNumericalResult: :CalcOK) ; numresult[dsRBCCV_IAS] .Value(cv) ; numresul [dsRBCCV_IAS] .Stat (dsNumericalResult: :CalcOK) ; FLl_hist.GetStats (0, RRcursor, mean, sd, cv); numresult [dsRBCMean_FLl] .Value (mean) ; numresult [dsRBCMean_FLl] .Stat (dsNumericalResult: :CalcOK) ; numresult[dsRBCCV_FLl] .Value (cv) ; numresult [dsRBCCV_FLl] .Stat (dsNumericalResult: :CalcOK) ,- FLl_hist.GetStats (RRcursor, RWcursor, mean, sd, cv) ; numresult [dsRETCMean_FLl] .Value (mean) ; numresult [dsRETCMean_FLl] .Stat (dsNumericalResult: :CalcOK) ; numresult [dsRETCCV_FLl] .Value(cv) ,- numresult [dsRETCCV_FLl] .Stat (dsNumericalResult: :CalcOK) ; } #ifdef DIAGS // Check on data sent to "results": FILE* fp = fopen("data,diag" , "w"),- if (!fp) { fprintf (stderr, "\nWarning: Unable to open output file 'data.diag' .\n" ) ,- } else { fprintf (fp, "Reticulocyte Cone: %8.3f K/ul\n", numresult[dsRETCConc] .Value() ) ; fprintf (fp, "Reticulocyte Pet.: %8.3f %%\n", 661 662 numresult[dsRETCPct] .Value ( ) ) ; fprintf (fp, "RMI: %8.3f %%\n" , numresul [dsRETCMaturityIndex] .Value0 ) ; fprintf (fp, "XnDiagnostic Results: \n" ) ; fprintf (fp, "\tRed Cell IAS mean: %6.2f; cv.: %6.2f\n", numresult [dsRBCMean_IAS] .Value ( ) , numresult [dsRBCCV_IAS] .Value ( ) ) ; fprintf (fp, "\tRed Cell FLl mean: %6.2f; cv.: %6.2f\n", numresult[dsRBCMean_FLl] .Value() , numresult[dsRBCCV_FLl] .Value0 ) ; fprintf (fp, "\tReticulocyte FLl mean: %6.2f; cv. : %6.2f\n\n", numresult [dsRETCMean_FLl] .Value ( ) , numresult[dsRETCCV_FLl] .Value( ) ) ; fclose (fp) ,- } #endif } void mrRETCAlgorithm: .-SendScatResults(dsRETCScatSc scatresult) { unsigned long maxnum = MIN(listcount, scatresult.MaxCells O ) ; unsigned long step = 1; if (maxnum > 0) step = listcount / maxnum; Boolean algstat = TRUE; // Send the scattergram results to storage: retclist->Resolution(dsRETCListMode: :IAS, 0) ; retclist->Resolution(dsRETCListMode: :FL1, 0) ; for (unsigned long i = 0; i < maxnum; i += step) 662 663 { dsRETCScatMeas cellmeas; cellmeas.ias = (dsScatMeas)retclist->CellMeas d, dsRETCListMode: :IAS) ; cellmeas.fll = (dsScatMeas)retclist->CellMeas d, dsRETCListMode: :FL1) ; dsRETCPopulation type = retclist->CellPopulation(i) ,- algstat = algstat ScSc scatresult.AddCell(Sccellmeas, type) ,- } if (! algstat) { dtlnternalLog log(SourceFileName) ; log « Line( LINE ) « "Error in sending reticulocyte scattergram results" « Flush; } // Send the discriminant values to storage: const dsScatMeas maxscat = 255; dsScatDiscriminantSc rrdisc = scatresult.Discriminant(dsRETCScat: :RBCRegion) ,- rrdisc.AddPoint(maxscat, 0) ; rrdisc.AddPoint ( (dsScatMeas)RPLine.XInt 0 , 0) ; mgRealPoint pwpoint = RPLine. Intersect(RWLine) ; rrdisc.AddPoint ( (dsScatMeas)pwpoint.x, (dsScatMeas)pwpoint.y) ; rrdisc.AddPoint (maxscat, (dsScatMeas)RWcursor) ; rrdisc.Close 0 ; } void mrRETCAlgorithm: :SendHistResults (dsRETCHistS. histresult) { 663 664 dtlnternalLog log(SourceFileName) ,- char outstr[100] ,- // Scale the FLl histogram to proper peak height: int npeak = FLl_smhist .Peak( ) ; int peakval = 0; if ((npeak > 0) ScSc (npeak < histMax) ) peakval = FLl_smhist[npeak] ; dsHistCount maxval = histresult.MaxCount () ; double scale = 0.0; if (peakval <= 0) { log « Line ( LINE ) « "mrtιHist256 : : Peak returned a ' peak ' with value = " « peakval « Flush; } else { scale = 5 * (double)maxval / (double)peakval; sprintf (outstr, "SendHistResults: Scaling value is %4.2f", scale); log « Line ( LINE ) « outstr « Flush; } // Pass the values to the reticulocyte-results histogram: log « Line ( LINE ) ' << "SendHistResults: Sending histogram data values" « Flush; if( scale > 0.0 ) { mmHist256 fllhist = FLl_smhist.Scale (scale) ; for (dsHistChannel i = 0; i < histresult.Size() ; i ++) { 664 665 histresult [i] = (dsHistCount)MIN(maxval, fllhistfi] ) ; } } else { for (dsHistChannel i = 0; i < histresult.Size() ; i ++) { histresult[i] = (dsHistCount)MIN(maxval, FLl_smhist [i] ) ; } } // Send the histogram discriminant values: log « Line( LINE ) << "SendHistResults-. Sending histogram discriminant values" << Flush; histresult.Channel (dsRETCHist: :LowerThresh) = (dsHistChannel)RRcursor; histresult.Channel (dsRETCHist: :UpperThresh) = (dsHistChannel)HFRcursor; } /** * * Copyright 1993,95 by Abbott Laboratories * Source Code Control System keywords * ♦ NAME: SSource: /usr3/FileServer/usr/eds/rtc/RCS/mrRETCAlgorithm.h,v $ ♦ $Locker: $ 665 666 $State: R4 $ $Revision: 2.3 $ $Author: eds $ $Date: 95/03/24 16:09:18 $ Log: .. See below LANGUAGE: GNU g++ ♦ DESCRIPTION: * This file contains the class definition for all the algorithms * used to calculate reticulocyte test results. * * ....$Log: mrRETCAlgorithm.h,v $ * Revision 2.3 95/03/24 16:09:18 eds * Changed the names of RRval and HFRval to RRcursor and HFRcursor respectively in order to better reflect their purposes. * Also: Installed a new data member, RWcursor, in order to refrain from re-calculating it in the member functions. * * Revision 2.2 95/03/21 10:32:51 eds * SCR 689: Process RETC Background. ♦ Installed DoBackground member function. * Installed CalcReticConc member function. * Installed doBackground data member. * Installed retccount data member. * Also, some format changes. ♦ * Revision 2.1 95/01/10 09:34:55 michaelf * SCR 524, Update the Language line * * Revision 1.8 94/10/18 17:21:28 jamesb * SCR 359: 666 667 * Added a function to send raw data summaries to results. * * Revision 1.7 94/10/17 14:27:53 jamesb * SCR 335: * Changed algorithm interface and calibration-factor usage to match changes * in calibration-data interface. * * Revision 1.6 94/08/24 14:32:48 jamesb * Incorporated suggestions from R2 and R3 reviews. * * Revision 1.5 94/07/29 10:36:51 jamesb * Added function "GetSysTime" and private data members for discriminants. * * Revision 1.4 94/07/21 16:27:34 jamesb * SCR 225: * Added dil. and cal. factors to RETCAlgorithm interface. * ♦ Revision 1.3 94/05/12 16:14:40 jamesb * Added several more class members for reticulocyte algorithm work. * * Revision 1.2 94/05/11 23:04:29 Johns ♦ SCR 132: * Convert occurrences of "mc" prefix to "mr". * * Revision 1.1 94/05/11 12:25:14 jamesb * Initial revision #ifndef _mrRETCAlgorithm_ #define _mrRETCAlgorithm_ 667 668 #include "cd4000.h" ♦include "mgAlgoDefs.h" ♦include "mgLine.h" #include "mmHist256.h" ♦include "diSpecimenType.h" #include "dsRETCMeas.h" #include "mrRETCListMode.h" #include "dsCBCResults.h" #include "dsRETCResults.h" #include "dcCalibrationData.h" #include "mgCellAlgorithm.h" class mrRETCAlgorithm : public mgCellAlgorithm { public: mrRETCAlgorithm(const diSpecimenTypeSc spectype, const dsRETCMeas& retc, const dsCBCResultsS. cbcrslt, dsRETCResultsSc retcrslt, const dcCalibrationDataSc cal, int dotiming = 0, int priority = 0); // Constructor for the class. // Parameters: // spectype - specimen type for the run // retc - reticulocyte optical transducer measurement data // cbcrslt - entire set of CBC results, including numerical, alert, // scattergram, and histogram data (used for concentration // calculations, based on impedance RBC measurements) 668 669 // retcrslt - entire set of reticulocyte results, including numerical, // alert, scattergram, and histogram data // dilptr - pointer to dilution factors // calptr - pointer to calibration factors // (Note: Since the count used for calculating reticulocyte // concentration comes from the impedance RBC measurements (from // CBC results), these factors are not used.) // dotiming - sets "timeflag" to TRUE or FALSE, which determines whether // timing values will be recorded (default is FALSE) . // priority - used to set the LynxOS priority for the thread containing // the algorithm operations (default is 0, normal priority) . -mrRETCAlgorith (void) ; // Destructor for the class -- default action only. Boolean CalcResults (void) ; // Calculates the entire set of reticulocyte test results from the // transducer measurements. The numerical, alert, and graphical results // include all of the reticulocyte-specific results, which are specified // in separate files. Returns whether the algorithms completed successfully. double GetTiming (int section) ,- // Returns the results (in seconds) of the run time for the specified 669 670 // section of the reticulocyte algorithm. private: const diSpecimenTypeSc specimentype; const dsRETCMeasSc retcmeas; const dsCBCResultsSc cbcresults; dsRETCResultsSc retcresults; const dcCalibrationDataSc caldata; Boolean doBackground; Boolean calcflag; mrRETCListMode^ retclist; // Storage for reticulocyte listmode data unsigned long listcount; // Number of listmode data values unsigned long gatedcount; // Number of listmode values inside RBC gate unsigned long retccount; // Number of listmode values inside RETC Zone double RetcConc; // Concentration of reticulocytes, in K/ul dsNumericalResult: :NRStatus RCStat; // Status of cone calculation double RetcPct; // Reticulocytes as percent of total RBCs dsNumericalResult: :NRStatus RPStat; // Status of % calculation double RMI; // Reticulocyte maturity index (% HFR) dsNumericalResult::NRStatus RMIStat; // Status of RMI calculation mmHist256 IAS_hist; // Histogram of Log-IAS measurements mmHist256 IAS_smhist; // Smoothed histogram of Log- IAS measurements 670 671 mmHist256 FLl_hist; // Histogram of Log-FLl measurements mmHist256 FLl_smhist; // Smoothed histogram of Log- FLl measurements mgLine RPLine; // Discriminant line between red cells and // platelets, in IAS vs. FLl Boolean RP_dflt; // Default value used for red-platelet line mgLine RWLine; // Discriminant line between red cells and // white cells, in IAS vs. FLl int RWcursor; // Separation value between red cells and // white cells, in IAS vs. FLl Boolean RW_dflt; // Default value used for red-white line int RRcursor; // Separation value between red cells and // reticulocytes, in FLl histogram Boolean RR_dflt; // Default value used for red-RETC separation int HFRcursor; // Separation value between low- and high- // fluorescence reticulocytes, in FLl enum retcalgsect { getdata, doanalysis. 671 672 sendresults, maxalgsect }; double timevalues[maxalgsect] ; // Storage for timing results. // Second-level functions, called by "CalcResults": double GetSysTime(void) ; // Returns the current system time, in seconds and milliseconds. void GetRETCData(const dsRETCListModeSc listdata); // Gets the necessary listmode RETC transducer measurements and // translates them into the forms appropriate for the analysis. // Parameters: // listdata - reference to RETC list-mode data for this run void DoRETCAnalysis(void) ; // Does the complete reticulocyte analysis, generating all the // required analytical results and storing them locally. void DoBackground(void) ,- // Does the reticulocyte background calculation. void SendRETCResults(void) ; // Sends to storage all of the required numerical, alert, // histogram, and scattergram results for the completed analysis. 672 673 void SendRawSummary(void) ,- // Sends the raw summary data for all measurements to dsRETCResults. // Third-level functions, called by second-level functions: void SetDefaults(void) ,- // If this sample has less than the minimum number of cells, or is a // background sample, sets everything to default values. void FindPLTs(void) ; // Locates and labels the platelets, using the IAS histogram. void FindWBCs(void) ,- // Locates and labels the WBCs, using the FLl histogram. void FindRETCs(void) ; // Locates and labels the reticulocytes, using the FLl histogram. void GetFinalCounts(Boolean validcounts); // Calculates %R, RMI Sc RETC (concentration) . // Parameters: // validcounts -- whether there is enough listmode data for valid results. void CalcReticConc( double retcpct ); // Calculates the concentration of reticulocytes. // Parameters: // retcpct -- the percentage of reticulocytes. void SendNumResults (dsNumericalResultSetSc numresult); 673

Claims: 674 // Sends all numerical results for storage and display. // Parameters: // numresult - reference to numerical-results object for this run void SendScatResults (dsRETCScatSc scatresult); // Sends all scattergram results for storage and display. // Returns whether this operation completed successfully. // Parameters: // scatresult - reference to scattergram-results object for this run void SendHistResults (dsRETCHistSc histresult); // Sends all histogram results for storage and display. // Returns whether this operation completed successfully. // Parameters: // histresult - reference to histogram-results object for this run mrRETCAlgorithm(const mrRETCAlgorithmSc); // Null copy constructor -- no copies allowed. mrRETCAlgorithmSc operator= (const mrRETCAlgorithmSc); // Null assignment operator -- no assignment allowed. },- #endif // _mrRETCAlgorit ' hm_ 674 675 WHAT IS CLAIMED IS: 1. An automated method for distinguishing and differentiating cells in a whole blood sample, the method comprising: a. aspirating a sample from a sample vessel; b. dispensing at least two aliquots of the sample; c analyzing the aliquots, substantially one cell at a time, and detecting at least multi-angle light scatter and fluorescence signals from at least one of the aliquots; c collecting data generated by the detection of the signals; d. processing the data; and e. reporting a result of the analysis, the result comprising information about red blood cells ("RBC") , white blood cells ("WBC") and fluorescent cells or cell bodies in the sample. 2. The automated method of claim 1 wherein the data collection step comprises collecting data from impedance, multi-angle light scatter and multi-wavelength fluorescence detectors. 3. The automated method of claim 1 wherein a third aliquot is dispensed and analyzed optically for platelets. 4. The automated method of claim 1 wherein one of the at least two aliquots is analyzed for WBC and fluorescent cells or cell bodies. 5. The automated method of claim 4 wherein the fluorescent cells or cell bodies are nucleated red blood cells ("NRBC") . 675 676 6. The automated method of claim 1 wherein an aliquot or one of the at least two aliquots is dispensed and analyzed for multi-angle light scatter fluorescence. 7. The automated method of claim 6 wherein the aliquot supplies data to report information about fluorescent cells or cell bodies in the sample and the cells or cell bodies are reticulocytes. 8. The automated method of claim 1 wherein one of the at least two aliquots is analyzed by means of impedance. 9. The automated method of claim 8 wherein the impedance data is processed at least in part to generate the reported RBC information. 10. The automated method of claim 1 wherein the reported quantitative WBC information is obtained from processing light scatter and fluorescent signal generated data. 11. The automated method of claim 10 wherein the WBC information comprises a five-part differential. 12. The automated method of claim 11 wherein the WBC differential further comprises a percentage NRBC. 13. The automated method of claim 1 wherein the analyzing and data processing of one or more aliquots of the sample is based upon test protocols influenced by selected data generated from one or more aliquots of the sample. 14. The automated method of claim 1 wherein at least one aliquot is analyzed to provide information about the cell viability of cells in the sample. 676 677 15. The method of claim 1 wherein a third aliquot of sample is placed in an instrument system sample receiving vessel and the method further comprises combining the aliquot with fluorescent-labelled monoclonal antibodies for a sufficient time to allow the labelled antibodies to become attached to cell surface antigens on the cells therein, lysing the labelled sample with a lysing reagent without thereafter separating the unlysed cells therefrom, transporting the lysed and monoclonal antibody labelled sample through an optical flow transducer, detecting multi-angle light scatter and fluorescence and counting and differentiating sub¬ populations of lymphocytes in the sample therefrom. 16. An automated instrument system for distinguishing and differentiating cells in a whole blood sample, the system comprising: a. an operation/instruction processing station; b. sample handling, aspiration and dispensing apparatus; c sample processing and analyzing apparatus comprising, sample and reagent handling apparatus and multi- angle light scattering and fluorescent light detecting apparatus; d. data collecting and data processing station; and e. a controller operatively interconnected to the operation/instruction processing station, sample handling, aspiration and dispensing apparatus, sample processing and analyzing apparatus, and the data collecting and processing station, the controller also capable of generating reportable quantitative information about cells in the sample, wherein the information comprises information about red blood cells ("RBC"), white blood cells ("WBC") and fluorescent cells or cell bodies. 677 678 17. The automated instrument system of claim 16 wherein the data collection station comprises detectors for impedance, multi-angle light scatter and multi-wavelength fluorescence. 18. The automated instrument system of claim 16 wherein the fluorescent cells or cell bodies are nucleated red blood cells ("NRBC") . 19. The automated instrument system of claim 16 wherein the fluorescent cells or cell bodies are reticulocytes. 20. The automated instrument system of claim 17 wherein impedance is utilized at least in part to generate the reported RBC information. 21. The automated instrument system of claim 16 wherein the WBC information comprises a five-part differential. 22. The automated instrument system of claim 21 wherein the WBC differential further comprises a percentage NRBC. 23. The automated instrument system of claim 16 wherein the operation/instruction processing station comprises an operator selectable test procedure menu. 24. The automated instrument system of claim 16 wherein the sample processing and analyzing apparatus responds to the controller based at least in part upon data previously generated by the sample processing and analyzing apparatus for cells in the sample. 25. The automated instrument of claim 16 wherein thereportable information further comprises cell viability information about the sample. 678 679 26. The automated instrument system of claim 16 wherein the fluorescent cells or cell bodies comprise fluorescent dye stained DNA or RNA. 27. The automated instrument system of claim 16 wherein the fluorescent cells or cell bodies comprise fluorescently labelled cell surface antigens. 28. The automated instrument system of claim 16 wherein the sample processing and analyzing apparatus further performs an automated lymphocyte subset analysis. 29. The automated instrument system of claim 16 wherein the sample processing and analyzing apparatus further comprises at least one temperature controlled incubation site. 679

Inventors: CHUPP VERNON L, KIM YOUNG RAN, LARUE RODERICK WALTON, LOBBAN PETER E, STUART JOHN PAUL, CHUPP, VERNON, L., KIM, YOUNG, RAN, LARUE, RODERICK, WALTON, LOBBAN, PETER, E., STUART, JOHN, PAUL
Applicants: ABBOTT LAB, ABBOTT LABORATORIES
Application year: 1995
Main classification: G01N15
IPC codes: G01N1, G01N15, G01N21, G01N27, G01N33, G01N35