From e4d190870ea8beac3aa686ca1d3750d2d7eae513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Mon, 2 Dec 2024 21:37:34 +0100 Subject: [PATCH] Read support for SCF trace files. --- .../feature.xml | 4 + .../.project | 17 ++ .../org.eclipse.core.resources.prefs | 2 + .../build.properties | 1 + .../feature.xml | 30 +++ .../.classpath | 7 + .../.gitignore | 1 + .../.project | 28 ++ .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 19 ++ .../OSGI-INF/l10n/bundle_en.properties | 1 + .../build.properties | 6 + .../plugin.xml | 17 ++ .../wsd/converter/supplier/scf/Activator.java | 45 ++++ .../converter/supplier/scf/PathResolver.java | 45 ++++ .../scf/core/ChromatogramImportConverter.java | 68 +++++ .../supplier/scf/core/MagicNumberMatcher.java | 31 +++ .../internal/support/HeaderArrayReader.java | 115 ++++++++ .../internal/support/IHeaderArrayReader.java | 63 +++++ .../support/ISamplePointsByteArrayReader.java | 25 ++ .../ISamplePointsShortArrayReader.java | 25 ++ .../ISequenceInformationArrayReader.java | 26 ++ .../support/SamplePointsByteArrayReader.java | 49 ++++ .../support/SamplePointsShortArrayReader.java | 58 ++++ .../SequenceInformationArrayReader.java | 68 +++++ .../supplier/scf/io/ChromatogramReader.java | 249 ++++++++++++++++++ .../supplier/scf/io/ChromatogramWriter.java | 30 +++ .../scf/model/IVendorChromatogram.java | 21 ++ .../supplier/scf/model/IVendorScan.java | 17 ++ .../scf/model/IVendorScanSignalDAD.java | 17 ++ .../supplier/scf/model/Probability.java | 48 ++++ .../scf/model/VendorChromatogram.java | 33 +++ .../supplier/scf/model/VendorScan.java | 23 ++ .../scf/model/VendorScanSignalDAD.java | 19 ++ .../converter/supplier/scf/model/Version.java | 56 ++++ .../.classpath | 7 + .../.gitignore | 1 + .../.project | 28 ++ .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 11 + .../build.properties | 4 + .../scf/ChromatogramReaderTestCase.java | 50 ++++ .../wsd/converter/supplier/scf/SCF.java | 21 ++ .../supplier/scf/io/ABCZ_F_ITest.java | 53 ++++ .../testdata/abcZ_F.scf | Bin 0 -> 71005 bytes 47 files changed, 1457 insertions(+) create mode 100644 chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/.project create mode 100644 chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/.settings/org.eclipse.core.resources.prefs create mode 100644 chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/build.properties create mode 100644 chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/feature.xml create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.classpath create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.gitignore create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.project create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.settings/org.eclipse.core.resources.prefs create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.settings/org.eclipse.jdt.core.prefs create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/META-INF/MANIFEST.MF create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/OSGI-INF/l10n/bundle_en.properties create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/build.properties create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/plugin.xml create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/Activator.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/PathResolver.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/core/ChromatogramImportConverter.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/core/MagicNumberMatcher.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/HeaderArrayReader.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/IHeaderArrayReader.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISamplePointsByteArrayReader.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISamplePointsShortArrayReader.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISequenceInformationArrayReader.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SamplePointsByteArrayReader.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SamplePointsShortArrayReader.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SequenceInformationArrayReader.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ChromatogramReader.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ChromatogramWriter.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorChromatogram.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorScan.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorScanSignalDAD.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/Probability.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorChromatogram.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorScan.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorScanSignalDAD.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/Version.java create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.classpath create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.gitignore create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.project create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.settings/org.eclipse.core.resources.prefs create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.settings/org.eclipse.jdt.core.prefs create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/META-INF/MANIFEST.MF create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/build.properties create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/ChromatogramReaderTestCase.java create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/SCF.java create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ABCZ_F_ITest.java create mode 100644 chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/testdata/abcZ_F.scf diff --git a/chemclipse/features/org.eclipse.chemclipse.rcp.app.compilation.core.feature/feature.xml b/chemclipse/features/org.eclipse.chemclipse.rcp.app.compilation.core.feature/feature.xml index 1d00d03072..72c699c39b 100644 --- a/chemclipse/features/org.eclipse.chemclipse.rcp.app.compilation.core.feature/feature.xml +++ b/chemclipse/features/org.eclipse.chemclipse.rcp.app.compilation.core.feature/feature.xml @@ -320,4 +320,8 @@ id="org.eclipse.chemclipse.chromatogram.xxd.identifier.supplier.timeranges.feature" version="0.0.0"/> + + diff --git a/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/.project b/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/.project new file mode 100644 index 0000000000..154feeb243 --- /dev/null +++ b/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.chemclipse.wsd.converter.supplier.scf.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/.settings/org.eclipse.core.resources.prefs b/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..801fab74d0 --- /dev/null +++ b/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=utf8 diff --git a/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/build.properties b/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/build.properties new file mode 100644 index 0000000000..64f93a9f0b --- /dev/null +++ b/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/feature.xml b/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/feature.xml new file mode 100644 index 0000000000..6940a114b7 --- /dev/null +++ b/chemclipse/features/org.eclipse.chemclipse.wsd.converter.supplier.scf.feature/feature.xml @@ -0,0 +1,30 @@ + + + + + SCF DNA sequencing data converter + + + + Copyright (c) 2024 Lablicate GmbH. + + + + %license + + + + + diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.classpath b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.classpath new file mode 100644 index 0000000000..81fe078c20 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.gitignore b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.gitignore new file mode 100644 index 0000000000..ae3c172604 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.project b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.project new file mode 100644 index 0000000000..52c5d763f9 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.project @@ -0,0 +1,28 @@ + + + org.eclipse.chemclipse.wsd.converter.supplier.scf + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.settings/org.eclipse.core.resources.prefs b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..801fab74d0 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=utf8 diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.settings/org.eclipse.jdt.core.prefs b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..9154beff79 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=17 diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/META-INF/MANIFEST.MF b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..d657fce57e --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: net.openchrom.wsd.converter.supplier.abif +Bundle-ManifestVersion: 2 +Bundle-Name: SCF Converter +Bundle-SymbolicName: org.eclipse.chemclipse.wsd.converter.supplier.scf;singleton:=true +Bundle-Version: 0.9.0.qualifier +Bundle-Activator: org.eclipse.chemclipse.wsd.converter.supplier.scf.Activator +Bundle-Vendor: ChemClipse +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.chemclipse.converter;bundle-version="0.8.0", + org.eclipse.chemclipse.wsd.converter;bundle-version="0.8.0", + org.eclipse.chemclipse.model;bundle-version="0.8.0", + org.eclipse.chemclipse.wsd.model;bundle-version="0.8.0", + org.eclipse.chemclipse.logging;bundle-version="0.8.0", + org.eclipse.chemclipse.processing;bundle-version="0.8.0", + org.eclipse.chemclipse.support;bundle-version="0.8.0", + org.apache.commons.lang3 +Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-ActivationPolicy: lazy diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/OSGI-INF/l10n/bundle_en.properties b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/OSGI-INF/l10n/bundle_en.properties new file mode 100644 index 0000000000..597fd0bfba --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/OSGI-INF/l10n/bundle_en.properties @@ -0,0 +1 @@ +#Properties file diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/build.properties b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/build.properties new file mode 100644 index 0000000000..948f0bdf02 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + OSGI-INF/,\ + plugin.xml diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/plugin.xml b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/plugin.xml new file mode 100644 index 0000000000..7c6daf7d51 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/plugin.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/Activator.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/Activator.java new file mode 100644 index 0000000000..2bc6d4f1d7 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/Activator.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philip Wenig - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + private static BundleContext context; + + public static BundleContext getContext() { + + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext bundleContext) throws Exception { + + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext bundleContext) throws Exception { + + Activator.context = null; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/PathResolver.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/PathResolver.java new file mode 100644 index 0000000000..c0e09caa01 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/PathResolver.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philip Wenig - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf; + +import java.io.IOException; +import java.net.URL; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.osgi.framework.Bundle; + +public class PathResolver { + + /** + * Returns a absolute path of the specified Folder. For example + * TESTDATA_IMPORT_EMPTY as an absolute Path: + * $PluginPath$/testData/test.scf + * + * @param string + * @return String absolutePath + */ + public static String getAbsolutePath(String string) { + + Bundle bundle = Platform.getBundle(Activator.getContext().getBundle().getSymbolicName()); + IPath path = new Path(string); + URL url = FileLocator.find(bundle, path, null); + try { + return FileLocator.resolve(url).getPath(); + } catch(IOException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/core/ChromatogramImportConverter.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/core/ChromatogramImportConverter.java new file mode 100644 index 0000000000..3231bb792c --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/core/ChromatogramImportConverter.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.core; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.chemclipse.converter.chromatogram.AbstractChromatogramImportConverter; +import org.eclipse.chemclipse.converter.l10n.ConverterMessages; +import org.eclipse.chemclipse.logging.core.Logger; +import org.eclipse.chemclipse.model.core.IChromatogramOverview; +import org.eclipse.chemclipse.processing.core.IProcessingInfo; +import org.eclipse.chemclipse.wsd.converter.io.IChromatogramWSDReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.io.ChromatogramReader; +import org.eclipse.chemclipse.wsd.model.core.IChromatogramWSD; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.osgi.util.NLS; + +public class ChromatogramImportConverter extends AbstractChromatogramImportConverter { + + private static final Logger logger = Logger.getLogger(ChromatogramImportConverter.class); + private static final String DESCRIPTION = "SCF Import Converter"; + + @Override + public IProcessingInfo convert(File file, IProgressMonitor monitor) { + + IProcessingInfo processingInfo = super.validate(file); + if(!processingInfo.hasErrorMessages()) { + IChromatogramWSDReader reader = new ChromatogramReader(); + monitor.subTask(ConverterMessages.importChromatogram); + try { + IChromatogramWSD chromatogram = reader.read(file, monitor); + processingInfo.setProcessingResult(chromatogram); + } catch(IOException e) { + logger.warn(e); + processingInfo.addErrorMessage(DESCRIPTION, NLS.bind(ConverterMessages.failedToReadFile, file.getAbsolutePath())); + } + } + return processingInfo; + } + + @Override + public IProcessingInfo convertOverview(File file, IProgressMonitor monitor) { + + IProcessingInfo processingInfo = super.validate(file); + if(!processingInfo.hasErrorMessages()) { + IChromatogramWSDReader reader = new ChromatogramReader(); + monitor.subTask(ConverterMessages.importChromatogramOverview); + try { + IChromatogramOverview chromatogramOverview = reader.readOverview(file, monitor); + processingInfo.setProcessingResult(chromatogramOverview); + } catch(IOException e) { + logger.warn(e); + processingInfo.addErrorMessage(DESCRIPTION, NLS.bind(ConverterMessages.failedToReadFile, file.getAbsolutePath())); + } + } + return processingInfo; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/core/MagicNumberMatcher.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/core/MagicNumberMatcher.java new file mode 100644 index 0000000000..22de855bd7 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/core/MagicNumberMatcher.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.core; + +import java.io.File; + +import org.eclipse.chemclipse.converter.core.AbstractMagicNumberMatcher; +import org.eclipse.chemclipse.converter.core.IMagicNumberMatcher; + +public class MagicNumberMatcher extends AbstractMagicNumberMatcher implements IMagicNumberMatcher { + + private static final byte[] MAGIC_CODE = new byte[]{(byte)'.', (byte)'s', (byte)'c', (byte)'f'}; + + @Override + public boolean checkFileFormat(File file) { + + if(!checkFileExtension(file, ".scf")) { + return false; + } + return checkMagicCode(file, MAGIC_CODE); + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/HeaderArrayReader.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/HeaderArrayReader.java new file mode 100644 index 0000000000..9dbdc0056b --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/HeaderArrayReader.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.chemclipse.converter.io.support.AbstractArrayReader; + +public class HeaderArrayReader extends AbstractArrayReader implements IHeaderArrayReader { + + public HeaderArrayReader(File file) throws IOException { + + super(file); + } + + @Override + public String readMagicNumber() { + + return readBytesAsString(4); + } + + @Override + public int readSampleNumber() { + + return read4BIntegerBE(); + } + + @Override + public int readSampleOffset() { + + return read4BIntegerBE(); + } + + @Override + public int readBaseNumber() { + + return read4BIntegerBE(); + } + + @Override + public int readBasesLeftClip() { + + return read4BIntegerBE(); + } + + @Override + public int readBasesRightClip() { + + return read4BIntegerBE(); + } + + @Override + public int readBasesOffset() { + + return read4BIntegerBE(); + } + + @Override + public int readCommentsSize() { + + return read4BIntegerBE(); + } + + @Override + public int readCommentsOffset() { + + return read4BIntegerBE(); + } + + @Override + public String readVersion() { + + return readBytesAsString(4); + } + + @Override + public int readSampleSize() { + + return read4BIntegerBE(); + } + + @Override + public int readCodeSet() { + + return read4BIntegerBE(); + } + + @Override + public int readPrivateSize() { + + return read4BIntegerBE(); + } + + @Override + public int readPrivateOffset() { + + return read4BIntegerBE(); + } + + @Override + public void skipSpare() { + + skipBytes(18); + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/IHeaderArrayReader.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/IHeaderArrayReader.java new file mode 100644 index 0000000000..626be8131a --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/IHeaderArrayReader.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support; + +import org.eclipse.chemclipse.converter.io.support.IArrayReader; + +public interface IHeaderArrayReader extends IArrayReader { + + String readMagicNumber(); + + /** @return Number of elements in Samples matrix */ + int readSampleNumber(); + + /** @return Byte offset from start of file */ + int readSampleOffset(); + + /** @return Number of bases in Bases matrix */ + int readBaseNumber(); + + /** @return No. bases in left clip (vector) */ + @Deprecated + int readBasesLeftClip(); + + /** @return No. bases in right clip (qual) */ + @Deprecated + int readBasesRightClip(); + + /** @return Byte offset from start of file */ + int readBasesOffset(); + + /** @return Number of bytes in Comment section */ + int readCommentsSize(); + + /** @return Byte offset from start of file */ + int readCommentsOffset(); + + /** @return "version.revision", e.g. '3' '.' '0' '0' */ + String readVersion(); + + /** @return Size of samples in bytes */ + int readSampleSize(); + + /** @return code set used (but ignored) */ + int readCodeSet(); + + /** @return No. of bytes of Private data, 0 if none */ + int readPrivateSize(); + + /** @return Byte offset from start of file */ + int readPrivateOffset(); + + /** Unused */ + void skipSpare(); +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISamplePointsByteArrayReader.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISamplePointsByteArrayReader.java new file mode 100644 index 0000000000..74f689b071 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISamplePointsByteArrayReader.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support; + +import org.eclipse.chemclipse.converter.io.support.IArrayReader; + +public interface ISamplePointsByteArrayReader extends IArrayReader { + + byte[] readAdenine(int numberBases); + + byte[] readThymine(int numberBases); + + byte[] readGuanine(int numberBases); + + byte[] readCytosine(int numberBases); +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISamplePointsShortArrayReader.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISamplePointsShortArrayReader.java new file mode 100644 index 0000000000..fa8daebcc0 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISamplePointsShortArrayReader.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support; + +import org.eclipse.chemclipse.converter.io.support.IArrayReader; + +public interface ISamplePointsShortArrayReader extends IArrayReader { + + short[] readAdenine(int numberBases); + + short[] readThymine(int numberBases); + + short[] readGuanine(int numberBases); + + short[] readCytosine(int numberBases); +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISequenceInformationArrayReader.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISequenceInformationArrayReader.java new file mode 100644 index 0000000000..2680a6b9d5 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/ISequenceInformationArrayReader.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support; + +import org.eclipse.chemclipse.converter.io.support.IArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.model.Probability; + +public interface ISequenceInformationArrayReader extends IArrayReader { + + int[] readPeakIndices(int numberBases); + + Probability readProbabilities(int numberBases); + + char[] readBaseCalls(int numberBases); + + byte[] readSpares(int numberBases); +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SamplePointsByteArrayReader.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SamplePointsByteArrayReader.java new file mode 100644 index 0000000000..46571a7d57 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SamplePointsByteArrayReader.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.chemclipse.converter.io.support.AbstractArrayReader; + +public class SamplePointsByteArrayReader extends AbstractArrayReader implements ISamplePointsByteArrayReader { + + public SamplePointsByteArrayReader(File file) throws IOException { + + super(file); + } + + @Override + public byte[] readAdenine(int numberBases) { + + return readBytes(numberBases); + } + + @Override + public byte[] readThymine(int numberBases) { + + return readBytes(numberBases); + } + + @Override + public byte[] readGuanine(int numberBases) { + + return readBytes(numberBases); + } + + @Override + public byte[] readCytosine(int numberBases) { + + return readBytes(numberBases); + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SamplePointsShortArrayReader.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SamplePointsShortArrayReader.java new file mode 100644 index 0000000000..89f7a87a5f --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SamplePointsShortArrayReader.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.chemclipse.converter.io.support.AbstractArrayReader; + +public class SamplePointsShortArrayReader extends AbstractArrayReader implements ISamplePointsShortArrayReader { + + public SamplePointsShortArrayReader(File file) throws IOException { + + super(file); + } + + @Override + public short[] readAdenine(int numberBases) { + + return readShorts(numberBases); + } + + @Override + public short[] readThymine(int numberBases) { + + return readShorts(numberBases); + } + + @Override + public short[] readGuanine(int numberBases) { + + return readShorts(numberBases); + } + + @Override + public short[] readCytosine(int numberBases) { + + return readShorts(numberBases); + } + + private short[] readShorts(int dataPoints) { + + short[] shortArray = new short[dataPoints]; + for(int i = 0; i < dataPoints; i++) { + shortArray[i] = read2BShortBE(); + } + return shortArray; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SequenceInformationArrayReader.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SequenceInformationArrayReader.java new file mode 100644 index 0000000000..4c1c977ab4 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/internal/support/SequenceInformationArrayReader.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.chemclipse.converter.io.support.AbstractArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.model.Probability; + +public class SequenceInformationArrayReader extends AbstractArrayReader implements ISequenceInformationArrayReader { + + public SequenceInformationArrayReader(File file) throws IOException { + + super(file); + } + + @Override + public int[] readPeakIndices(int numberBases) { + + return readIntegers(numberBases); + } + + @Override + public Probability readProbabilities(int numberBases) { + + return new Probability(readBytes(numberBases), readBytes(numberBases), readBytes(numberBases), readBytes(numberBases)); + } + + @Override + public char[] readBaseCalls(int numberBases) { + + return readCharacters(numberBases); + } + + @Override + public byte[] readSpares(int numberBases) { + + return readBytes(numberBases); + } + + private int[] readIntegers(int dataPoints) { + + int[] intArray = new int[dataPoints]; + for(int i = 0; i < dataPoints; i++) { + intArray[i] = read4BIntegerBE(); + } + return intArray; + } + + private char[] readCharacters(int dataPoints) { + + char[] charArray = new char[dataPoints]; + for(int i = 0; i < dataPoints; i++) { + charArray[i] = (char)readByte(); + } + return charArray; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ChromatogramReader.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ChromatogramReader.java new file mode 100644 index 0000000000..ec30712021 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ChromatogramReader.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.io; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.util.Date; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.NotImplementedException; +import org.apache.commons.lang3.time.DateUtils; +import org.eclipse.chemclipse.converter.exceptions.FileIsNotReadableException; +import org.eclipse.chemclipse.converter.io.support.DataArrayReader; +import org.eclipse.chemclipse.converter.io.support.IDataArrayReader; +import org.eclipse.chemclipse.logging.core.Logger; +import org.eclipse.chemclipse.model.core.IChromatogramOverview; +import org.eclipse.chemclipse.wsd.converter.io.AbstractChromatogramWSDReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support.HeaderArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support.IHeaderArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support.ISamplePointsByteArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support.ISamplePointsShortArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support.ISequenceInformationArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support.SamplePointsByteArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support.SamplePointsShortArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.internal.support.SequenceInformationArrayReader; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.model.IVendorChromatogram; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.model.IVendorScan; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.model.VendorChromatogram; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.model.VendorScan; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.model.VendorScanSignalDAD; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.model.Version; +import org.eclipse.chemclipse.wsd.model.core.IChromatogramWSD; +import org.eclipse.core.runtime.IProgressMonitor; + +/* + * Simon Dear, Rodger Staden (1992). + * A standard file format for data from DNA sequencing instruments. + * DNA Sequence, 3(2), 107–110. + * https://doi.org/10.3109/10425179209034003 + */ +public class ChromatogramReader extends AbstractChromatogramWSDReader { + + private static final Logger logger = Logger.getLogger(ChromatogramReader.class); + // + private int numberSamples; + private int offsetSamples; + private int sampleSize; + private int numberBases; + private int offsetBases; + private int offsetComments; + private int sizeComments; + private int offsetPrivate; + private int sizePrivate; + + @Override + public IChromatogramWSD read(File file, IProgressMonitor monitor) throws IOException { + + return readChromatogram(file); + } + + @Override + public IChromatogramOverview readOverview(File file, IProgressMonitor monitor) throws IOException { + + return readChromatogram(file); + } + + private IChromatogramWSD readChromatogram(File file) throws IOException { + + IVendorChromatogram chromatogram = new VendorChromatogram(); + chromatogram.setConverterId("SCF"); // to be exportable + chromatogram.setFile(file); + readHeader(file, chromatogram); + if(chromatogram.getVersion().getMajor() != 3) { + throw new NotImplementedException("Only version 3 is supported."); + } + if(numberSamples > 0) { + readSamples(file, chromatogram); + } + if(numberBases > 0) { + readSequenceInformation(file, chromatogram); + } + if(sizeComments > 0) { + readComments(file, chromatogram); + } + if(sizePrivate > 0) { + readPrivateData(file); + } + return chromatogram; + } + + @SuppressWarnings("deprecation") + private void readHeader(File file, IVendorChromatogram chromatogram) throws IOException { + + IHeaderArrayReader headerArrayReader = new HeaderArrayReader(file); + headerArrayReader.resetPosition(); + String magicNumber = headerArrayReader.readMagicNumber(); + if(!magicNumber.equals(".scf")) { + throw new FileIsNotReadableException("Not an SCF trace file."); + } + numberSamples = headerArrayReader.readSampleNumber(); + offsetSamples = headerArrayReader.readSampleOffset(); + numberBases = headerArrayReader.readBaseNumber(); + headerArrayReader.readBasesLeftClip(); + headerArrayReader.readBasesRightClip(); + offsetBases = headerArrayReader.readBasesOffset(); + sizeComments = headerArrayReader.readCommentsSize(); + offsetComments = headerArrayReader.readCommentsOffset(); + chromatogram.setVersion(new Version(headerArrayReader.readVersion())); + sampleSize = headerArrayReader.readSampleSize(); + headerArrayReader.readCodeSet(); + sizePrivate = headerArrayReader.readPrivateSize(); + offsetPrivate = headerArrayReader.readPrivateOffset(); + headerArrayReader.skipSpare(); + } + + private void readSamples(File file, IVendorChromatogram chromatogram) throws IOException { + + if(sampleSize == 1) { + ISamplePointsByteArrayReader samplesByteArrayReader = new SamplePointsByteArrayReader(file); + samplesByteArrayReader.resetPosition(); + samplesByteArrayReader.seek(offsetSamples); + samplesByteArrayReader.readCytosine(numberSamples); + samplesByteArrayReader.readGuanine(numberSamples); + samplesByteArrayReader.readThymine(numberSamples); + throw new NotImplementedException("Sample points with precision 1 are not yet supported."); + } else if(sampleSize == 2) { + ISamplePointsShortArrayReader samplesShortArrayReader = new SamplePointsShortArrayReader(file); + samplesShortArrayReader.resetPosition(); + samplesShortArrayReader.seek(offsetSamples); + // + addShortSignals(samplesShortArrayReader.readAdenine(numberSamples), chromatogram); + chromatogram.setDataName("Adenine"); + // + IVendorChromatogram referencedChromatogram1 = new VendorChromatogram(); + addShortSignals(samplesShortArrayReader.readCytosine(numberSamples), referencedChromatogram1); + referencedChromatogram1.setDataName("Cytosine"); + chromatogram.addReferencedChromatogram(referencedChromatogram1); + // + IVendorChromatogram referencedChromatogram2 = new VendorChromatogram(); + addShortSignals(samplesShortArrayReader.readGuanine(numberSamples), referencedChromatogram2); + referencedChromatogram2.setDataName("Guanine"); + chromatogram.addReferencedChromatogram(referencedChromatogram2); + // + IVendorChromatogram referencedChromatogram3 = new VendorChromatogram(); + addShortSignals(samplesShortArrayReader.readThymine(numberSamples), referencedChromatogram3); + referencedChromatogram3.setDataName("Thymine"); + chromatogram.addReferencedChromatogram(referencedChromatogram3); + } + } + + private void readSequenceInformation(File file, IVendorChromatogram chromatogram) throws IOException { + + ISequenceInformationArrayReader sequenceInformationArrayReader = new SequenceInformationArrayReader(file); + sequenceInformationArrayReader.resetPosition(); + sequenceInformationArrayReader.seek(offsetBases); + sequenceInformationArrayReader.readPeakIndices(numberBases); + sequenceInformationArrayReader.readProbabilities(numberBases); + chromatogram.setMiscInfo(new String(sequenceInformationArrayReader.readBaseCalls(numberBases))); + sequenceInformationArrayReader.readSpares(numberBases); + } + + private void readComments(File file, IVendorChromatogram chromatogram) throws IOException { + + IDataArrayReader dataArrayReader = new DataArrayReader(file); + dataArrayReader.resetPosition(); + dataArrayReader.seek(offsetComments); + String comments = dataArrayReader.readString(sizeComments); + Matcher fieldMatcher = Pattern.compile("([A-Z0-9]{4})=(.+)").matcher(comments); + while(fieldMatcher.find()) { + if(fieldMatcher.groupCount() == 2) { + String fieldId = fieldMatcher.group(1); + String value = fieldMatcher.group(2); + if(fieldId.equals("DATE")) { + chromatogram.setDate(parseDate(value)); + } + if(fieldId.equals("NAME")) { + chromatogram.setSampleName(value); + } + if(fieldId.equals("OPER")) { + chromatogram.setOperator(value); + } + if(fieldId.equals("MACH")) { + chromatogram.setInstrument(value); + } + } + } + } + + // vendor specific fields + private void readPrivateData(File file) throws IOException { + + IDataArrayReader dataArrayReader = new DataArrayReader(file); + dataArrayReader.resetPosition(); + dataArrayReader.seek(offsetPrivate); + dataArrayReader.readString(sizePrivate); + } + + // sadly not standardized + private Date parseDate(String value) { + + String[] formats = {"MMM dd yyyy HH:mm:ss", "EEE dd MMM HH:mm:ss yyyy"}; + try { + String[] dateParts = value.split(" to "); + if(dateParts.length > 1) { + return DateUtils.parseDate(dateParts[1], Locale.ENGLISH, formats); + } else { + return DateUtils.parseDate(value, Locale.ENGLISH, formats); + } + } catch(ParseException e) { + logger.warn(e); + } + return null; + } + + private void addShortSignals(short[] samples, IVendorChromatogram chromatogram) { + + short sample = 0; + sample = 0; + for(int i = 0; i < numberSamples; i++) { + samples[i] = (short)(samples[i] + sample); + sample = samples[i]; + } + sample = 0; + for(int i = 0; i < numberSamples; i++) { + samples[i] = (short)(samples[i] + sample); + sample = samples[i]; + } + for(short base : samples) { + VendorScanSignalDAD scanSignal = new VendorScanSignalDAD(); + scanSignal.setAbsorbance(base); + IVendorScan scan = new VendorScan(); + scan.addScanSignal(scanSignal); + chromatogram.addScan(scan); + } + chromatogram.recalculateRetentionTimes(); + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ChromatogramWriter.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ChromatogramWriter.java new file mode 100644 index 0000000000..c4a3438fd1 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ChromatogramWriter.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.io; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.lang3.NotImplementedException; +import org.eclipse.chemclipse.converter.exceptions.FileIsNotWriteableException; +import org.eclipse.chemclipse.wsd.converter.io.AbstractChromatogramWSDWriter; +import org.eclipse.chemclipse.wsd.model.core.IChromatogramWSD; +import org.eclipse.core.runtime.IProgressMonitor; + +public class ChromatogramWriter extends AbstractChromatogramWSDWriter { + + @Override + public void writeChromatogram(File file, IChromatogramWSD chromatogram, IProgressMonitor monitor) throws FileIsNotWriteableException, IOException { + + throw new NotImplementedException(); + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorChromatogram.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorChromatogram.java new file mode 100644 index 0000000000..f69b3fe29f --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorChromatogram.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.model; + +import org.eclipse.chemclipse.wsd.model.core.IChromatogramWSD; + +public interface IVendorChromatogram extends IChromatogramWSD { + + Version getVersion(); + + void setVersion(Version version); +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorScan.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorScan.java new file mode 100644 index 0000000000..9806c5ac03 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorScan.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.model; + +import org.eclipse.chemclipse.wsd.model.core.IScanWSD; + +public interface IVendorScan extends IScanWSD { +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorScanSignalDAD.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorScanSignalDAD.java new file mode 100644 index 0000000000..2be7f52013 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/IVendorScanSignalDAD.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.model; + +import org.eclipse.chemclipse.wsd.model.core.IScanSignalWSD; + +public interface IVendorScanSignalDAD extends IScanSignalWSD { +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/Probability.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/Probability.java new file mode 100644 index 0000000000..d20d2fb803 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/Probability.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.model; + +public class Probability { + + private byte[] adenine; + private byte[] thymine; + private byte[] guanine; + private byte[] cytosine; + + public Probability(byte[] adenine, byte[] cytosine, byte[] guanine, byte[] thymine) { + + this.adenine = adenine; + this.cytosine = cytosine; + this.guanine = guanine; + this.thymine = thymine; + } + + public byte[] getAdenine() { + + return adenine; + } + + public byte[] getCytosine() { + + return cytosine; + } + + public byte[] getGuanine() { + + return guanine; + } + + public byte[] getThymine() { + + return thymine; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorChromatogram.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorChromatogram.java new file mode 100644 index 0000000000..2b27463014 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorChromatogram.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.model; + +import org.eclipse.chemclipse.wsd.model.core.AbstractChromatogramWSD; + +public class VendorChromatogram extends AbstractChromatogramWSD implements IVendorChromatogram { + + private static final long serialVersionUID = 2457872678347226000L; + // + private Version version; + + @Override + public Version getVersion() { + + return version; + } + + @Override + public void setVersion(Version version) { + + this.version = version; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorScan.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorScan.java new file mode 100644 index 0000000000..a3767f5a0d --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorScan.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.model; + +import org.eclipse.chemclipse.wsd.model.core.AbstractScanWSD; + +public class VendorScan extends AbstractScanWSD implements IVendorScan { + + /** + * Renew the serialVersionUID any time you have changed some fields or + * methods. + */ + private static final long serialVersionUID = 3575508460954261124L; +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorScanSignalDAD.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorScanSignalDAD.java new file mode 100644 index 0000000000..25a0f16c7f --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/VendorScanSignalDAD.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.model; + +import org.eclipse.chemclipse.wsd.model.core.AbstractScanSignalWSD; + +public class VendorScanSignalDAD extends AbstractScanSignalWSD implements IVendorScanSignalDAD { + + private static final long serialVersionUID = -2457872678347226000L; +} \ No newline at end of file diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/Version.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/Version.java new file mode 100644 index 0000000000..2496f35c4f --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.converter.supplier.scf/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/model/Version.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.model; + +public class Version implements Comparable { + + private int major; + private int revision; + + public Version(String version) { + + if(version == null || version.isEmpty()) { + throw new IllegalArgumentException("Version string cannot be null or empty"); + } + String[] parts = version.split("\\."); + if(parts.length != 2) { + throw new IllegalArgumentException("Version must follow 'version.revision' format"); + } + this.major = Integer.parseInt(parts[0]); + this.revision = Integer.parseInt(parts[1]); + } + + public int getMajor() { + + return major; + } + + public int getRevision() { + + return revision; + } + + @Override + public int compareTo(Version other) { + + if(this.major != other.major) { + return Integer.compare(this.major, other.major); + } + return Integer.compare(this.revision, other.revision); + } + + @Override + public String toString() { + + return major + "." + revision; + } +} diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.classpath b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.classpath new file mode 100644 index 0000000000..81fe078c20 --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.gitignore b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.gitignore new file mode 100644 index 0000000000..ae3c172604 --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.project b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.project new file mode 100644 index 0000000000..9318545d32 --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.project @@ -0,0 +1,28 @@ + + + org.eclipse.chemclipse.wsd.converter.supplier.scf.test + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.settings/org.eclipse.core.resources.prefs b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..801fab74d0 --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=utf8 diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.settings/org.eclipse.jdt.core.prefs b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..9154beff79 --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=17 diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/META-INF/MANIFEST.MF b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..62b83162e5 --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/META-INF/MANIFEST.MF @@ -0,0 +1,11 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test +Bundle-ManifestVersion: 2 +Bundle-Name: SCF Converter Test +Bundle-SymbolicName: org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test +Bundle-Version: 0.9.0.qualifier +Bundle-Vendor: ChemClipse +Fragment-Host: org.eclipse.chemclipse.wsd.converter.supplier.scf;bundle-version="0.9.0" +Bundle-RequiredExecutionEnvironment: JavaSE-17 +Require-Bundle: org.junit;bundle-version="4.12.0", + org.eclipse.chemclipse.rcp.app.test;bundle-version="0.8.0" diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/build.properties b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/ChromatogramReaderTestCase.java b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/ChromatogramReaderTestCase.java new file mode 100644 index 0000000000..57736f1b74 --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/ChromatogramReaderTestCase.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf; + +import java.io.File; + +import org.eclipse.chemclipse.processing.core.IProcessingInfo; +import org.eclipse.chemclipse.wsd.converter.chromatogram.ChromatogramConverterWSD; +import org.eclipse.chemclipse.wsd.model.core.IChromatogramWSD; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.junit.Ignore; + +import junit.framework.TestCase; + +@Ignore("Template to be inherited.") +public class ChromatogramReaderTestCase extends TestCase { + + protected IChromatogramWSD chromatogram; + protected String extensionPointId; + protected String pathImport; + protected File fileImport; + + @Override + protected void setUp() throws Exception { + + super.setUp(); + fileImport = new File(this.pathImport); + IProcessingInfo processingInfo = ChromatogramConverterWSD.getInstance().convert(fileImport, extensionPointId, new NullProgressMonitor()); + chromatogram = processingInfo.getProcessingResult(); + } + + @Override + protected void tearDown() throws Exception { + + pathImport = null; + fileImport = null; + chromatogram = null; + // + super.tearDown(); + } +} diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/SCF.java b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/SCF.java new file mode 100644 index 0000000000..83f4716822 --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/SCF.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf; + +public class SCF extends PathResolver { + + public static final String EXTENSION_POINT_ID = "org.eclipse.chemclipse.wsd.converter.supplier.scf"; + /* + * IMPORT + */ + public static final String TESTFILE_IMPORT_ABCZ_F = "testdata/abcZ_F.scf"; +} diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ABCZ_F_ITest.java b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ABCZ_F_ITest.java new file mode 100644 index 0000000000..f56eda995b --- /dev/null +++ b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/src/org/eclipse/chemclipse/wsd/converter/supplier/scf/io/ABCZ_F_ITest.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2024 Lablicate GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthias Mailänder - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.wsd.converter.supplier.scf.io; + +import java.time.ZoneId; + +import org.eclipse.chemclipse.wsd.converter.supplier.scf.ChromatogramReaderTestCase; +import org.eclipse.chemclipse.wsd.converter.supplier.scf.SCF; +import org.junit.Test; + +public class ABCZ_F_ITest extends ChromatogramReaderTestCase { + + @Override + protected void setUp() throws Exception { + + extensionPointId = SCF.EXTENSION_POINT_ID; + pathImport = SCF.getAbsolutePath(SCF.TESTFILE_IMPORT_ABCZ_F); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + + super.tearDown(); + } + + @Test + public void testChromatogram() { + + assertNotNull(chromatogram); + assertEquals(7831, chromatogram.getNumberOfScans()); + assertEquals(3, chromatogram.getReferencedChromatograms().size()); + assertEquals("NM-1999-13-abcZ", chromatogram.getSampleName()); + assertEquals(2004, chromatogram.getDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().getYear()); + assertEquals("Zoo3730-1519-025", chromatogram.getInstrument()); + assertEquals("A-G-GCACCGTATTTGATCCGTTGCCGAAGGTTTGGGTAAAATTCGCGATTTATTGCGCCGTTACCACCGCGTCGGTCATGAGTTGGAAAACGGTTCGGG" + // + "TGAGGCTTTGTTGAAAGAACTCAACGAATTACAACTTGAAATCGAAGCGAAGGACGGCTGGAAGCTGGATGCGGCAGTCAAGCAGACTTTGGGCGAACTCGGTTT" + // + "GCCGGAAAACGAAAAAATCGGCAACCTTTCCGGCGGTCAGAAAAAGCGTGTCGCCTTGGCGCAGGCTTGGGTGCAGAAGCCCGACGTATTGCTGCTGGACGAACC" + // + "GACCAACCATTTGGATATTGACGCGATTATCTGGTTGGAAAACCTGCTCAAGGCGTTTGAAGGCAGCTTGGTCGTGATTACCCACGACCGCCGTTTTTTGGATAA" + // + "TATCGCTACGCGGATTGTTGAACTTGACCGCGGCATTCTACGTTCCTATCCCGGCTCGTTCTCTAAATACAGTGAGAAAAAAGCGCAAGAGTTGGCAGTCAAAAC" + // + "C-G-AACAAA----------------------------------------------" + // + "T----------------------------------------------------------------------------T", chromatogram.getMiscInfo()); + } +} diff --git a/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/testdata/abcZ_F.scf b/chemclipse/tests/org.eclipse.chemclipse.wsd.converter.supplier.scf.fragment.test/testdata/abcZ_F.scf new file mode 100644 index 0000000000000000000000000000000000000000..f4c8e24cb215e868587e4104f00b089d42217cd8 GIT binary patch literal 71005 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 literal 0 HcmV?d00001