Skip to content

Commit

Permalink
837 sum formula parent (#1901)
Browse files Browse the repository at this point in the history
* Fixes #837 sum formula parent

* Fixes #837 sum formula parent

* Fixes #837 sum formula parent

* PR feedback
  • Loading branch information
msevestre authored Feb 16, 2023
1 parent 1b21594 commit 75881f2
Show file tree
Hide file tree
Showing 25 changed files with 253 additions and 51 deletions.
4 changes: 3 additions & 1 deletion src/OSPSuite.Assets/UIConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,9 @@ public static string TimeArrayValuesDoesNotMatchFirstIndividual(int id, int inde
public static string UnitIsNotDefinedInDimension(string unit, string dimension) => $"Unit '{unit}' is not defined in dimension '{dimension}'.";

public static string CouldNotFindNeighborhoodBetween(string container1, string container2) => $"Could not find neighborhood between '{container1}' and '{container2}'";


public const string InParentTagCanOnlyBeUsedWithAndOperator = "IN PARENT tag can only be used with AND operator";

public static class SensitivityAnalysis
{
public static readonly string NoSimulationDefined = "No simulation defined";
Expand Down
10 changes: 5 additions & 5 deletions src/OSPSuite.Core/Domain/Builder/SpatialStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,16 @@ public override void AcceptVisitor(IVisitor visitor)
}

/// <summary>
/// Copy the references for first and second Neighbor from <paramref name="sourcecNeighborhoodBuilder" /> to
/// Copy the references for first and second Neighbor from <paramref name="sourceNeighborhoodBuilder" /> to
/// <paramref name="targetNeighborhoodBuilder" />.
/// </summary>
/// <param name="sourcecNeighborhoodBuilder">The source neighborhood builder to copy neighbors from.</param>
/// <param name="sourceNeighborhoodBuilder">The source neighborhood builder to copy neighbors from.</param>
/// <param name="targetNeighborhoodBuilder">The neighborhood builder to copy neighbors to.</param>
private void updateNeighborsReferences(INeighborhoodBuilder sourcecNeighborhoodBuilder, INeighborhoodBuilder targetNeighborhoodBuilder)
private void updateNeighborsReferences(INeighborhoodBuilder sourceNeighborhoodBuilder, INeighborhoodBuilder targetNeighborhoodBuilder)
{
var objectPathFactory = new ObjectPathFactory(new AliasCreator());
var firstPath = objectPathFactory.CreateAbsoluteObjectPath(sourcecNeighborhoodBuilder.FirstNeighbor);
var secondPath = objectPathFactory.CreateAbsoluteObjectPath(sourcecNeighborhoodBuilder.SecondNeighbor);
var firstPath = objectPathFactory.CreateAbsoluteObjectPath(sourceNeighborhoodBuilder.FirstNeighbor);
var secondPath = objectPathFactory.CreateAbsoluteObjectPath(sourceNeighborhoodBuilder.SecondNeighbor);

foreach (var topContainer in TopContainers)
{
Expand Down
1 change: 1 addition & 0 deletions src/OSPSuite.Core/Domain/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ public static class ParameterExport
public const string OR = "Or";
public const string IN_CONTAINER = "In container";
public const string NOT_IN_CONTAINER = "Not in container";
public const string IN_PARENT = "In parent";
public const string LLOQ = "LLOQ";

public static string NameWithUnitFor(string name, IDimension dimension)
Expand Down
2 changes: 1 addition & 1 deletion src/OSPSuite.Core/Domain/Descriptors/DescriptorCriteria.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public enum CriteriaOperator
Or
}

public class DescriptorCriteria : List<IDescriptorCondition>, ISpecification<IEntity>, ISpecification<EntityDescriptor>
public class DescriptorCriteria : List<ITagCondition>, ISpecification<IEntity>, ISpecification<EntityDescriptor>
{
//Default behavior
public CriteriaOperator Operator { get; set; } = CriteriaOperator.And;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ public DescriptorCriteriaBuilder InContainer(string containerName)
return this;
}

public DescriptorCriteriaBuilder InParent()
{
_criteria.Add(new InParentCondition());
return this;
}

public DescriptorCriteriaBuilder NotInContainer(string containerName)
{
_criteria.Add(new NotInContainerCondition(containerName));
Expand Down
11 changes: 0 additions & 11 deletions src/OSPSuite.Core/Domain/Descriptors/IDescriptorCondition.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public InContainerCondition(string tag) : base(tag, Constants.IN_CONTAINER)
{
}

public override IDescriptorCondition CloneCondition() => new InContainerCondition(Tag);
public override ITagCondition CloneCondition() => new InContainerCondition(Tag);

public override bool IsSatisfiedBy(EntityDescriptor entityDescriptor)
{
Expand Down
22 changes: 22 additions & 0 deletions src/OSPSuite.Core/Domain/Descriptors/InParentCondition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace OSPSuite.Core.Domain.Descriptors
{
public class InParentCondition : TagCondition
{
public InParentCondition() : base(Constants.IN_PARENT, Constants.IN_PARENT)
{
}

public override string Condition { get; } = Constants.IN_PARENT.ToUpper();

//false because this condition should never be evaluated as it will need to be replaced
//by some InContainer conditions in the model
public override bool IsSatisfiedBy(EntityDescriptor item) => false;

public override ITagCondition CloneCondition() => new InParentCondition();

public override void Replace(string keyword, string replacement)
{
/*nothing to do*/
}
}
}
2 changes: 1 addition & 1 deletion src/OSPSuite.Core/Domain/Descriptors/MatchAllCondition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public MatchAllCondition() : base(Constants.ALL_TAG, Constants.ALL_TAG)

public override bool IsSatisfiedBy(EntityDescriptor item) => true;

public override IDescriptorCondition CloneCondition() => new MatchAllCondition();
public override ITagCondition CloneCondition() => new MatchAllCondition();

public override void Replace(string keyword, string replacement)
{
Expand Down
2 changes: 1 addition & 1 deletion src/OSPSuite.Core/Domain/Descriptors/MatchTagCondition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public override bool IsSatisfiedBy(EntityDescriptor entityDescriptor)
return entityDescriptor.Tags.Contains(Tag);
}

public override IDescriptorCondition CloneCondition()
public override ITagCondition CloneCondition()
{
return new MatchTagCondition(Tag);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public NotInContainerCondition(string tag) : base(tag, Constants.NOT_IN_CONTAINE
{
}

public override IDescriptorCondition CloneCondition() => new NotInContainerCondition(Tag);
public override ITagCondition CloneCondition() => new NotInContainerCondition(Tag);

public override bool IsSatisfiedBy(EntityDescriptor entityDescriptor)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ public override bool IsSatisfiedBy(EntityDescriptor entityDescriptor)
return !entityDescriptor.Tags.Contains(Tag);
}

public override IDescriptorCondition CloneCondition() => new NotMatchTagCondition(Tag);
public override ITagCondition CloneCondition() => new NotMatchTagCondition(Tag);
}
}
11 changes: 9 additions & 2 deletions src/OSPSuite.Core/Domain/Descriptors/TagCondition.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using OSPSuite.Utility;

namespace OSPSuite.Core.Domain.Descriptors
{
public interface ITagCondition : IDescriptorCondition
public interface ITagCondition : ISpecification<EntityDescriptor>
{
/// <summary>
/// Returns the underlying tag associated with the condition
Expand All @@ -11,6 +13,11 @@ public interface ITagCondition : IDescriptorCondition
/// Returns the semantic display of the condition for the tag
/// </summary>
string Condition { get; }


ITagCondition CloneCondition();

void Replace(string keyword, string replacement);
}

public abstract class TagCondition : ITagCondition
Expand All @@ -31,7 +38,7 @@ protected TagCondition(string tag, string type) : this(type)

public virtual string Condition => $"{_type.ToUpper()} {Tag}";

public abstract IDescriptorCondition CloneCondition();
public abstract ITagCondition CloneCondition();

public virtual void Replace(string keyword, string replacement)
{
Expand Down
6 changes: 3 additions & 3 deletions src/OSPSuite.Core/Domain/KeywordReplacerCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public interface IKeywordReplacerCollection : IEnumerable<IKeywordReplacer>
/// <summary>
/// Replace the criteria value with all possible replacement induced by a IKeywordInTagReplacer
/// </summary>
void ReplaceIn(IDescriptorCondition descriptorCondition);
void ReplaceIn(ITagCondition tagCondition);
}

public class KeywordReplacerCollection : IKeywordReplacerCollection
Expand Down Expand Up @@ -82,9 +82,9 @@ public void ReplaceIn(Tags tags)
_allTagReplacer.Each(r => r.ReplaceIn(tags));
}

public void ReplaceIn(IDescriptorCondition descriptorCondition)
public void ReplaceIn(ITagCondition tagCondition)
{
_allTagReplacer.Each(r => r.ReplaceIn(descriptorCondition));
_allTagReplacer.Each(r => r.ReplaceIn(tagCondition));
}

private void replaceTagsIn(IEntity entity)
Expand Down
35 changes: 31 additions & 4 deletions src/OSPSuite.Core/Domain/Services/FormulaTask.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using OSPSuite.Assets;
using OSPSuite.Core.Domain.Descriptors;
using OSPSuite.Core.Domain.Formulas;
using OSPSuite.Core.Domain.UnitSystem;
using OSPSuite.Core.Extensions;
Expand Down Expand Up @@ -61,18 +61,21 @@ public class FormulaTask : IFormulaTask,
private readonly IObjectBaseFactory _objectBaseFactory;
private readonly IAliasCreator _aliasCreator;
private readonly IDimensionFactory _dimensionFactory;
private readonly IEntityPathResolver _entityPathResolver;
private readonly ICache<string, IList<ExplicitFormula>> _originIdToFormulaCache = new Cache<string, IList<ExplicitFormula>>();

public FormulaTask(
IObjectPathFactory objectPathFactory,
IObjectBaseFactory objectBaseFactory,
IAliasCreator aliasCreator,
IDimensionFactory dimensionFactory)
IDimensionFactory dimensionFactory,
IEntityPathResolver entityPathResolver)
{
_objectPathFactory = objectPathFactory;
_objectBaseFactory = objectBaseFactory;
_aliasCreator = aliasCreator;
_dimensionFactory = dimensionFactory;
_entityPathResolver = entityPathResolver;
}

public void CheckFormulaOriginIn(IModel model)
Expand Down Expand Up @@ -195,7 +198,7 @@ private IContainer getContainerOrThrow(IReadOnlyList<string> path, IUsingFormula
throw new OSPSuiteException(Error.CouldNotFindQuantityWithPath(path.ToPathString()));

return container;
}
}

public void ExpandDynamicFormulaIn(IModel model) => ExpandDynamicFormulaIn(model.Root);

Expand All @@ -211,13 +214,37 @@ public void ExpandDynamicFormulaIn(IContainer container)
if (dynamicFormula.Criteria.IsSatisfiedBy(entityUsingFormula))
throw new CircularReferenceInSumFormulaException(dynamicFormula.Name, entityUsingFormula.Name);

dynamicFormula.Criteria = updateDynamicFormulaCriteria(dynamicFormula, entityUsingFormula);
entityUsingFormula.Formula = dynamicFormula.ExpandUsing(allFormulaUsable, _objectPathFactory, _objectBaseFactory);
});
}

