Skip to content

Commit 902787e

Browse files
rwmcintoshmsevestreYuri05Yuri05
authored
Merge develop into v13 (#2413)
* Fixes #2383 Align with new IParameterFactory.CreateDistributedParameter contract (#2384) OSPSuite.Core's CreateDistributedParameter now pre-creates the sub-parameters referenced by the distribution formula (Mean, Deviation/GeometricDeviation/Minimum/Maximum, Percentile). This requires MoBi's three callers of the mapper/factory to be adjusted so they no longer add duplicate sub-parameters or apply the value redundantly. PathAndValueEntityToDistributedParameterMapper: when a caller-supplied sub-parameter overlaps a factory-created one, update the existing child's value instead of calling Add (which would throw NotUniqueNameException). New unit test covers this case. IndividualParameterToParameterDTOMapper / SpatialStructureContentExporter: the OSPSuite.Core mapper now applies the value internally (constant formula for plain parameters, fixed value via Value setter for distributed). The redundant constant-formula assignment is removed and IFormulaFactory is no longer needed in either class. * Fixes #2398 Update dimensions (#2401) Co-authored-by: Yuri05 <Yuri05@github.com> * update OSPSuite.Core to the latest 12.3 (#2408) Co-authored-by: Yuri05 <Yuri05@github.com> --------- Co-authored-by: Michael Sevestre <michael@design2code.ca> Co-authored-by: Juri Solodenko <Yuri05@users.noreply.github.com> Co-authored-by: Yuri05 <Yuri05@github.com>
1 parent 5c1b3a7 commit 902787e

7 files changed

Lines changed: 92 additions & 36 deletions

dimensions

src/MoBi.Core/Mappers/PathAndValueEntityToDistributedParameterMapper.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
using OSPSuite.Core.Domain;
1+
using System.Collections.Generic;
2+
using OSPSuite.Core.Domain;
23
using OSPSuite.Core.Domain.Builder;
34
using OSPSuite.Core.Domain.Formulas;
4-
using System.Collections.Generic;
55
using OSPSuite.Utility.Extensions;
66

77
namespace MoBi.Core.Mappers
@@ -32,6 +32,16 @@ private void addSubParameters<TBuilder>(IReadOnlyList<TBuilder> subParameters, I
3232
{
3333
subParameters.Each(subParameter =>
3434
{
35+
//the factory pre-creates the sub-parameters referenced by the distribution formula and a Percentile.
36+
//If the caller provides a sub-parameter with the same name, just update the existing one's value.
37+
var existing = distributedParameter.GetSingleChildByName<IParameter>(subParameter.Name);
38+
if (existing != null)
39+
{
40+
if (subParameter.Value.HasValue)
41+
existing.Value = subParameter.Value.Value;
42+
return;
43+
}
44+
3545
distributedParameter.Add(_parameterFactory.CreateParameter(subParameter.Name, subParameter.Value, subParameter.Dimension, formula: subParameter.Formula, displayUnit: subParameter.DisplayUnit));
3646
});
3747
}

src/MoBi.Presentation/Mappers/IndividualParameterToParameterDTOMapper.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@ public class IndividualParameterToParameterDTOMapper : IIndividualParameterToPar
1818
{
1919
private readonly IParameterToParameterDTOMapper _parameterToParameterDTOMapper;
2020
private readonly IParameterValueToParameterMapper _parameterValueToParameterMapper;
21-
private readonly IFormulaFactory _formulaFactory;
2221
private readonly ICloneManagerForBuildingBlock _cloneManager;
2322

24-
public IndividualParameterToParameterDTOMapper(IParameterToParameterDTOMapper parameterToParameterDTOMapper, IParameterValueToParameterMapper parameterValueToParameterMapper, IFormulaFactory formulaFactory, ICloneManagerForBuildingBlock cloneManager)
23+
public IndividualParameterToParameterDTOMapper(IParameterToParameterDTOMapper parameterToParameterDTOMapper, IParameterValueToParameterMapper parameterValueToParameterMapper, ICloneManagerForBuildingBlock cloneManager)
2524
{
2625
_parameterToParameterDTOMapper = parameterToParameterDTOMapper;
2726
_parameterValueToParameterMapper = parameterValueToParameterMapper;
28-
_formulaFactory = formulaFactory;
2927
_cloneManager = cloneManager;
3028
}
3129

@@ -39,18 +37,32 @@ public ParameterDTO MapFrom(IndividualBuildingBlock individualBuildingBlock, Ind
3937

4038
private IParameter parameterForIndividualParameter(IndividualBuildingBlock selectedIndividual, IndividualParameter individualParameter)
4139
{
40+
//the mapper already takes care of applying the value (constant formula for plain parameters,
41+
//fixed value via the distributed parameter Value setter for distributed ones).
4242
var parameter = _parameterValueToParameterMapper.MapFrom(individualParameter);
4343
if (parameter is IDistributedParameter distributedParameter)
4444
{
45+
//the factory pre-creates the sub-parameters referenced by the distribution formula plus a Percentile.
46+
//If the individual provides matching sub-parameters, update the existing entries so we don't end up
47+
//with duplicate children (which would throw a NotUniqueNameException).
4548
var subParameters = selectedIndividual.Where(x => isSubParameter(x, individualParameter));
46-
subParameters.Each(subParameter => distributedParameter.Add(parameterForIndividualParameter(selectedIndividual, subParameter)));
49+
subParameters.Each(subParameter =>
50+
{
51+
var existing = distributedParameter.GetSingleChildByName<IParameter>(subParameter.Name);
52+
if (existing != null)
53+
{
54+
if (subParameter.Value.HasValue)
55+
existing.Value = subParameter.Value.Value;
56+
return;
57+
}
58+
distributedParameter.Add(parameterForIndividualParameter(selectedIndividual, subParameter));
59+
});
4760
}
48-
else
61+
else if (individualParameter.Formula != null && !individualParameter.Value.HasValue)
4962
{
50-
if (individualParameter.Value.HasValue)
51-
parameter.Formula = _formulaFactory.ConstantFormula(individualParameter.Value.Value, individualParameter.Dimension);
52-
else if (individualParameter.Formula != null)
53-
parameter.Formula = _cloneManager.Clone(individualParameter.Formula, new FormulaCache());
63+
//only clone an explicit formula here when no value was provided, because a value would already
64+
//have been turned into a constant formula by the mapper above and would otherwise be overwritten.
65+
parameter.Formula = _cloneManager.Clone(individualParameter.Formula, new FormulaCache());
5466
}
5567
return parameter;
5668
}

src/MoBi.Presentation/Tasks/SpatialStructureContentExporter.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,20 @@ public class SpatialStructureContentExporter : ISpatialStructureContentExporter
3131
private readonly IObjectPathFactory _objectPathFactory;
3232
private readonly ICloneManagerForBuildingBlock _cloneManager;
3333
private readonly IPathAndValueEntityToParameterValueMapper _pathAndValueEntityToParameterValueMapper;
34-
private readonly IFormulaFactory _formulaFactory;
3534
private readonly IParameterValueToParameterMapper _individualParameterToParameterMapper;
3635
private readonly IInteractionTaskContext _interactionTaskContext;
3736
private readonly IMoBiApplicationController _applicationController;
3837

39-
public SpatialStructureContentExporter(IMoBiSpatialStructureFactory spatialStructureFactory,
40-
ICloneManagerForBuildingBlock cloneManager,
41-
IObjectPathFactory objectPathFactory,
42-
IPathAndValueEntityToParameterValueMapper pathAndValueEntityToParameterValueMapper,
43-
IFormulaFactory formulaFactory,
38+
public SpatialStructureContentExporter(IMoBiSpatialStructureFactory spatialStructureFactory,
39+
ICloneManagerForBuildingBlock cloneManager,
40+
IObjectPathFactory objectPathFactory,
41+
IPathAndValueEntityToParameterValueMapper pathAndValueEntityToParameterValueMapper,
4442
IParameterValueToParameterMapper individualParameterToParameterMapper, IInteractionTaskContext interactionTaskContext, IMoBiApplicationController applicationController)
4543
{
4644
_spatialStructureFactory = spatialStructureFactory;
4745
_cloneManager = cloneManager;
4846
_objectPathFactory = objectPathFactory;
4947
_pathAndValueEntityToParameterValueMapper = pathAndValueEntityToParameterValueMapper;
50-
_formulaFactory = formulaFactory;
5148
_individualParameterToParameterMapper = individualParameterToParameterMapper;
5249
_interactionTaskContext = interactionTaskContext;
5350
_applicationController = applicationController;
@@ -230,12 +227,13 @@ private void addIndividualParameterToContainerByPath(IndividualParameter individ
230227

231228
private IParameter createParameter(IndividualParameter individualParameter)
232229
{
230+
//the mapper already takes care of applying the value (constant formula for plain parameters,
231+
//fixed value via the distributed parameter Value setter for distributed ones).
233232
var parameterToAdd = _individualParameterToParameterMapper.MapFrom(individualParameter);
234233

235-
// The mapper does not create a formula for the parameter. Caller must clone or create the formula based on how it will be used
236-
if (individualParameter.Value.HasValue)
237-
parameterToAdd.Formula = _formulaFactory.ConstantFormula(individualParameter.Value.Value, individualParameter.Dimension);
238-
else if (individualParameter.Formula != null)
234+
//only clone an explicit formula here when no value was provided, because a value would already
235+
//have been turned into a constant formula by the mapper above and would otherwise be overwritten.
236+
if (individualParameter.Formula != null && !individualParameter.Value.HasValue)
239237
parameterToAdd.Formula = _cloneManager.Clone(individualParameter.Formula);
240238

241239
return parameterToAdd;

tests/MoBi.Tests/Core/Mapper/PathAndValueEntityToDistributedParameterMapperSpecs.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,51 @@ public void should_create_a_distributed_parameter_with_sub_parameters()
6262
_result.Children.Count.ShouldBeEqualTo(2);
6363
}
6464
}
65+
66+
public class When_creating_a_distributed_parameter_whose_factory_already_pre_created_overlapping_sub_parameters : concern_for_PathAndValueEntityToDistributedParameterMapper
67+
{
68+
private IndividualParameter _individualParameter;
69+
private IDistributedParameter _distributedParameter;
70+
private IReadOnlyList<IndividualParameter> _subParameters;
71+
private IDistributedParameter _result;
72+
73+
protected override void Context()
74+
{
75+
base.Context();
76+
_individualParameter = new IndividualParameter { Name = "Name", Value = 5.0, DistributionType = DistributionType.Discrete };
77+
_subParameters = new[] { new IndividualParameter { Name = "Mean", Value = 42.0 }, new IndividualParameter { Name = "Percentile", Value = 0.7 } };
78+
79+
//factory now returns a distributed parameter that already has Mean and Percentile placeholders
80+
_distributedParameter = new DistributedParameter().WithName("Name");
81+
_distributedParameter.Add(new Parameter().WithName("Mean"));
82+
_distributedParameter.Add(new Parameter().WithName("Percentile"));
83+
84+
A.CallTo(() => _parameterFactory.CreateDistributedParameter(_individualParameter.Name, _individualParameter.DistributionType.Value, A<double?>._, _individualParameter.Dimension, A<string>._, A<Unit>._)).Returns(_distributedParameter);
85+
A.CallTo(() => _parameterFactory.CreateParameter(A<string>._, A<double?>._, A<IDimension>._, A<string>._, A<IFormula>._, A<Unit>._))
86+
.ReturnsLazily(x => new Parameter().WithName(x.Arguments.Get<string>(0)).WithValue(x.Arguments.Get<double?>(1) ?? 0));
87+
}
88+
89+
protected override void Because()
90+
{
91+
_result = sut.MapFrom(_individualParameter, DistributionType.Discrete, _subParameters);
92+
}
93+
94+
[Observation]
95+
public void should_not_throw_due_to_duplicate_sub_parameter_names()
96+
{
97+
_result.ShouldNotBeNull();
98+
}
99+
100+
[Observation]
101+
public void should_keep_a_single_child_per_sub_parameter_name()
102+
{
103+
_result.Children.Count.ShouldBeEqualTo(2);
104+
}
105+
106+
[Observation]
107+
public void the_caller_supplied_sub_parameter_values_should_win_over_the_factory_placeholders()
108+
{
109+
_result.GetSingleChildByName<IParameter>("Mean").Value.ShouldBeEqualTo(42.0);
110+
}
111+
}
65112
}

tests/MoBi.Tests/Presentation/Mapper/IndividualParameterToParameterDTOMapperSpecs.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,15 @@ namespace MoBi.Presentation.Mapper
1515
internal class concern_for_IndividualParameterToParameterDTOMapper : ContextSpecification<IndividualParameterToParameterDTOMapper>
1616
{
1717
protected ICloneManagerForBuildingBlock _cloneManagerForBuildingBlock;
18-
protected IFormulaFactory _formulaFactory;
1918
protected IParameterValueToParameterMapper _parameterValueToParameterMapper;
2019
protected IParameterToParameterDTOMapper _parameterToParameterDTOMapper;
2120

2221
protected override void Context()
2322
{
2423
_cloneManagerForBuildingBlock = A.Fake<ICloneManagerForBuildingBlock>();
25-
_formulaFactory = A.Fake<IFormulaFactory>();
2624
_parameterValueToParameterMapper = A.Fake<IParameterValueToParameterMapper>();
2725
_parameterToParameterDTOMapper = A.Fake<IParameterToParameterDTOMapper>();
28-
sut = new IndividualParameterToParameterDTOMapper(_parameterToParameterDTOMapper, _parameterValueToParameterMapper, _formulaFactory, _cloneManagerForBuildingBlock);
26+
sut = new IndividualParameterToParameterDTOMapper(_parameterToParameterDTOMapper, _parameterValueToParameterMapper, _cloneManagerForBuildingBlock);
2927

3028
A.CallTo(() => _parameterToParameterDTOMapper.MapFrom(A<IParameter>._)).ReturnsLazily(x => new ParameterDTO(x.GetArgument<IParameter>(0)));
3129
}
@@ -70,12 +68,6 @@ protected override IndividualParameter GetParameter()
7068
{
7169
return new IndividualParameter { Value = 4 };
7270
}
73-
74-
[Observation]
75-
public void the_formula_factory_creates_a_formula_from_the_value()
76-
{
77-
A.CallTo(() => _formulaFactory.ConstantFormula(_individualParameter.Value.Value, _individualParameter.Dimension)).MustHaveHappened();
78-
}
7971
}
8072

8173
internal class When_mapping_from_individual_to_dto_for_simple_parameter_with_formula : When_mapping_from_individual_to_dto_for_individual_parameter

tests/MoBi.Tests/Presentation/Tasks/SpatialStructureContentExporterSpecs.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,13 @@ public abstract class concern_for_SpatialStructureContentExporter : ContextSpeci
2828
private IMoBiApplicationController _applicationController;
2929
protected ISelectFolderAndIndividualAndExpressionFromProjectPresenter _selectIndividualAndExpressionFromProjectPresenter;
3030
protected ICloneManagerForBuildingBlock _cloneManager;
31-
protected IFormulaFactory _formulaFactory;
3231
protected IPathAndValueEntityToParameterValueMapper _pathAndValueEntityToParameterValueMapper;
3332
private IObjectBaseFactory _objectBaseFactory;
3433
private IParameterValueToParameterMapper _individualParameterToParameterMapper;
3534
protected SpatialStructure _spatialStructure;
3635

3736
protected override void Context()
3837
{
39-
_formulaFactory = A.Fake<IFormulaFactory>();
4038
_spatialStructureFactory = A.Fake<IMoBiSpatialStructureFactory>();
4139
_interactionTaskContext = A.Fake<IInteractionTaskContext>();
4240
_applicationController = A.Fake<IMoBiApplicationController>();
@@ -57,7 +55,7 @@ protected override void Context()
5755
A.CallTo(() => _interactionTaskContext.InteractionTask).Returns(_interactionTask);
5856
A.CallTo(() => _individualParameterToParameterMapper.MapFrom(A<IndividualParameter>._)).ReturnsLazily(x => newParameter(x.Arguments.Get<IndividualParameter>(0)));
5957
A.CallTo(() => _spatialStructureFactory.Create()).Returns(_spatialStructure);
60-
sut = new SpatialStructureContentExporter(_spatialStructureFactory, _cloneManager, _objectPathFactory, _pathAndValueEntityToParameterValueMapper, _formulaFactory, _individualParameterToParameterMapper, _interactionTaskContext, _applicationController);
58+
sut = new SpatialStructureContentExporter(_spatialStructureFactory, _cloneManager, _objectPathFactory, _pathAndValueEntityToParameterValueMapper, _individualParameterToParameterMapper, _interactionTaskContext, _applicationController);
6159
}
6260

6361
private static IParameter newParameter(IndividualParameter individualParameter)
@@ -226,7 +224,6 @@ protected override void Context()
226224
A.CallTo(() => _selectIndividualAndExpressionFromProjectPresenter.GetPathIndividualAndExpressionsForExport(_containerToSave)).Returns(("FilePath", _individual, _expressionProfiles));
227225
A.CallTo(() => _spatialStructureFactory.Create()).Returns(_tmpSpatialStructure);
228226
A.CallTo(() => _cloneManager.Clone(_containerToSave, _tmpSpatialStructure.FormulaCache)).Returns(_clonedContainer);
229-
A.CallTo(() => _formulaFactory.ConstantFormula(replacementIndividualParameter.Value.Value, replacementIndividualParameter.Dimension)).ReturnsLazily(x => new ConstantFormula(x.Arguments.Get<double>(0)));
230227
A.CallTo(() => _interactionTaskContext.Context.Create<ParameterValuesBuildingBlock>()).Returns(_parameterValuesBuildingBlock);
231228
A.CallTo(() => _interactionTask.Save(A<SpatialStructureTransfer>._, A<string>._)).Invokes(x => _transfer = x.Arguments.Get<SpatialStructureTransfer>(0));
232229
A.CallTo(() => _cloneManager.Clone(A<InitialCondition>._, A<FormulaCache>._)).ReturnsLazily(x => newInitialCondition(x.Arguments.Get<InitialCondition>(0)));

0 commit comments

Comments
 (0)