From db9da5829f0c823b3e6788c774210f429ed375e0 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Mon, 5 Feb 2018 10:06:45 +0100 Subject: [PATCH] simple export of reaction kinetics --- .../java/lcsb/mapviewer/common/XmlParser.java | 2 +- .../reaction/KineticsXmlParser.java | 6 +- .../reaction/ReactionFromXml.java | 40 ++++++++--- .../model/sbml/SbmlBioEntityExporter.java | 3 +- .../model/sbml/SbmlElementParser.java | 1 + .../converter/model/sbml/SbmlExporter.java | 5 +- .../converter/model/sbml/SbmlParser.java | 1 + .../model/sbml/SbmlReactionExporter.java | 68 ++++++++++++++++++- .../model/sbml/SbmlReactionParser.java | 1 + .../model/sbml/SbmlSpeciesParser.java | 5 +- .../model/sbml/SbmlUnitExporter.java | 30 ++++++++ .../model/sbml/GenericSbmlParserTest.java | 8 +-- .../sbml/GenericSbmlToXmlParserTest.java | 2 +- .../model/map/InconsistentModelException.java | 30 ++++---- .../model/map/compartment/Compartment.java | 6 ++ .../map/reaction/ReactionComparator.java | 2 + 16 files changed, 172 insertions(+), 38 deletions(-) create mode 100644 converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlUnitExporter.java diff --git a/commons/src/main/java/lcsb/mapviewer/common/XmlParser.java b/commons/src/main/java/lcsb/mapviewer/common/XmlParser.java index d7ac52a290..66be945a96 100644 --- a/commons/src/main/java/lcsb/mapviewer/common/XmlParser.java +++ b/commons/src/main/java/lcsb/mapviewer/common/XmlParser.java @@ -8,6 +8,7 @@ import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import javax.xml.parsers.DocumentBuilder; @@ -374,5 +375,4 @@ public class XmlParser { } return result; } - } diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/KineticsXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/KineticsXmlParser.java index b1ae5738ed..e77e87b9d8 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/KineticsXmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/KineticsXmlParser.java @@ -63,7 +63,11 @@ public class KineticsXmlParser extends XmlParser { elementsUsedInKinetics.add(element); } result.addArguments(elementsUsedInKinetics); - result.setDefinition(super.nodeToString(mathNode, true)); + + String definition = super.nodeToString(mathNode, true); + definition = definition.replace(" xmlns=\"http://www.sbml.org/sbml/level2/version4\"", ""); + definition = definition.replace("<math>", "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">"); + result.setDefinition(definition); return result; } diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionFromXml.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionFromXml.java index c0a3ef113e..cbf7f44399 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionFromXml.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionFromXml.java @@ -225,20 +225,40 @@ public class ReactionFromXml extends XmlParser { for (Node node : elementNodes) { String speciesId = super.getNodeAttr("species", node); String aliasId = super.getNodeAttr("alias", node); - Element element = model.getElementByElementId(aliasId); - result.put(speciesId, element); - - Compartment compartment = element.getCompartment(); - if (compartment != null) { - // in kinetics we can have reference to compartment (so we need to find SBML - // compartment id) - String compartmentId = elements.getElementByElementId(compartment.getElementId()).getElementId(); - result.put(compartmentId, compartment); - } + addElementMapping(model, result, speciesId, aliasId); + } + + for (Node node : super.getAllNotNecessirellyDirectChild("celldesigner:reactantLink", annotationNode)) { + String speciesId = super.getNodeAttr("reactant", node); + String aliasId = super.getNodeAttr("alias", node); + addElementMapping(model, result, speciesId, aliasId); + } + + for (Node node : super.getAllNotNecessirellyDirectChild("celldesigner:productLink", annotationNode)) { + String speciesId = super.getNodeAttr("product", node); + String aliasId = super.getNodeAttr("alias", node); + addElementMapping(model, result, speciesId, aliasId); } + return result; } + private void addElementMapping(Model model, Map<String, Element> result, String speciesId, String aliasId) { + Element element = model.getElementByElementId(aliasId); + result.put(speciesId, element); + addCompartmentMapping(result, element); + } + + private void addCompartmentMapping(Map<String, Element> result, Element element) { + Compartment compartment = element.getCompartment(); + if (compartment != null) { + // in kinetics we can have reference to compartment (so we need to find SBML + // compartment id) + String compartmentId = elements.getElementByElementId(compartment.getElementId()).getElementId(); + result.put(compartmentId, compartment); + } + } + /** * Parses reaction annotation node and update reaction. * diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java index 97f1c528a8..b864632fea 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java @@ -11,11 +11,12 @@ import org.sbml.jsbml.Model; import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph; import org.sbml.jsbml.ext.layout.Layout; +import lcsb.mapviewer.common.XmlParser; import lcsb.mapviewer.common.exception.InvalidStateException; import lcsb.mapviewer.model.map.BioEntity; import lcsb.mapviewer.model.map.InconsistentModelException; -public abstract class SbmlBioEntityExporter<T extends BioEntity, S extends org.sbml.jsbml.AbstractNamedSBase> { +public abstract class SbmlBioEntityExporter<T extends BioEntity, S extends org.sbml.jsbml.AbstractNamedSBase> extends XmlParser { Logger logger = Logger.getLogger(SbmlBioEntityExporter.class); Layout layout; diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java index 5987e77f0c..7cd9676e7a 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java @@ -15,6 +15,7 @@ import org.sbml.jsbml.ext.layout.Layout; import lcsb.mapviewer.common.Pair; import lcsb.mapviewer.converter.InvalidInputDataExecption; +import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.species.Element; public abstract class SbmlElementParser<T extends org.sbml.jsbml.Symbol> extends SbmlBioEntityParser { diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java index cc105d8a04..1b159bd344 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java @@ -25,10 +25,13 @@ public class SbmlExporter { SbmlCompartmentExporter compartmentExporter = new SbmlCompartmentExporter(layout, model); SbmlBioEntityExporter<Species, org.sbml.jsbml.Species> speciesExporter = new SbmlSpeciesExporter(layout, model, compartmentExporter); - SbmlReactionExporter reactionExporter = new SbmlReactionExporter(layout, model, speciesExporter); + SbmlReactionExporter reactionExporter = new SbmlReactionExporter(layout, model, speciesExporter, compartmentExporter); + SbmlUnitExporter unitExporter = new SbmlUnitExporter(model); compartmentExporter.exportElements(result); speciesExporter.exportElements(result); reactionExporter.exportElements(result); + unitExporter.exportUnits(result); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); SBMLWriter.write(doc, stream, "minerva", "1.0"); diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java index 5d17c13bd7..07429d9d30 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java @@ -226,6 +226,7 @@ public class SbmlParser implements IConverter { throws ConverterException, InconsistentModelException, IOException { File file = new File(filePath); String exportedString = toXml(model); + logger.debug(exportedString); FileWriter fileWriter = new FileWriter(file); fileWriter.write(exportedString); fileWriter.flush(); diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java index a563670114..02ec6cbdf8 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java @@ -7,6 +7,9 @@ import java.util.List; import java.util.Map; import org.apache.log4j.Logger; +import org.sbml.jsbml.ASTNode; +import org.sbml.jsbml.KineticLaw; +import org.sbml.jsbml.LocalParameter; import org.sbml.jsbml.SimpleSpeciesReference; import org.sbml.jsbml.Species; import org.sbml.jsbml.SpeciesReference; @@ -18,26 +21,35 @@ import org.sbml.jsbml.ext.layout.Point; import org.sbml.jsbml.ext.layout.ReactionGlyph; import org.sbml.jsbml.ext.layout.SpeciesReferenceGlyph; import org.sbml.jsbml.ext.layout.SpeciesReferenceRole; +import org.sbml.jsbml.text.parser.ParseException; +import org.w3c.dom.Node; import lcsb.mapviewer.common.Configuration; +import lcsb.mapviewer.common.exception.InvalidXmlSchemaException; import lcsb.mapviewer.model.map.InconsistentModelException; +import lcsb.mapviewer.model.map.compartment.Compartment; +import lcsb.mapviewer.model.map.kinetics.SbmlKinetics; +import lcsb.mapviewer.model.map.kinetics.SbmlParameter; import lcsb.mapviewer.model.map.modifier.Inhibition; -import lcsb.mapviewer.model.map.modifier.Modulation; import lcsb.mapviewer.model.map.modifier.Trigger; import lcsb.mapviewer.model.map.reaction.Modifier; import lcsb.mapviewer.model.map.reaction.Product; import lcsb.mapviewer.model.map.reaction.Reactant; import lcsb.mapviewer.model.map.reaction.Reaction; import lcsb.mapviewer.model.map.reaction.ReactionNode; +import lcsb.mapviewer.model.map.species.Element; public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sbml.jsbml.Reaction> { Logger logger = Logger.getLogger(SbmlReactionExporter.class); private SbmlBioEntityExporter<lcsb.mapviewer.model.map.species.Species, Species> speciesExporter; + private SbmlBioEntityExporter<Compartment, org.sbml.jsbml.Compartment> compartmentExporter; public SbmlReactionExporter(Layout layout, lcsb.mapviewer.model.map.model.Model minervaModel, - SbmlBioEntityExporter<lcsb.mapviewer.model.map.species.Species, Species> speciesExporter) { + SbmlBioEntityExporter<lcsb.mapviewer.model.map.species.Species, Species> speciesExporter, + SbmlBioEntityExporter<lcsb.mapviewer.model.map.compartment.Compartment, org.sbml.jsbml.Compartment> compartmentExporter) { super(layout, minervaModel); this.speciesExporter = speciesExporter; + this.compartmentExporter = compartmentExporter; } Map<ReactionNode, SimpleSpeciesReference> speciesReferenceByReactionNode = new HashMap<>(); @@ -66,9 +78,61 @@ public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sb SimpleSpeciesReference speciesReference = result.createModifier(sbmlSymbol); speciesReferenceByReactionNode.put(modifier, speciesReference); } + if (reaction.getKinetics() != null) { + result.setKineticLaw(createKineticLaw(reaction)); + } return result; } + private KineticLaw createKineticLaw(Reaction reaction) throws InconsistentModelException { + SbmlKinetics kinetics = reaction.getKinetics(); + KineticLaw result = new KineticLaw(); + for (SbmlParameter minervaParameter : kinetics.getParameters()) { + if (minervaModel.getParameterById(minervaParameter.getElementId()) == null) { + LocalParameter parameter = new LocalParameter(); + parameter.setId(minervaParameter.getElementId()); + parameter.setName(minervaParameter.getName()); + parameter.setValue(minervaParameter.getValue()); + parameter.setUnits(minervaParameter.getUnits().getUnitId()); + result.addLocalParameter(parameter); + } + } + + try { + Node node = super.getXmlDocumentFromString(kinetics.getDefinition()); + for (Node ciNode : super.getAllNotNecessirellyDirectChild("ci", node)) { + String id = super.getNodeValue(ciNode).trim(); + Element element = minervaModel.getElementByElementId(id); + if (element != null) { + String sbmlId = null; + Species species= speciesExporter.sbmlElementByElementId.get(id); + if (species !=null) { + sbmlId = species.getId(); + } else { + sbmlId = compartmentExporter.sbmlElementByElementId.get(id).getId(); + } + + logger.debug(id); + logger.debug(element.getElementId()); + logger.debug(speciesExporter); + logger.debug(speciesExporter.sbmlElementByElementId); + logger.debug(speciesExporter.sbmlElementByElementId.get(element.getElementId())); + ciNode.setTextContent(sbmlId); + } + } + String definition = super.nodeToString(node); + definition = definition.replace(" xmlns=\"http://www.sbml.org/sbml/level2/version4\"", ""); + definition = definition.replace("<math>", "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">"); + logger.debug(definition); + result.setMath(ASTNode.parseMathML(definition)); + logger.debug(result.getMathMLString()); + return result; + } catch (InvalidXmlSchemaException e) { + throw new InconsistentModelException(e); + } + + } + private String getReactionId(Reaction reaction) { int separatorIndex = reaction.getElementId().indexOf("__"); if (separatorIndex > 0) { diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java index 0f91b7a80c..cceec32e95 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java @@ -305,6 +305,7 @@ public class SbmlReactionParser extends SbmlBioEntityParser { elementsUsedInKinetics.add(element); } result.addArguments(elementsUsedInKinetics); + result.setDefinition(super.nodeToString(node)); } catch (InvalidXmlSchemaException e) { throw new InvalidInputDataExecption(e); } diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java index 15b76f37b1..1a9826c4e3 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java @@ -40,6 +40,9 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> try { Species result = clazz.getConstructor(String.class).newInstance(species.getId()); assignBioEntityData(species, result); + if (layout == null) { + assignCompartment(result, species.getCompartment()); + } return result; } catch (SecurityException | NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { @@ -67,7 +70,7 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> private void assignCompartment(Element element, String compartmentId) { Compartment compartment = minervaModel.getElementByElementId(compartmentId); - if (compartment == null) { + if (compartment == null && layout != null) { List<Compartment> compartments = new ArrayList<>(); for (CompartmentGlyph glyph : layout.getListOfCompartmentGlyphs()) { if (glyph.getCompartment().equals(compartmentId)) { diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlUnitExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlUnitExporter.java new file mode 100644 index 0000000000..27e2fa310d --- /dev/null +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlUnitExporter.java @@ -0,0 +1,30 @@ +package lcsb.mapviewer.converter.model.sbml; + +import org.apache.log4j.Logger; +import org.sbml.jsbml.UnitDefinition; + +import lcsb.mapviewer.model.map.kinetics.SbmlUnit; +import lcsb.mapviewer.model.map.model.Model; + +public class SbmlUnitExporter { + Logger logger = Logger.getLogger(SbmlUnitExporter.class); + private Model minervaModel; + + public SbmlUnitExporter(lcsb.mapviewer.model.map.model.Model minervaModel) { + this.minervaModel = minervaModel; + } + + public void exportUnits(org.sbml.jsbml.Model result) { + for (SbmlUnit unit : minervaModel.getUnits()) { + result.addUnitDefinition(createUnitDefinition(unit)); + } + } + + private UnitDefinition createUnitDefinition(SbmlUnit unit) { + UnitDefinition result = new UnitDefinition(); + result.setId(unit.getUnitId()); + result.setName(unit.getName()); + return result; + } + +} diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlParserTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlParserTest.java index 9266510347..026f607a24 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlParserTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlParserTest.java @@ -7,7 +7,6 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -60,7 +59,7 @@ public class GenericSbmlParserTest { @Test public void createModelTest() throws Exception { try { - String dir = Files.createTempDirectory("sbgn-temp-images-dir").toFile().getAbsolutePath(); + String dir = Files.createTempDirectory("sbml-temp-images-dir").toFile().getAbsolutePath(); IConverter converter = new SbmlParser(); @@ -80,11 +79,6 @@ public class GenericSbmlParserTest { CellDesignerXmlParser cellDesignerXmlParser = new CellDesignerXmlParser(); String xmlString = cellDesignerXmlParser.toXml(model); - String cellDesignerFilePath = pathWithouExtension.concat("_CD.xml"); - PrintWriter out = new PrintWriter(cellDesignerFilePath); - out.print(xmlString); - out.close(); - InputStream is = new ByteArrayInputStream(xmlString.getBytes("UTF-8")); Model model2 = cellDesignerXmlParser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false)); diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlToXmlParserTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlToXmlParserTest.java index 65211af194..7fbdd583ff 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlToXmlParserTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlToXmlParserTest.java @@ -59,7 +59,7 @@ public class GenericSbmlToXmlParserTest { + filePath.getFileName().toString().substring(0, filePath.getFileName().toString().indexOf(".xml")); String xmlFilePath = pathWithouExtension.concat(".xml"); converter.exportModelToFile(model, xmlFilePath); - + Model model2 = converter.createModel(new ConverterParams().filename(xmlFilePath)); model2.setName(null); diff --git a/model/src/main/java/lcsb/mapviewer/model/map/InconsistentModelException.java b/model/src/main/java/lcsb/mapviewer/model/map/InconsistentModelException.java index 2b339c01e9..a823e1bf11 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/InconsistentModelException.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/InconsistentModelException.java @@ -7,18 +7,22 @@ package lcsb.mapviewer.model.map; * */ public class InconsistentModelException extends Exception { - /** - * - */ - private static final long serialVersionUID = 1L; + /** + * + */ + private static final long serialVersionUID = 1L; - /** - * Default constructor with a message passed in the argument. - * - * @param message - * text message of this exception - */ - public InconsistentModelException(String message) { - super(message); - } + /** + * Default constructor with a message passed in the argument. + * + * @param message + * text message of this exception + */ + public InconsistentModelException(String message) { + super(message); + } + + public InconsistentModelException(Exception e) { + super(e); + } } diff --git a/model/src/main/java/lcsb/mapviewer/model/map/compartment/Compartment.java b/model/src/main/java/lcsb/mapviewer/model/map/compartment/Compartment.java index b06a1b5dd4..bfba815afd 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/compartment/Compartment.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/compartment/Compartment.java @@ -395,4 +395,10 @@ public class Compartment extends Element { return "Compartment"; } + public void removeElements(Set<Element> elements) { + for (Element element : elements) { + removeElement(element); + } + } + } diff --git a/model/src/main/java/lcsb/mapviewer/model/map/reaction/ReactionComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/reaction/ReactionComparator.java index eb812a44ed..856ed07348 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/reaction/ReactionComparator.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/reaction/ReactionComparator.java @@ -177,6 +177,8 @@ public class ReactionComparator extends Comparator<Reaction> { SbmlKineticsComparator kineticsComparator = new SbmlKineticsComparator(); if (kineticsComparator.compare(arg0.getKinetics(), arg1.getKinetics()) != 0) { logger.debug("Kinetics different"); + logger.debug(arg0.getKinetics()); + logger.debug(arg1.getKinetics()); return kineticsComparator.compare(arg0.getKinetics(), arg1.getKinetics()); } return 0; -- GitLab