Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

632 import concentration based sbml files #633

Merged
merged 10 commits into from
Oct 7, 2021
2 changes: 2 additions & 0 deletions src/MoBi.Engine/EngineRegister.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ public override void RegisterInContainer(IContainer container)
x.AssemblyContainingType<EngineRegister>();
x.WithConvention(new OSPSuiteRegistrationConvention(registerConcreteType: true));
x.ExcludeType<UnitDefinitionImporter>();
x.ExcludeType<SpeciesImporter>();
x.ExcludeType<FunctionDefinitionImporter>();
});

container.Register<SBMLImporterRepository, SBMLImporterRepository>();
container.Register<ASTHandler, ASTHandler>();
container.Register<IUnitDefinitionImporter, UnitDefinitionImporter>(LifeStyle.Singleton);
container.Register<ISpeciesImporter, SpeciesImporter>(LifeStyle.Singleton);
container.Register<IFunctionDefinitionImporter, FunctionDefinitionImporter>(LifeStyle.Singleton);
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/MoBi.Engine/Sbml/ASTHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class ASTHandler
private IMoBiProject _sbmlProject;
public List<FunctionDefinition> FunctionDefinitions { get; set; }
public bool NeedAbsolutePath { get; set; }
public bool UseConcentrations { get; set; } = false;

private readonly IObjectPathFactory _objectPathFactory;
private readonly IObjectBaseFactory _objectBaseFactory;
Expand Down Expand Up @@ -808,13 +809,14 @@ private string parseLog(ASTNode rootNode)
/// <summary>
/// Checks if a object path for the given objectName is already existant and creates a new one if not.
/// </summary>
private string getObjectPathName(string parentContainer, string objectName)
private string getObjectPathName(string parentContainer, string objectName, bool useConcentration = false)
{
if (objectPathExistent(objectName))
return objectName;

var alias = createAliasFrom(objectName);
_objectPaths.Add(_objectPathFactory.CreateFormulaUsablePathFrom(parentContainer, objectName).WithAlias(alias));
var usablePath = useConcentration ? _objectPathFactory.CreateFormulaUsablePathFrom(parentContainer, objectName, Constants.Parameters.CONCENTRATION) : _objectPathFactory.CreateFormulaUsablePathFrom(parentContainer, objectName);
_objectPaths.Add(usablePath.WithAlias(alias));
return alias;
}