private DescriptorCriteria updateDynamicFormulaCriteria(DynamicFormula formula, IUsingFormula usingFormula)
{
//we need to replace IN PARENT criteria with actual criteria matching the parent of the usingFormula
var criteria = formula.Criteria;
var allInParentTags = criteria.Where(x => x.IsAnImplementationOf<InParentCondition>()).ToList();
var parent = usingFormula.ParentContainer;
if (!allInParentTags.Any() || parent == null)
return criteria;

//because we need to restrict operations by adding criteria automatically, only AND makes sense
if (criteria.Operator != CriteriaOperator.And)
throw new OSPSuiteException(Error.InParentTagCanOnlyBeUsedWithAndOperator);

//we clone the criteria and remove all instances of InParentCondition. Then we add the criteria to the parent specifically
var modifiedCriteria = criteria.Clone();
allInParentTags.Each(x => modifiedCriteria.RemoveByTag<InParentCondition>(x.Tag));

//add to the formula the link to parent. We use the consolidated path here so that we do not deal with the root container as criteria
var parentPath = _entityPathResolver.PathFor(parent).ToPathArray();
parentPath.Each(x=> modifiedCriteria.Add(new InContainerCondition(x)));
return modifiedCriteria;
}

public string AddParentVolumeReferenceToFormula(IFormula formula)
{
string volumeAlias = _aliasCreator.CreateAliasFrom(VOLUME_ALIAS, formula.ObjectPaths.Select(p => p.Alias));
var volumeAlias = _aliasCreator.CreateAliasFrom(VOLUME_ALIAS, formula.ObjectPaths.Select(p => p.Alias));

//possible reference
var volumeReferencePath = _objectPathFactory.CreateFormulaUsablePathFrom(PARENT_CONTAINER, VOLUME)
Expand Down
2 changes: 1 addition & 1 deletion src/OSPSuite.Core/Domain/Services/IKeywordReplacer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ public interface IKeywordInObjectPathReplacer : IKeywordReplacer
public interface IKeywordInTagsReplacer : IKeywordReplacer
{
void ReplaceIn(Tags tags);
void ReplaceIn(IDescriptorCondition descriptorCondition);
void ReplaceIn(ITagCondition descriptorCondition);
}
}
2 changes: 1 addition & 1 deletion src/OSPSuite.Core/Domain/Services/SimpleKeywordReplacer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void ReplaceIn(Tags tags)
tags.Replace(_keyword, _replacement);
}

