Skip to content

Commit

Permalink
Merge pull request #95 from Akhetonics/feature/NonLinearity
Browse files Browse the repository at this point in the history
Feature/non linearity
  • Loading branch information
aignermax authored Jan 25, 2024
2 parents 766d625 + 3c32032 commit 360a980
Show file tree
Hide file tree
Showing 50 changed files with 996 additions and 338 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
using CAP_Contracts.Logger;
using CAP_Core.Components;
using CAP_Core.Components.ComponentHelpers;
using Components.ComponentDraftMapper.DTOs;
using CAP_Core.Grid.FormulaReading;
using CAP_Core.Tiles.Grid;
using CAP_DataAccess.Components.ComponentDraftMapper.DTOs;
using System.Globalization;
using System.Numerics;

namespace Components.ComponentDraftMapper
namespace CAP_DataAccess.Components.ComponentDraftMapper
{
public class ComponentDraftConverter
{
public ILogger Logger { get; }

public ComponentDraftConverter(ILogger logger)
{
CultureInfo englishCulture = CultureInfo.CreateSpecificCulture("en-US");
Thread.CurrentThread.CurrentCulture = englishCulture;
Thread.CurrentThread.CurrentUICulture = englishCulture;
Logger = logger;
}

Expand All @@ -25,7 +31,7 @@ private Component ConvertDraftToComponent(ComponentDraft draft, int typeNumber)
try
{
var parts = CreatePartsFromDraft(draft);
var connections = CreateConnectionsFromDraft(draft, parts);
var connections = CreateWaveLengthSpecificSMatricesFromDrafts(draft, parts);
return new Component(connections, draft.nazcaFunctionName, draft.nazcaFunctionParameters, parts, typeNumber, draft.identifier, DiscreteRotation.R0);
}
catch (Exception ex)
Expand All @@ -44,31 +50,79 @@ private Component ConvertDraftToComponent(ComponentDraft draft, int typeNumber)
foreach (var group in pinsGroupedByPosition)
{
var (x, y) = group.Key;
var realPins = group.Value.Select(pinDraft => new Pin(pinDraft.name, pinDraft.matterType, pinDraft.side)).ToList();
var realPins = group.Value.Select(pinDraft => new Pin(pinDraft.name, pinDraft.number, pinDraft.matterType, pinDraft.side)).ToList();
parts[x, y] = new Part(realPins);
}

return parts;
}

private List<CAP_Core.Components.Connection> CreateConnectionsFromDraft(ComponentDraft draft, Part[,] parts)
private Dictionary<int, SMatrix> CreateWaveLengthSpecificSMatricesFromDrafts(ComponentDraft draft, Part[,] parts)
{
return draft.connections.Select(dto =>
var definedMatrices = new Dictionary<int, SMatrix>();
var allPins = Component.GetAllPins(parts);
var allPinsGuids = allPins.SelectMany(p => new[] { p.IDInFlow, p.IDOutFlow }).ToList();
var pinNumberToModelMap = CreatePinNumberToModelMap(draft, parts);

foreach (var matrixDraft in draft.sMatrices)
{
var fromPinDTO = draft.pins.Single(p => p.number == dto.fromPinNr);
var toPinDTO = draft.pins.Single(p => p.number == dto.toPinNr);
var matrixModel = new SMatrix(allPinsGuids);
var connections = new Dictionary<(Guid, Guid), Complex>();
var nonLinearConnectionFunctions = new Dictionary<(Guid, Guid), ConnectionFunction>();

foreach (var connectionDraft in matrixDraft.connections)
{
if (!pinNumberToModelMap.TryGetValue(connectionDraft.FromPinNr, out var fromPinModel))
{
Logger.PrintErr($"unable to find suitable pin for 'fromPinNr' {connectionDraft.FromPinNr}.");
continue;
}
if (!pinNumberToModelMap.TryGetValue(connectionDraft.ToPinNr, out var toPinModel))
{
Logger.PrintErr($"unable to find suitable pin for 'toPinNr' {connectionDraft.FromPinNr}.");
continue;
}
connections.Add((fromPinModel.IDInFlow, toPinModel.IDOutFlow), connectionDraft.ToComplexNumber());
if (TryGetNonLinearConnectionFunction(connectionDraft, allPins, out var connectionFunction))
{
nonLinearConnectionFunctions.Add((fromPinModel.IDInFlow, toPinModel.IDOutFlow), connectionFunction);
}
}

var fromPinModel = FindModelPin(parts, fromPinDTO);
var toPinModel = FindModelPin(parts, toPinDTO);
matrixModel.SetValues(connections);
matrixModel.SetNonLinearConnectionFunctions(nonLinearConnectionFunctions);
definedMatrices.Add(matrixDraft.waveLength, matrixModel);
}

return new CAP_Core.Components.Connection
return definedMatrices;
}

public static Dictionary<int, Pin> CreatePinNumberToModelMap(ComponentDraft draft, Part[,] parts)
{
var map = new Dictionary<int, Pin>();
foreach (var pin in draft.pins)
{
var modelPin = FindModelPin(parts, pin);
if (modelPin != null)
{
FromPin = fromPinModel.IDInFlow,
ToPin = toPinModel.IDOutFlow,
Magnitude = dto.magnitude,
WireLengthNM = dto.wireLengthNM
};
}).ToList();
map[pin.number] = modelPin;
}
}
return map;
}
private bool TryGetNonLinearConnectionFunction(DTOs.Connection connectionDraft, List<Pin> allPins, out ConnectionFunction function)
{
function = default;
if (String.IsNullOrWhiteSpace(connectionDraft.Formula) || allPins?.Count == 0)
return false;

var convertedFunction = MathExpressionReader.ConvertToDelegate(connectionDraft.Formula, allPins);
if (convertedFunction != null)
{
function = (ConnectionFunction)convertedFunction;
return true;
}
return false;
}