Expand Down Expand Up @@ -905,7 +907,7 @@ private string getObjectPathNameOfMolecule(IMoleculeBuilder molecule, Species sp
//reaction
if (NeedAbsolutePath == false)
{
return getObjectPathName(ObjectPath.PARENT_CONTAINER, molecule.Name);
return getObjectPathName(ObjectPath.PARENT_CONTAINER, molecule.Name, UseConcentrations);
}

if (_sbmlInformation.MoleculeInformation.All(info => info.GetMoleculeBuilderName() != molecule.Name))
Expand Down
5 changes: 4 additions & 1 deletion src/MoBi.Engine/Sbml/ReactionImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ public class ReactionImporter : SBMLImporter
private readonly IPassiveTransportBuildingBlock _passiveTransportBuildingBlock;
private readonly IDimensionFactory _dimensionFactory;
private readonly IFunctionDefinitionImporter _functionDefinitionImporter;
private readonly ISpeciesImporter _speciesImporter;

public ReactionImporter(IObjectPathFactory objectPathFactory, IObjectBaseFactory objectBaseFactory, IMoBiDimensionFactory moBiDimensionFactory, ASTHandler astHandler, IMoBiContext context, IReactionBuildingBlockFactory reactionBuildingBlockFactory, IFunctionDefinitionImporter functionDefinitionImporter)
public ReactionImporter(IObjectPathFactory objectPathFactory, IObjectBaseFactory objectBaseFactory, IMoBiDimensionFactory moBiDimensionFactory, ASTHandler astHandler, IMoBiContext context, IReactionBuildingBlockFactory reactionBuildingBlockFactory, IFunctionDefinitionImporter functionDefinitionImporter, ISpeciesImporter speciesImporter)
: base(objectPathFactory, objectBaseFactory, astHandler, context)
{
_dimensionFactory = moBiDimensionFactory;
Expand All @@ -37,6 +38,7 @@ public ReactionImporter(IObjectPathFactory objectPathFactory, IObjectBaseFactory
_passiveTransportBuildingBlock = ObjectBaseFactory.Create<IPassiveTransportBuildingBlock>()
.WithName(SBMLConstants.SBML_PASSIVETRANSPORTS_BB);
_functionDefinitionImporter = functionDefinitionImporter;
_speciesImporter = speciesImporter;
}

/// <summary>
Expand All @@ -45,6 +47,7 @@ public ReactionImporter(IObjectPathFactory objectPathFactory, IObjectBaseFactory
protected override void Import(Model model)
{
_astHandler.FunctionDefinitions = _functionDefinitionImporter.FunctionDefinitions;
_astHandler.UseConcentrations = _speciesImporter.UseConcentrations;
for (long i = 0; i < model.getNumReactions(); i++)
{
CreateReaction(model.getReaction(i), model);
Expand Down
4 changes: 2 additions & 2 deletions src/MoBi.Engine/Sbml/SBMLImporterRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public IEnumerable<ISBMLImporter> All()
{
yield return _container.Resolve<IUnitDefinitionImporter>();
yield return _container.Resolve<CompartmentImporter>();
yield return _container.Resolve<SpeciesImporter>();
yield return _container.Resolve<ISpeciesImporter>();
yield return _container.Resolve<ParameterImporter>();
yield return _container.Resolve<IFunctionDefinitionImporter>();
yield return _container.Resolve<ReactionImporter>();
Expand All @@ -30,7 +30,7 @@ public IEnumerable<ISBMLImporter> AllFor(Model sbmlModel)
yield return _container.Resolve<IUnitDefinitionImporter>();
yield return _container.Resolve<CompartmentImporter>();
if (sbmlModel.getNumSpecies() != 0)
yield return _container.Resolve<SpeciesImporter>();
yield return _container.Resolve<ISpeciesImporter>();
if (sbmlModel.getNumParameters() != 0)
yield return _container.Resolve<ParameterImporter>();
if (sbmlModel.getNumFunctionDefinitions() != 0)
Expand Down
37 changes: 24 additions & 13 deletions src/MoBi.Engine/Sbml/SpeciesImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@
using OSPSuite.Core.Domain.Formulas;
using OSPSuite.Core.Domain.Services;
using OSPSuite.Core.Domain.UnitSystem;
using OSPSuite.Utility;
using Model = libsbmlcs.Model;
using Unit = OSPSuite.Core.Domain.UnitSystem.Unit;

namespace MoBi.Engine.Sbml
{
public class SpeciesImporter : SBMLImporter
public interface ISpeciesImporter : ISBMLImporter
{
bool UseConcentrations { get; }
}

public class SpeciesImporter : SBMLImporter, IStartable, ISpeciesImporter
{
private readonly IMoleculeStartValuesCreator _moleculeStartValuesCreator;
internal IMoleculeBuildingBlock MoleculeBuildingBlock;
Expand All @@ -25,7 +31,6 @@ public class SpeciesImporter : SBMLImporter
private readonly IMoBiDimensionFactory _moBiDimensionFactory;
private readonly Dictionary<string, Dimension> _dimensionDictionary;
private IUnitDefinitionImporter _unitDefinitionImporter;
private IFormulaFactory _formulaFactory;
private int _counter;

public SpeciesImporter(IObjectPathFactory objectPathFactory, IObjectBaseFactory objectBaseFactory, IMoleculeBuilderFactory moleculeBuilderFactory, IMoleculeStartValuesCreator moleculeStartValuesCreator, IMoBiDimensionFactory moBiDimensionFactory, ASTHandler astHandler, IMoBiContext context, IUnitDefinitionImporter unitDefinitionImporter, IFormulaFactory formulaFactory)
Expand All @@ -37,9 +42,10 @@ public SpeciesImporter(IObjectPathFactory objectPathFactory, IObjectBaseFactory
_counter = 1;
_dimensionDictionary = new Dictionary<string, Dimension>();
_unitDefinitionImporter = unitDefinitionImporter;
_formulaFactory = formulaFactory;
}

public bool UseConcentrations { get; private set; }

protected override void Import(Model model)
{
CreateMoleculeBuildingBlock();
Expand All @@ -48,7 +54,6 @@ protected override void Import(Model model)
CreateMoleculeFromSpecies(model.getSpecies(i));
}
CheckMoleculeNameContainer();
CreateDummySpecies();
CreateMoleculeStartValueBuildingBlock(model);
SetMoleculeStartValues(model);
SetDummyMSVs();
Expand Down Expand Up @@ -211,15 +216,16 @@ private void SetMoleculeStartValues(Model model)
//unit is {unit of amount}/{unit of size}
var baseValue = _unitDefinitionImporter.ToMobiBaseUnit(sbmlUnit, sbmlSpecies.getInitialConcentration());
msv.StartValue = baseValue.value;
msv.Formula = _formulaFactory.ConstantFormula(baseValue.value, baseValue.dimension);

var sizeDimension = GetSizeDimensionFromCompartment(sbmlSpecies, model);
if (amountDimension == null) continue;
if (sizeDimension == null) continue;

var newDim = _moBiDimensionFactory.DimensionForUnit($"{amountDimension.BaseUnit.Name}/{sizeDimension.BaseUnit.Name}") ?? CreateNewDimension(amountDimension, sizeDimension);
msv.Dimension = newDim;
molInfo.SetDimension(newDim);
msv.Formula = _context.Create<ExplicitFormula>($"{msv.Name}_0").WithName($"{msv.Name}_0").WithDimension(amountDimension).WithFormulaString($"{baseValue.value} * {Constants.VOLUME_ALIAS}");
msv.Formula.AddObjectPath(
ObjectPathFactory.CreateFormulaUsablePathFrom(ObjectPath.PARENT_CONTAINER, Constants.Parameters.VOLUME)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msevestre Check the change in the call. This is why the Volume was not found before. It should not be one single string but the list of all individual paths

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it would be very nice to use the code base for concentration based reactions, but the way the importer is written it is not trivial to me. I would propose to keep it in mind for the future but just use this solution for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good. What about the reaction rate? Aren;t they expecting concentration?

Copy link
Member Author

@abdelr abdelr Oct 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msevestre I think this is related to the second PR, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know lol.

.WithAlias(Constants.VOLUME_ALIAS)
.WithDimension(_moBiDimensionFactory.Dimension(Constants.Dimension.VOLUME))
);
_moleculeStartValuesBuildingBlock.AddFormula(msv.Formula);
msv.Dimension = amountDimension;
molInfo.SetDimension(amountDimension);
UseConcentrations = true;
}
else
{
Expand Down Expand Up @@ -352,5 +358,10 @@ private void SetDummyMSVs()
}
}
}

public void Start()
{
UseConcentrations = false;
}
}
}
22 changes: 22 additions & 0 deletions tests/MoBi.Tests/Core/SBML/ReactionImporterSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,26 @@ public void ShouldCreateAliases()
_moBiProject.ReactionBlockCollection.First().ElementAt(7).Formula.ObjectPaths.Where(op => op.Alias == "Ct").ShouldNotBeEmpty();
}
}

public class ConcentrationBasedReactionImporterTests : ReactionImporterSpecs
{
protected override void Context()
{
base.Context();
_fileName = Helper.TestFileFullPath("tiny_example_12.xml");
}

protected override void Because()
{
_sbmlTask.ImportModelFromSbml(_fileName, _moBiProject);
}

[Observation]
public void should_parse_user_defined_functions()
{
var gkReaction = _moBiProject.ReactionBlockCollection.First().First();
var glucosePath = gkReaction.Formula.ObjectPaths.ElementAt(1);
glucosePath.Last().ShouldBeEqualTo(Constants.Parameters.CONCENTRATION);
}
}
}
14 changes: 13 additions & 1 deletion tests/MoBi.Tests/Core/SBML/SpeciesImporterSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,19 @@ protected override void Context()
public void should_understand_litre_as_unit()
{
var msvbb = _moBiProject.MoleculeStartValueBlockCollection.FirstOrDefault();
msvbb.FirstOrDefault().Dimension.Name.ShouldBeEqualTo("Concentration (molar)");
msvbb.FirstOrDefault().Dimension.Name.ShouldBeEqualTo("Amount");
}

[Observation]
public void should_assign_molecule_start_values_as_concentrations()
{
var msvbb = _moBiProject.MoleculeStartValueBlockCollection.FirstOrDefault();
var glucose = msvbb.First();
glucose.Formula.ToString().ShouldBeEqualTo("5000 * V");
var volumePath = glucose.Formula.ObjectPaths.First();
volumePath.ToString().ShouldBeEqualTo("..|Volume");
volumePath.Alias.ShouldBeEqualTo("V");
volumePath.Count.ShouldBeEqualTo(2);
}
}
}