public void ReplaceIn(IDescriptorCondition descriptorCondition)
public void ReplaceIn(ITagCondition descriptorCondition)
{
descriptorCondition.Replace(_keyword, _replacement);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ public override void PerformMapping()
}
}

public class InParentConditionXmlSerializer : TagConditionXmlSerializer<InParentCondition>
{
public override void PerformMapping()
{
/*nothing to do*/
}
}

public class InContainerConditionXmlSerializer : TagConditionXmlSerializer<InContainerCondition>
{
}
Expand Down
12 changes: 6 additions & 6 deletions tests/OSPSuite.Core.Tests/Domain/DescriptorCriteriaSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ public class When_checking_if_a_criteria_satisfies_some_tags_that_are_not_satisf
protected override void Context()
{
base.Context();
var cond1 = A.Fake<IDescriptorCondition>();
var cond1 = A.Fake<ITagCondition>();
A.CallTo(() => cond1.IsSatisfiedBy(_entityCriteria)).Returns(true);
var cond2 = A.Fake<IDescriptorCondition>();
var cond2 = A.Fake<ITagCondition>();
A.CallTo(() => cond2.IsSatisfiedBy(_entityCriteria)).Returns(false);
sut.Add(cond1);
sut.Add(cond2);
Expand Down Expand Up @@ -77,9 +77,9 @@ public class When_checking_if_a_criteria_satisfies_some_tags_that_are_not_satisf
protected override void Context()
{
base.Context();
var cond1 = A.Fake<IDescriptorCondition>();
var cond1 = A.Fake<ITagCondition>();
A.CallTo(() => cond1.IsSatisfiedBy(_entityCriteria)).Returns(true);
var cond2 = A.Fake<IDescriptorCondition>();
var cond2 = A.Fake<ITagCondition>();
A.CallTo(() => cond2.IsSatisfiedBy(_entityCriteria)).Returns(false);
sut.Add(cond1);
sut.Add(cond2);
Expand All @@ -98,9 +98,9 @@ public class When_checking_if_a_criteria_satisfies_some_tags_that_are_satisfied_
protected override void Context()
{
base.Context();
var cond1 = A.Fake<IDescriptorCondition>();
var cond1 = A.Fake<ITagCondition>();
A.CallTo(() => cond1.IsSatisfiedBy(_entityCriteria)).Returns(true);
var cond2 = A.Fake<IDescriptorCondition>();
var cond2 = A.Fake<ITagCondition>();
A.CallTo(() => cond2.IsSatisfiedBy(_entityCriteria)).Returns(true);
sut.Add(cond1);
sut.Add(cond2);
Expand Down
Loading

0 comments on commit 75881f2

Please sign in to comment.