public ProteinAlignerResult( LinearTransformation3D transformation, UnitValue averagePositionError, bool isTransformationValid) { Transformation = transformation; AveragePositionError = averagePositionError; IsTransformationValid = isTransformationValid; }
private ProteinAlignerResult AlignUsingPositionPairs(List <Point3D> sequence1, List <Point3D> sequence2) { var validIndices = sequence1 .PairwiseOperation(sequence2, (p1, p2) => p1 != null && p2 != null) .Select((isValid, idx) => new { IsValid = isValid, Index = idx }) .Where(x => x.IsValid) .Select(x => x.Index) .ToList(); if (validIndices.Count < 2) { throw new ArgumentException("Too little position information (too many null-points) for alignment of sequences"); } var sequence2PositionArray = new double[validIndices.Count, 4]; for (int validIdx = 0; validIdx < validIndices.Count; validIdx++) { var idx = validIndices[validIdx]; sequence2PositionArray[validIdx, 0] = 1; sequence2PositionArray[validIdx, 1] = sequence2[idx].X; sequence2PositionArray[validIdx, 2] = sequence2[idx].Y; sequence2PositionArray[validIdx, 3] = sequence2[idx].Z; } var sequence1X = validIndices.Select(idx => sequence1[idx].X).ToArray(); var sequence1Y = validIndices.Select(idx => sequence1[idx].Y).ToArray(); var sequence1Z = validIndices.Select(idx => sequence1[idx].Z).ToArray(); var betaX = LinearRegression(sequence2PositionArray, sequence1X); var betaY = LinearRegression(sequence2PositionArray, sequence1Y); var betaZ = LinearRegression(sequence2PositionArray, sequence1Z); var rotationMatrix = new Matrix3X3(); rotationMatrix.Set(new[, ] { { betaX[1], betaX[2], betaX[3] }, { betaY[1], betaY[2], betaY[3] }, { betaZ[1], betaZ[2], betaZ[3] } }); var transformation = new LinearTransformation3D( new Vector3D(betaX[0], betaY[0], betaZ[0]), rotationMatrix); var averagePositionError = validIndices .Select(idx => sequence1[idx].DistanceTo(transformation.Apply(sequence2[idx]))) .Average() .To(SIPrefix.Pico, Unit.Meter); var isRotationMatrixValid = (rotationMatrix[0, 0].Square() + rotationMatrix[1, 0].Square() + rotationMatrix[2, 0].Square()).IsBetween(0.9, 1.1) && (rotationMatrix[0, 1].Square() + rotationMatrix[1, 1].Square() + rotationMatrix[2, 1].Square()).IsBetween(0.9, 1.1) && (rotationMatrix[0, 2].Square() + rotationMatrix[1, 2].Square() + rotationMatrix[2, 2].Square()).IsBetween(0.9, 1.1); return(new ProteinAlignerResult(transformation, averagePositionError, isRotationMatrixValid)); }