From 8acdb85f57ec8b0733e4f22542a401617dc9ff1f Mon Sep 17 00:00:00 2001 From: jcschaff Date: Thu, 14 Nov 2024 17:43:09 -0500 Subject: [PATCH 1/4] support Infinity and NaN in SBML values and MathML --- .../org/vcell/sbml/vcell/SBMLImporter.java | 25 ++++++++++++++++--- .../org/vcell/sbml/SBMLTestSuiteTest.java | 2 -- .../vcell/parser/ExpressionMathMLParser.java | 14 ++++++++++- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/vcell-core/src/main/java/org/vcell/sbml/vcell/SBMLImporter.java b/vcell-core/src/main/java/org/vcell/sbml/vcell/SBMLImporter.java index bcb17b58d3..3e0cb7e070 100644 --- a/vcell-core/src/main/java/org/vcell/sbml/vcell/SBMLImporter.java +++ b/vcell-core/src/main/java/org/vcell/sbml/vcell/SBMLImporter.java @@ -2975,18 +2975,35 @@ private static void addOutputFunctions(org.sbml.jsbml.Model sbmlModel, BioModel private static void applySavedExpressions(org.sbml.jsbml.Model sbmlModel, SBMLSymbolMapping sbmlSymbolMapping, VCLogger vcLogger) throws Exception{ for(SBase sbmlValueTargetSbase : sbmlSymbolMapping.getSbmlValueTargets()){ Double sbmlValue = sbmlSymbolMapping.getSbmlValue(sbmlValueTargetSbase); - if(sbmlValue != null && !sbmlValue.isInfinite() && !sbmlValue.isNaN()){ + final Expression sbmlValueExp; + if (sbmlValue != null) { + if (sbmlValue.isInfinite() && sbmlValue > 0) { + sbmlValueExp = new Expression(Double.MAX_VALUE); + logger.debug("setting infinite value for SBML id " + sbmlValueTargetSbase.getId() + " to " + Double.MAX_VALUE); + } else if (sbmlValue.isInfinite() && sbmlValue < 0){ + sbmlValueExp = new Expression(-Double.MAX_VALUE); + logger.debug("setting infinite value for SBML id " + sbmlValueTargetSbase.getId() + " to " + -Double.MAX_VALUE); + } else if (sbmlValue.isNaN()){ + sbmlValueExp = new Expression("0/0"); + logger.debug("setting NaN value for SBML id " + sbmlValueTargetSbase.getId() + " to 0/0"); + } else { + sbmlValueExp = new Expression(sbmlValue); + } + } else { + sbmlValueExp = null; + } + if(sbmlValueExp != null){ EditableSymbolTableEntry targetSte = sbmlSymbolMapping.getInitialSte(sbmlValueTargetSbase); try { if(targetSte != null){ if(targetSte.isExpressionEditable()){ - targetSte.setExpression(new Expression(sbmlValue)); + targetSte.setExpression(sbmlValueExp); } } else { targetSte = sbmlSymbolMapping.getRuntimeSte(sbmlValueTargetSbase); if(targetSte != null){ if(targetSte.isExpressionEditable()){ - targetSte.setExpression(new Expression(sbmlValue)); + targetSte.setExpression(sbmlValueExp); } } else { logger.error("couldn't find vcell object mapped to sbml object: " + sbmlValueTargetSbase); @@ -2998,7 +3015,7 @@ private static void applySavedExpressions(org.sbml.jsbml.Model sbmlModel, SBMLSy vcLogger.sendMessage(VCLogger.Priority.HighPriority, VCLogger.ErrorType.OverallWarning, msg); } } else { - String msg = "missing or unexpected value attribute '" + sbmlValue + "' for SBML object id " + sbmlValueTargetSbase.getId(); + String msg = "missing value attribute for SBML object id " + sbmlValueTargetSbase.getId(); logger.error(msg); vcLogger.sendMessage(VCLogger.Priority.HighPriority, VCLogger.ErrorType.OverallWarning, msg); } diff --git a/vcell-core/src/test/java/org/vcell/sbml/SBMLTestSuiteTest.java b/vcell-core/src/test/java/org/vcell/sbml/SBMLTestSuiteTest.java index 439fa4a32e..c7ecfc0974 100644 --- a/vcell-core/src/test/java/org/vcell/sbml/SBMLTestSuiteTest.java +++ b/vcell-core/src/test/java/org/vcell/sbml/SBMLTestSuiteTest.java @@ -374,8 +374,6 @@ public static Collection testCases() { faults.put(943, FAULT.DELAY); faults.put(945, FAULT.STRUCTURE_SIZE_IN_ASSIGNMENT_RULE); faults.put(947, FAULT.STRUCTURE_SIZE_IN_ASSIGNMENT_RULE); - faults.put(950, FAULT.VALUE_NAN_INF_OR_MISSING); - faults.put(951, FAULT.VALUE_NAN_INF_OR_MISSING); faults.put(957, FAULT.XOR_MISSING); faults.put(958, FAULT.XOR_MISSING); faults.put(959, FAULT.INCONSISTENT_UNIT_SYSTEM); diff --git a/vcell-math/src/main/java/cbit/vcell/parser/ExpressionMathMLParser.java b/vcell-math/src/main/java/cbit/vcell/parser/ExpressionMathMLParser.java index 8fc9d7c1b9..3fdd14b178 100644 --- a/vcell-math/src/main/java/cbit/vcell/parser/ExpressionMathMLParser.java +++ b/vcell-math/src/main/java/cbit/vcell/parser/ExpressionMathMLParser.java @@ -497,7 +497,19 @@ private SimpleNode getRootNode(Element nodeMathML, String timeSymbol) throws Exp } else { throw new ExpressionException("csymbol node type "+nodeMathML.getAttributeValue(MathMLTags.DEFINITIONURL)+" not supported yet"); } - } else{ + } else if (nodeMathML.getName().equals(MathMLTags.NOT_A_NUMBER)){ + ASTFloatNode zeroNode = new ASTFloatNode(0.0); + ASTFloatNode zeroNode2 = new ASTFloatNode(0.0); + ASTInvertTermNode invNode = new ASTInvertTermNode(); + invNode.jjtAddChild(zeroNode2); + ASTMultNode multNode = new ASTMultNode(); + multNode.jjtAddChild(zeroNode); + multNode.jjtAddChild(invNode); + return multNode; + } else if (nodeMathML.getName().equals(MathMLTags.INFINITY)) { + ASTFloatNode infNode = new ASTFloatNode(Double.MAX_VALUE); + return infNode; + }else{ throw new ExpressionException("node type '"+nodeMathML.getName()+"' not supported yet"); } } From 355c69ef44b0d480a6b80083801ac06ffd416cbf Mon Sep 17 00:00:00 2001 From: jcschaff Date: Fri, 15 Nov 2024 01:35:17 -0500 Subject: [PATCH 2/4] add unit test for infinity and NaN from MathML --- .../java/cbit/vcell/parser/MathMLTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/vcell-math/src/test/java/cbit/vcell/parser/MathMLTest.java b/vcell-math/src/test/java/cbit/vcell/parser/MathMLTest.java index 1c28811272..4aa7cd985b 100644 --- a/vcell-math/src/test/java/cbit/vcell/parser/MathMLTest.java +++ b/vcell-math/src/test/java/cbit/vcell/parser/MathMLTest.java @@ -80,6 +80,26 @@ public void testMathMLParsing_XOR() throws IOException, ExpressionException { assertTrue(equiv, msg); } + @Test + public void testNaN_MathmlParsing() throws ExpressionException { + String nanMathML = ""; + Expression exp = new ExpressionMathMLParser(null).fromMathML(nanMathML, "t"); + Expression expectedExp = new Expression("0/0"); + boolean equiv = ExpressionUtils.functionallyEquivalent(exp, expectedExp, true); + String msg = "not equivalent: origExp='"+exp.infix()+"', expMathML='"+expectedExp.infix()+"'"; + assertTrue(equiv, msg); + } + + @Test + public void testInfinity_MathmlParsing() throws ExpressionException { + String nanMathML = ""; + Expression exp = new ExpressionMathMLParser(null).fromMathML(nanMathML, "t"); + Expression expectedExp = new Expression(Double.MAX_VALUE); + boolean equiv = ExpressionUtils.functionallyEquivalent(exp, expectedExp, true); + String msg = "not equivalent: origExp='"+exp.infix()+"', expMathML='"+expectedExp.infix()+"'"; + assertTrue(equiv, msg); + } + @ParameterizedTest @MethodSource("testCases") From a539a5d036dd883abe3cf15904d616e7b9f93fa2 Mon Sep 17 00:00:00 2001 From: jcschaff Date: Fri, 15 Nov 2024 01:47:50 -0500 Subject: [PATCH 3/4] new failure mode for SBML test suite model 696 after supporting NaN --- .../src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcell-core/src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java b/vcell-core/src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java index 7bbc1702ad..6cad88769a 100644 --- a/vcell-core/src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java +++ b/vcell-core/src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java @@ -157,7 +157,7 @@ public static Map knownFaults() { faults.put(627, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'Metabolite_123' to model: 'UNRESOLVED.initConc' is either not found in your model or is not allowed to be used in the current context. Check that y faults.put(628, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'Metabolite_8' to model: 'UNRESOLVED.initConc' is either not found in your model or is not allowed to be used in the current context. Check that you faults.put(632, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'k4b' to model: 'UNRESOLVED.initConc' is either not found in your model or is not allowed to be used in the current context. Check that you have pro - faults.put(696, SBMLTestSuiteTest.FAULT.MATHML_PARSING); // cause: Error adding Lambda function UnsupportedConstruct: error parsing expression ' ': node type 'notanumber' not supported yet + faults.put(696, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'Metabolite_16' to model: 'UNRESOLVED.initConc' is either not found in your model or is not allowed to be used in the current context. Check that yo faults.put(705, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'Metabolite_21' to model: 'UNRESOLVED.initConc' is either not found in your model or is not allowed to be used in the current context. Check that yo faults.put(706, SBMLTestSuiteTest.FAULT.UNCATEGORIZED); // cause: found more than one SBase match for sid=v, matched [org.vcell.sbml.vcell.SBMLSymbolMapping$SBaseWrapper@67cc48df, org.vcell.sbml.vcell.SBMLSymbolMapping$SBaseWrapper@483ac21f] faults.put(710, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'Metabolite_0_0' to model: 'UNRESOLVED.initConc' is either not found in your model or is not allowed to be used in the current context. Check that y From 5c6cbd44e5ecebe947f52aceb0bf82e19a22b0ed Mon Sep 17 00:00:00 2001 From: jcschaff Date: Fri, 15 Nov 2024 02:01:29 -0500 Subject: [PATCH 4/4] SBML Test suite model 952 works now that NaN supported --- vcell-core/src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/vcell-core/src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java b/vcell-core/src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java index 6cad88769a..7285e492b2 100644 --- a/vcell-core/src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java +++ b/vcell-core/src/test/java/org/vcell/sbml/BMDB_SBMLImportTest.java @@ -179,7 +179,6 @@ public static Map knownFaults() { faults.put(872, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'beta' to model: 'UNRESOLVED.initConc' is either not found in your model or is not allowed to be used in the current context. Check that you have pr faults.put(908, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'Metabolite_2' to model: 'UNRESOLVED.initConc' is either not found in your model or is not allowed to be used in the current context. Check that you faults.put(925, SBMLTestSuiteTest.FAULT.UNCATEGORIZED); // cause: OverallWarning: missing or unexpected value attribute '-Infinity' for SBML object id log_time - faults.put(952, SBMLTestSuiteTest.FAULT.MATHML_PARSING); // cause: Error adding Lambda function UnsupportedConstruct: error parsing expression ' ': node type 'notanumber' not supported yet faults.put(956, SBMLTestSuiteTest.FAULT.MATHML_PARSING); // cause: Error adding Lambda function UnsupportedConstruct: error parsing expression ' ': node type 'notanumber' not supported yet faults.put(961, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'rateOf_re15' to model: 're15' is either not found in your model or is not allowed to be used in the current context. Check that you have provided t faults.put(969, SBMLTestSuiteTest.FAULT.EXPRESSION_BINDING_EXCEPTION); // cause: Error binding global parameter 'Metabolite_11' to model: 'UNRESOLVED.initConc' is either not found in your model or is not allowed to be used in the current context. Check that yo