private static Pin FindModelPin(Part[,] parts, PinDraft pinDraft)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using CAP_Contracts;
using Components.ComponentDraftMapper.DTOs;
using CAP_DataAccess.Components.ComponentDraftMapper.DTOs;

namespace Components.ComponentDraftMapper
namespace CAP_DataAccess.Components.ComponentDraftMapper
{
public class ComponentDraftFileReader
{
Expand All @@ -17,7 +17,13 @@ public ComponentDraftFileReader(IDataAccessor dataAccessor)

public IDataAccessor DataAccessor { get; }

public (ComponentDraft? draft, string error) TryReadJson(string path)
/// <summary>
/// error is null if everything goes right, otherwise draft is null and error is the error description.
/// it does not throw any exception directly
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public (ComponentDraft? draft, string? error) TryReadJson(string path)
{
if (DataAccessor.DoesResourceExist(path))
{
Expand All @@ -26,7 +32,7 @@ public ComponentDraftFileReader(IDataAccessor dataAccessor)
{
try
{
return (JsonSerializer.Deserialize<ComponentDraft>(fileContent) ?? new ComponentDraft(),"");
return (JsonSerializer.Deserialize<ComponentDraft>(fileContent) ?? new ComponentDraft(), null);
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using CAP_Contracts;
using Components.ComponentDraftMapper.DTOs;
using CAP_Core.Components.ComponentHelpers;
using CAP_DataAccess.Components.ComponentDraftMapper.DTOs;
using MathNet.Numerics;

namespace Components.ComponentDraftMapper
namespace CAP_DataAccess.Components.ComponentDraftMapper
{
public class ComponentDraftValidator
{
Expand All @@ -27,6 +30,7 @@ public class ComponentDraftValidator
public static readonly string ErrorToPinNrInvalid = "Err_016";
public static readonly string ErrorPinPartYBiggerMaxHeight = "Err_017";
public static readonly string ErrorPinPartXBiggerMaxHeight = "Err_018";
public static readonly string ErrorMatrixNotDefinedForWaveLength = "Err_019";

public IResourcePathChecker ResourcePathChecker { get; }

Expand All @@ -46,15 +50,19 @@ public bool ResourceExists(string godotPath)
public (bool isValid, string errorMsg) Validate(ComponentDraft draft)
{
string errorMsg = "";
if (draft.overlays.Count == 0)
if(draft == null)
{
errorMsg += ErrorOverlayCountIsNull + $" {nameof(draft.overlays)}.count is null\n";
throw new Exception("Draft cannot be null - there might have been some error while parsing the json of the component draft");
}
if (draft.overlays == null || draft.overlays.Count == 0)
{
errorMsg += ErrorOverlayCountIsNull + $" {nameof(draft.overlays)}.count is 0 - no overlays are defined\n";
}
if (draft.fileFormatVersion > ComponentDraftFileReader.CurrentFileVersion)
{
errorMsg += ErrorFileVersionNotSupported + $" {nameof(draft.fileFormatVersion)} is higher than what this software can handle. The max Version readable is {ComponentDraftFileReader.CurrentFileVersion}\n";
}
if (draft.pins.Count == 0)
if (draft.pins == null ||draft.pins.Count == 0)
{
errorMsg += ErrorNoPinsDefined + $" There are no {nameof(draft.pins)} defined at all. At least 1 pin should be defined\n";
}
Expand Down Expand Up @@ -86,24 +94,39 @@ public bool ResourceExists(string godotPath)
{
errorMsg += ErrorIdentifierNotSet + $" {nameof(draft.identifier)} has to be defined\n";
}
foreach (var overlay in draft.overlays)
if(draft?.overlays != null)
{
errorMsg += ValidateOverlay(overlay);
foreach (var overlay in draft.overlays)
{
errorMsg += ValidateOverlay(overlay);
}
}

errorMsg += ValidatePinNumbersAreUnique(draft.pins);
foreach (var pin in draft.pins)
if(draft?.pins != null)
{
errorMsg += ValidatePin(pin, draft.widthInTiles, draft.heightInTiles);
foreach (var pin in draft.pins)
{
errorMsg += ValidatePin(pin, draft.widthInTiles, draft.heightInTiles);
}
}
foreach (var connection in draft.connections)

if(draft?.sMatrices == null)
{
errorMsg += $"{ErrorMatrixNotDefinedForWaveLength} sMatrix is not defined for any WaveLength\n";
} else
{
errorMsg += ValidateConnection(draft.pins, connection);
foreach (var connection in draft.sMatrices)
{
errorMsg += ValidateConnection(draft.pins, draft.sMatrices);
}
}


bool success = true;
if (errorMsg.Length > 0)
{
errorMsg += $"in ComponentDraft {draft.GetType().Name}\n";
errorMsg += $"in ComponentDraft {draft.identifier}\n";
success = false;
}
return (success, errorMsg);
Expand Down Expand Up @@ -176,19 +199,38 @@ private static string ValidatePinNumbersAreUnique(List<PinDraft> pins)
return "";
}

private static string ValidateConnection(List<PinDraft> pins, Connection connection)
private static string ValidateConnection(List<PinDraft> pins, List<WaveLengthSpecificSMatrix> matrixDrafts)
{
string errorMsg = "";
// the pinIDs on the connections should exist
var allPinNumbers = pins.Select(p => p.number).ToHashSet();
if (!allPinNumbers.Contains(connection.fromPinNr))
// test if the SMatrices are defined for all given standard wavelengths
var definedWaveLengths = matrixDrafts.Select(m => m.waveLength).ToList();
// we use Reflection to get all properties as this class is used as an enum
foreach (PropertyInfo prop in typeof(StandardWaveLengths).GetProperties(BindingFlags.Public | BindingFlags.Static))
{
errorMsg += ErrorFromPinNrInvalid + $" The number '{nameof(Connection.fromPinNr)}' is not defined in the list of Pins\n";
int waveLength = (int)prop.GetValue(null);
if (!definedWaveLengths.Contains(waveLength))
{
errorMsg += ErrorMatrixNotDefinedForWaveLength + $" SMatrix is not defined for the standard-waveLength: '{waveLength} nanometer' \n";
}
}
if (!allPinNumbers.Contains(connection.toPinNr))

// test if all pins exist that are being used in the connections of the SMatrices
foreach(var matrix in matrixDrafts)
{
errorMsg += ErrorToPinNrInvalid + $"the number '{nameof(Connection.toPinNr)}' is not defined in the list of Pins\n";
foreach(var connection in matrix.connections)
{
var allPinNumbers = pins.Select(p => p.number).ToHashSet();
if (!allPinNumbers.Contains(connection.FromPinNr))
{
errorMsg += ErrorFromPinNrInvalid + $"The number '{nameof(Connection.FromPinNr)}' is not defined in the list of Pins\n";
}
if (!allPinNumbers.Contains(connection.ToPinNr))
{
errorMsg += ErrorToPinNrInvalid + $"The number '{nameof(Connection.ToPinNr)}' is not defined in the list of Pins\n";
}
}
}

return errorMsg;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using CAP_DataAccess.Helpers;
using Components.ComponentDraftMapper.DTOs;
using Components.ComponentDraftMapper;
using CAP_DataAccess.Components.ComponentDraftMapper.DTOs;
using CAP_DataAccess.Components.ComponentDraftMapper;
using CAP_Contracts;

namespace CAP_DataAccess.Components.ComponentDraftMapper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System.Text;
using System.Threading.Tasks;

namespace Components.ComponentDraftMapper.DTOs
namespace CAP_DataAccess.Components.ComponentDraftMapper.DTOs
{
public class ComponentDraft
{
Expand All @@ -16,7 +16,7 @@ public class ComponentDraft
public int widthInTiles { get; set; }
public int heightInTiles { get; set; }
public List<PinDraft> pins { get; set; }
public List<Connection> connections { get; set; }
public List<WaveLengthSpecificSMatrix> sMatrices { get; set; }
public List<Overlay> overlays { get; set; }
public string sceneResPath { get; set; }

Expand Down
42 changes: 37 additions & 5 deletions CAP-DataAccess/Components/ComponentDraftMapper/DTOs/Connection.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
namespace Components.ComponentDraftMapper.DTOs
using System.Numerics;
using System.Text.Json.Serialization;

namespace CAP_DataAccess.Components.ComponentDraftMapper.DTOs
{
public class Connection
{
public int fromPinNr { get; set; }
public int toPinNr { get; set; }
public float magnitude { get; set; }
public float wireLengthNM { get; set; }
[JsonPropertyName("fromPinNr")]
public int FromPinNr { get; set; }
[JsonPropertyName("toPinNr")]
public int ToPinNr { get; set; }
[JsonPropertyName("nonLinearFormula")]
public string? Formula { get; set; }
[JsonPropertyName("real")]
public double? Real { get; set; }
[JsonPropertyName("imaginary")]
public double? Imaginary { get; set; }
[JsonPropertyName("phase")]
public double? Phase { get; set; }
[JsonPropertyName("magnitude")]
public double? Magnitude { get; set; }
public Complex ToComplexNumber()
{
if (Real.HasValue && Imaginary.HasValue)
{
return new Complex(Real.Value, Imaginary.Value);
}
else if (Magnitude.HasValue && Phase.HasValue)
{
return Complex.FromPolarCoordinates(Magnitude.Value, Phase.Value);
}
else if (!string.IsNullOrWhiteSpace(Formula))
{
return 0;
}
else
{
throw new InvalidOperationException("Not enough data to create a complex number for the connection");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using CAP_Core.Tiles;

namespace Components.ComponentDraftMapper.DTOs
namespace CAP_DataAccess.Components.ComponentDraftMapper.DTOs
{
public class Overlay
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using CAP_Core.Components;
using CAP_Core.Tiles;

namespace Components.ComponentDraftMapper.DTOs
namespace CAP_DataAccess.Components.ComponentDraftMapper.DTOs
{
public class PinDraft
{
Expand Down
Loading

0 comments on commit 360a980

Please sign in to comment.