Search in sources :

Example 26 with DataPoint

use of net.sf.mzmine.datamodel.DataPoint in project mzmine2 by mzmine.

the class MassDetectionTask method run.

/**
 * @see Runnable#run()
 */
public void run() {
    // make arrays to contain everything you need
    ArrayList<Integer> pointsInScans = new ArrayList<>();
    ArrayList<Double> allMZ = new ArrayList<>();
    ArrayList<Double> allIntensities = new ArrayList<>();
    // idecies of full mass list where scan starts?
    ArrayList<Integer> startIndex = new ArrayList<>();
    ArrayList<Double> scanAcquisitionTime = new ArrayList<>();
    // XCMS needs this one
    ArrayList<Double> totalIntensity = new ArrayList<>();
    double curTotalIntensity;
    int lastPointCount = 0;
    startIndex.add(0);
    try {
        setStatus(TaskStatus.PROCESSING);
        logger.info("Started mass detector on " + dataFile);
        final Scan[] scans = scanSelection.getMatchingScans(dataFile);
        totalScans = scans.length;
        // Process scans one by one
        for (Scan scan : scans) {
            if (isCanceled())
                return;
            MassDetector detector = massDetector.getModule();
            DataPoint[] mzPeaks = detector.getMassValues(scan, massDetector.getParameterSet());
            SimpleMassList newMassList = new SimpleMassList(name, scan, mzPeaks);
            // Add new mass list to the scan
            scan.addMassList(newMassList);
            if (this.saveToCDF) {
                curTotalIntensity = 0;
                for (int a = 0; a < mzPeaks.length; a++) {
                    DataPoint curMzPeak = mzPeaks[a];
                    allMZ.add(curMzPeak.getMZ());
                    allIntensities.add(curMzPeak.getIntensity());
                    curTotalIntensity += curMzPeak.getIntensity();
                }
                scanAcquisitionTime.add(scan.getRetentionTime());
                pointsInScans.add(0);
                startIndex.add(mzPeaks.length + lastPointCount);
                totalIntensity.add(curTotalIntensity);
                lastPointCount = mzPeaks.length + lastPointCount;
            }
            processedScans++;
        }
        // Update the GUI with all new mass lists
        MZmineProjectImpl project = (MZmineProjectImpl) MZmineCore.getProjectManager().getCurrentProject();
        final RawDataTreeModel treeModel = project.getRawDataTreeModel();
        treeModel.updateGUIWithNewObjects();
        ;
        if (this.saveToCDF) {
            // ************** write mass list *******************************
            final String outFileNamePath = outFilename.getPath();
            logger.info("Saving mass detector results to netCDF file " + outFileNamePath);
            NetcdfFileWriter writer = NetcdfFileWriter.createNew(NetcdfFileWriter.Version.netcdf3, outFileNamePath, null);
            Dimension dim_massValues = writer.addDimension(null, "mass_values", allMZ.size());
            Dimension dim_intensityValues = writer.addDimension(null, "intensity_values", allIntensities.size());
            Dimension dim_scanIndex = writer.addDimension(null, "scan_index", startIndex.size() - 1);
            Dimension dim_scanAcquisitionTime = writer.addDimension(null, "scan_acquisition_time", scanAcquisitionTime.size());
            Dimension dim_totalIntensity = writer.addDimension(null, "total_intensity", totalIntensity.size());
            Dimension dim_pointsInScans = writer.addDimension(null, "point_count", pointsInScans.size());
            // add dimensions to list
            List<Dimension> dims = new ArrayList<>();
            dims.add(dim_massValues);
            dims.add(dim_intensityValues);
            dims.add(dim_scanIndex);
            dims.add(dim_scanAcquisitionTime);
            dims.add(dim_totalIntensity);
            dims.add(dim_pointsInScans);
            // make the variables that contain the actual data I think.
            Variable var_massValues = writer.addVariable(null, "mass_values", DataType.DOUBLE, "mass_values");
            Variable var_intensityValues = writer.addVariable(null, "intensity_values", DataType.DOUBLE, "intensity_values");
            Variable var_scanIndex = writer.addVariable(null, "scan_index", DataType.INT, "scan_index");
            Variable var_scanAcquisitionTime = writer.addVariable(null, "scan_acquisition_time", DataType.DOUBLE, "scan_acquisition_time");
            Variable var_totalIntensity = writer.addVariable(null, "total_intensity", DataType.DOUBLE, "total_intensity");
            Variable var_pointsInScans = writer.addVariable(null, "point_count", DataType.INT, "point_count");
            var_massValues.addAttribute(new Attribute("units", "M/Z"));
            var_intensityValues.addAttribute(new Attribute("units", "Arbitrary Intensity Units"));
            var_scanIndex.addAttribute(new Attribute("units", "index"));
            var_scanAcquisitionTime.addAttribute(new Attribute("units", "seconds"));
            var_totalIntensity.addAttribute(new Attribute("units", "Arbitrary Intensity Units"));
            var_pointsInScans.addAttribute(new Attribute("units", "count"));
            var_massValues.addAttribute(new Attribute("scale_factor", 1.0));
            var_intensityValues.addAttribute(new Attribute("scale_factor", 1.0));
            var_scanIndex.addAttribute(new Attribute("scale_factor", 1.0));
            var_scanAcquisitionTime.addAttribute(new Attribute("scale_factor", 1.0));
            var_totalIntensity.addAttribute(new Attribute("scale_factor", 1.0));
            var_pointsInScans.addAttribute(new Attribute("scale_factor", 1.0));
            // create file
            writer.create();
            ArrayDouble.D1 arr_massValues = new ArrayDouble.D1(dim_massValues.getLength());
            ArrayDouble.D1 arr_intensityValues = new ArrayDouble.D1(dim_intensityValues.getLength());
            ArrayDouble.D1 arr_scanIndex = new ArrayDouble.D1(dim_scanIndex.getLength());
            ArrayDouble.D1 arr_scanAcquisitionTime = new ArrayDouble.D1(dim_scanAcquisitionTime.getLength());
            ArrayDouble.D1 arr_totalIntensity = new ArrayDouble.D1(dim_totalIntensity.getLength());
            ArrayDouble.D1 arr_pointsInScans = new ArrayDouble.D1(dim_pointsInScans.getLength());
            for (int i = 0; i < allMZ.size(); i++) {
                arr_massValues.set(i, allMZ.get(i));
                arr_intensityValues.set(i, allIntensities.get(i));
            }
            int i = 0;
            for (; i < scanAcquisitionTime.size(); i++) {
                arr_scanAcquisitionTime.set(i, scanAcquisitionTime.get(i) * 60);
                arr_pointsInScans.set(i, pointsInScans.get(i));
                arr_scanIndex.set(i, startIndex.get(i));
                arr_totalIntensity.set(i, totalIntensity.get(i));
            }
            // arr_scanIndex.set(i,startIndex.get(i));
            // For tiny test file
            // arr_intensityValues .set(0,200);
            // arr_scanIndex .set(0,0);
            // arr_scanAcquisitionTime .set(0,10);
            // arr_totalIntensity .set(0,200);
            // arr_pointsInScans .set(0,0);
            // arr_intensityValues .set(1,300);
            // arr_scanIndex .set(1,1);
            // arr_scanAcquisitionTime .set(1,20);
            // arr_totalIntensity .set(1,300);
            // arr_pointsInScans .set(1,0);
            writer.write(var_massValues, arr_massValues);
            writer.write(var_intensityValues, arr_intensityValues);
            writer.write(var_scanIndex, arr_scanIndex);
            writer.write(var_scanAcquisitionTime, arr_scanAcquisitionTime);
            writer.write(var_totalIntensity, arr_totalIntensity);
            writer.write(var_pointsInScans, arr_pointsInScans);
            writer.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
        setErrorMessage(e.getMessage());
        setStatus(TaskStatus.ERROR);
    }
    setStatus(TaskStatus.FINISHED);
    logger.info("Finished mass detector on " + dataFile);
}
Also used : Variable(ucar.nc2.Variable) Attribute(ucar.nc2.Attribute) ArrayList(java.util.ArrayList) DataPoint(net.sf.mzmine.datamodel.DataPoint) ArrayDouble(ucar.ma2.ArrayDouble) RawDataTreeModel(net.sf.mzmine.desktop.impl.projecttree.RawDataTreeModel) SimpleMassList(net.sf.mzmine.datamodel.impl.SimpleMassList) Dimension(ucar.nc2.Dimension) ArrayDouble(ucar.ma2.ArrayDouble) DataPoint(net.sf.mzmine.datamodel.DataPoint) NetcdfFileWriter(ucar.nc2.NetcdfFileWriter) Scan(net.sf.mzmine.datamodel.Scan) MZmineProjectImpl(net.sf.mzmine.project.impl.MZmineProjectImpl)

Example 27 with DataPoint

use of net.sf.mzmine.datamodel.DataPoint in project mzmine2 by mzmine.

the class PearsonCorrelation method run.

/**
 * @see Runnable#run()
 */
public void run() {
    setStatus(TaskStatus.PROCESSING);
    logger.info("Started Scan Alignment on " + dataFile);
    scanNumbers = dataFile.getScanNumbers(1);
    totalScans = scanNumbers.length;
    RawDataFileWriter newRDFW = null;
    try {
        newRDFW = MZmineCore.createNewFile(dataFile.getName() + ' ' + suffix);
        // [relative scan][j value]
        DataPoint[][] mzValues = null;
        int i, j, si, sj, ii, k, shift, ks;
        int[] shiftedScans = new int[mzSpan * 2 + 1];
        for (i = 0; i < totalScans; i++) {
            if (isCanceled())
                return;
            Scan scan = dataFile.getScan(scanNumbers[i]);
            si = (int) Math.max(0, i - scanSpan);
            sj = (int) (si + 2 * scanSpan);
            if (sj >= totalScans) {
                si = (int) Math.max(0, si - (sj - totalScans + 1));
                sj = (int) (si + 2 * scanSpan);
            }
            if (scan != null) {
                // Allocate
                if (mzValues == null || mzValues.length < sj - si + 1)
                    mzValues = new DataPoint[sj - si + 1][];
                // Load Data Points
                for (j = si; j <= sj; j++) {
                    Scan xscan = dataFile.getScan(scanNumbers[j]);
                    mzValues[j - si] = xscan.getDataPoints();
                }
                // Estimate Correlations
                ii = i - si;
                final SimpleScan newScan = new SimpleScan(scan);
                DataPoint[] newDP = new DataPoint[mzValues[ii].length];
                int maxShift = 0;
                double maxCorrelation = 0;
                int ndp = mzValues[ii].length;
                // System.out.print("Scan="+i);
                for (shift = -mzSpan; shift <= mzSpan; shift++) {
                    PearsonCorrelation thisShift = new PearsonCorrelation();
                    for (k = 0; k < ndp; k++) {
                        ks = k + shift;
                        if (ks >= 0 && ks < ndp && mzValues[ii][ks].getIntensity() >= minimumHeight) {
                            DataPoint dp = mzValues[ii][k];
                            double mz = dp.getMZ();
                            int f = 0;
                            for (j = 0; j < mzValues.length; j++) {
                                // System.out.println(j);
                                if (j != ii) {
                                    if (mzValues[j].length > k && Math.abs(mzValues[j][k].getMZ() - mz) < 1e-10) {
                                        f = k;
                                    } else {
                                        f = findFirstMass(mz, mzValues[j]);
                                        if (Math.abs(mzValues[j][f].getMZ() - mz) > 1e-10) {
                                            f = -f;
                                        }
                                    }
                                    if (f >= 0) {
                                        if (logScale) {
                                            thisShift.enter(Math.log(mzValues[j][f].getIntensity()), Math.log(mzValues[ii][ks].getIntensity()));
                                        } else {
                                            thisShift.enter(mzValues[j][f].getIntensity(), mzValues[ii][ks].getIntensity());
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // correlation="+Math.round(thisShift.correlation()*1000)/1000.0);
                    if (thisShift.correlation() > maxCorrelation) {
                        maxShift = shift;
                        maxCorrelation = thisShift.correlation();
                    }
                // newDP[k] = new SimpleDataPoint(mz, c > 0 ? a/c : 0);
                }
                // Copy DataPoints with maxShift as the shift
                shift = maxShift;
                // System.out.println("\nScan="+i+", Shift="+maxShift+", Correlation="+maxCorrelation);
                shiftedScans[maxShift + mzSpan]++;
                for (k = 0; k < ndp; k++) {
                    ks = k + shift;
                    if (ks >= 0 && ks < ndp) {
                        newDP[k] = new SimpleDataPoint(mzValues[ii][k].getMZ(), mzValues[ii][ks].getIntensity());
                    } else {
                        newDP[k] = new SimpleDataPoint(mzValues[ii][k].getMZ(), 0);
                    }
                }
                newScan.setDataPoints(newDP);
                newRDFW.addScan(newScan);
            }
            processedScans++;
        }
        if (!isCanceled()) {
            // Finalize writing
            newRDF = newRDFW.finishWriting();
            // Add the newly created file to the project
            project.addFile(newRDF);
            // Remove the original data file if requested
            if (removeOriginal) {
                project.removeFile(dataFile);
            }
            setStatus(TaskStatus.FINISHED);
            String shifts = "";
            for (i = -mzSpan; i <= mzSpan; i++) {
                shifts = shifts + i + ":" + shiftedScans[i + mzSpan] + " | ";
            }
            logger.info("Finished Scan Alignment on " + dataFile + ". Scans per shift = " + shifts);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
Also used : RawDataFileWriter(net.sf.mzmine.datamodel.RawDataFileWriter) IOException(java.io.IOException) DataPoint(net.sf.mzmine.datamodel.DataPoint) SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint) SimpleScan(net.sf.mzmine.datamodel.impl.SimpleScan) SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint) DataPoint(net.sf.mzmine.datamodel.DataPoint) SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint) Scan(net.sf.mzmine.datamodel.Scan) SimpleScan(net.sf.mzmine.datamodel.impl.SimpleScan)

Example 28 with DataPoint

use of net.sf.mzmine.datamodel.DataPoint in project mzmine2 by mzmine.

the class BaselineCorrector method subtractTICBaselines.

/**
 * Perform baseline correction in bins (TIC).
 *
 * @param origDataFile dataFile of concern.
 * @param dataPoints input data points to correct.
 * @param baselines the baselines - one per m/z bin.
 * @param numBins the number of m/z bins.
 * @param scanIndex the current scan index that these data points come from.
 * @return the corrected data points.
 */
private DataPoint[] subtractTICBaselines(final RawDataFile origDataFile, final DataPoint[] dataPoints, final double[][] baselines, final int numBins, final int scanIndex) {
    // Create an ArrayList for new data points.
    final DataPoint[] newDataPoints = new DataPoint[dataPoints.length];
    // Determine MZ range.
    final Range<Double> mzRange = origDataFile.getDataMZRange();
    // Loop through all original data points.
    int i = 0;
    for (final DataPoint dp : dataPoints) {
        // Subtract baseline.
        final double mz = dp.getMZ();
        final int bin = RangeUtils.binNumber(mzRange, numBins, mz);
        final double baselineIntenstity = baselines[bin][scanIndex];
        newDataPoints[i++] = baselineIntenstity <= 0.0 ? new SimpleDataPoint(dp) : new SimpleDataPoint(mz, Math.max(0.0, dp.getIntensity() * (1.0 - baselineIntenstity)));
    }
    // Return the new data points.
    return newDataPoints;
}
Also used : SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint) DataPoint(net.sf.mzmine.datamodel.DataPoint) SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint) DataPoint(net.sf.mzmine.datamodel.DataPoint) SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint)

Example 29 with DataPoint

use of net.sf.mzmine.datamodel.DataPoint in project mzmine2 by mzmine.

the class ScanSmoothingTask method findFirstMass.

static int findFirstMass(double mass, DataPoint[] mzValues) {
    int l = 0;
    int r = mzValues.length - 1;
    int mid = 0;
    while (l < r) {
        mid = (r + l) / 2;
        if (mzValues[mid].getMZ() > mass) {
            r = mid - 1;
        } else if (mzValues[mid].getMZ() < mass) {
            l = mid + 1;
        } else {
            r = mid;
        }
    }
    return l;
}
Also used : DataPoint(net.sf.mzmine.datamodel.DataPoint) SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint)

Example 30 with DataPoint

use of net.sf.mzmine.datamodel.DataPoint in project mzmine2 by mzmine.

the class ScanSmoothingTask method run.

/**
 * @see Runnable#run()
 */
public void run() {
    setStatus(TaskStatus.PROCESSING);
    logger.info("Started Scan Smoothing on " + dataFile);
    scanNumbers = dataFile.getScanNumbers(1);
    totalScans = scanNumbers.length;
    RawDataFileWriter newRDFW = null;
    int timepassed = 0;
    int mzpassed = 0;
    try {
        newRDFW = MZmineCore.createNewFile(dataFile.getName() + ' ' + suffix);
        // [relative scan][j value]
        DataPoint[][] mzValues = null;
        int i, j, si, sj, ii, k, ssi, ssj;
        for (i = 0; i < totalScans; i++) {
            if (isCanceled())
                return;
            // Smoothing in TIME space
            Scan scan = dataFile.getScan(scanNumbers[i]);
            if (scan != null) {
                double rt = scan.getRetentionTime();
                final SimpleScan newScan = new SimpleScan(scan);
                DataPoint[] newDP = null;
                sj = si = i;
                ssi = ssj = i;
                if (timeSpan > 0 || scanSpan > 0) {
                    double timeMZtol = Math.max(mzTol, 1e-5);
                    for (si = i; si > 1; si--) {
                        Scan scanS = dataFile.getScan(scanNumbers[si - 1]);
                        if (scanS == null || scanS.getRetentionTime() < rt - timeSpan / 2) {
                            break;
                        }
                    }
                    for (sj = i; sj < totalScans - 1; sj++) {
                        Scan scanS = dataFile.getScan(scanNumbers[sj + 1]);
                        if (scanS == null || scanS.getRetentionTime() >= rt + timeSpan / 2) {
                            break;
                        }
                    }
                    ssi = i - (scanSpan - 1) / 2;
                    ssj = i + (scanSpan - 1) / 2;
                    if (ssi < 0) {
                        ssj += -ssi;
                        ssi = 0;
                    }
                    if (ssj >= totalScans) {
                        ssi -= (ssj - totalScans + 1);
                        ssj = totalScans - 1;
                    }
                    if (sj - si + 1 < scanSpan) {
                        si = ssi;
                        sj = ssj;
                    // si = Math.min(si, ssi);
                    // sj = Math.max(sj, ssj);
                    }
                    if (sj > si) {
                        timepassed++;
                        // Allocate
                        if (mzValues == null || mzValues.length < sj - si + 1)
                            mzValues = new DataPoint[sj - si + 1][];
                        // Load Data Points
                        for (j = si; j <= sj; j++) {
                            Scan xscan = dataFile.getScan(scanNumbers[j]);
                            mzValues[j - si] = xscan.getDataPoints();
                        }
                        // Estimate Averages
                        ii = i - si;
                        newDP = new DataPoint[mzValues[ii].length];
                        for (k = 0; k < mzValues[ii].length; k++) {
                            DataPoint dp = mzValues[ii][k];
                            double mz = dp.getMZ();
                            double intensidad = 0;
                            if (dp.getIntensity() > 0) {
                                // only process
                                // those > 0
                                double a = 0;
                                short c = 0;
                                int f = 0;
                                for (j = 0; j < mzValues.length; j++) {
                                    // System.out.println(j);
                                    if (mzValues[j].length > k && Math.abs(mzValues[j][k].getMZ() - mz) < timeMZtol) {
                                        f = k;
                                    } else {
                                        f = findFirstMass(mz, mzValues[j]);
                                        if (Math.abs(mzValues[j][f].getMZ() - mz) > timeMZtol) {
                                            f = -f;
                                        }
                                    }
                                    if (f >= 0 && mzValues[j][f].getIntensity() >= minimumHeight) {
                                        a += mzValues[j][f].getIntensity();
                                        c++;
                                    } else {
                                        c = (short) (c + 0);
                                    }
                                }
                                intensidad = c > 0 ? a / c : 0;
                            }
                            newDP[k] = new SimpleDataPoint(mz, intensidad);
                        }
                    }
                } else if (scan != null) {
                    newDP = scan.getDataPoints();
                }
                if ((mzTol > 0 || mzPoints > 0)) {
                    mzpassed++;
                    DataPoint[] updatedDP = new DataPoint[newDP.length];
                    for (k = 0; k < newDP.length; k++) {
                        double mz = newDP[k].getMZ();
                        double intensidad = 0;
                        if (newDP[k].getIntensity() > 0) {
                            for (si = k; si > 0 && (newDP[si].getMZ() + mzTol >= mz || k - si <= mzPoints); si--) ;
                            for (sj = k; sj < newDP.length - 1 && (newDP[sj].getMZ() - mzTol <= mz || sj - k <= mzPoints); sj++) ;
                            double sum = 0;
                            for (j = si; j <= sj; j++) {
                                sum += newDP[j].getIntensity();
                            }
                            intensidad = sum / (sj - si + 1);
                        }
                        updatedDP[k] = new SimpleDataPoint(mz, intensidad);
                    }
                    newDP = updatedDP;
                }
                // Register new smoothing data
                if (scan != null && newDP != null) {
                    newScan.setDataPoints(newDP);
                    newRDFW.addScan(newScan);
                }
            }
            processedScans++;
        }
        if (!isCanceled()) {
            // Finalize writing
            newRDF = newRDFW.finishWriting();
            // Add the newly created file to the project
            project.addFile(newRDF);
            // Remove the original data file if requested
            if (removeOriginal) {
                project.removeFile(dataFile);
            }
            setStatus(TaskStatus.FINISHED);
            if (mzpassed + timepassed < totalScans / 2) {
                logger.warning("It seems that parameters were not properly set. Scans processed : time=" + timepassed + ", mz=" + mzpassed);
            }
            logger.info("Finished Scan Smoothing on " + dataFile);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
Also used : SimpleScan(net.sf.mzmine.datamodel.impl.SimpleScan) SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint) DataPoint(net.sf.mzmine.datamodel.DataPoint) SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint) Scan(net.sf.mzmine.datamodel.Scan) SimpleScan(net.sf.mzmine.datamodel.impl.SimpleScan) RawDataFileWriter(net.sf.mzmine.datamodel.RawDataFileWriter) IOException(java.io.IOException) DataPoint(net.sf.mzmine.datamodel.DataPoint) SimpleDataPoint(net.sf.mzmine.datamodel.impl.SimpleDataPoint)

Aggregations

DataPoint (net.sf.mzmine.datamodel.DataPoint)214 SimpleDataPoint (net.sf.mzmine.datamodel.impl.SimpleDataPoint)98 Scan (net.sf.mzmine.datamodel.Scan)64 ArrayList (java.util.ArrayList)50 RawDataFile (net.sf.mzmine.datamodel.RawDataFile)44 Feature (net.sf.mzmine.datamodel.Feature)27 MassList (net.sf.mzmine.datamodel.MassList)24 PeakListRow (net.sf.mzmine.datamodel.PeakListRow)22 IOException (java.io.IOException)20 SimpleScan (net.sf.mzmine.datamodel.impl.SimpleScan)18 IsotopePattern (net.sf.mzmine.datamodel.IsotopePattern)17 SimpleIsotopePattern (net.sf.mzmine.datamodel.impl.SimpleIsotopePattern)16 SimpleFeature (net.sf.mzmine.datamodel.impl.SimpleFeature)15 SimplePeakListRow (net.sf.mzmine.datamodel.impl.SimplePeakListRow)15 SimplePeakList (net.sf.mzmine.datamodel.impl.SimplePeakList)12 DataPointSorter (net.sf.mzmine.util.DataPointSorter)12 HashMap (java.util.HashMap)10 Vector (java.util.Vector)10 Range (com.google.common.collect.Range)8 TreeMap (java.util.TreeMap)8