Skip to content

Commit

Permalink
feature: #1294: Added ability to process MV4 homework
Browse files Browse the repository at this point in the history
---

docs: #1294: Added homework instructions and updated debug client models changelog.

chore: #1294: Updated SQL queries.

refactor: #1294: Yield Genotype matcher response as enumerable prevent memory exceptions.

refactor: #1294: Use IEnumerable when bulk inserting to reduce memory usage.

chore: #1294: Add SQL to select out

chore: #1294: Store matching genotypes

refactor: #1294: Move match prediction debug models to debug client models namespace.

chore: #1294: Add HLA version to homework set.

chore: #1294: SQL for selecting out homework subjects with missing HLA.

chore: #1294: Process all sets imported found in a directory.

chore: #1294: Import pdps directly from file.

chore: #1294: Detect subjects with missing HLA.

chore: #1294: Add functions to submit MV4 homework request.

chore: #1294: Add genotype count to debug model, genotype matcher response.
  • Loading branch information
zabeen committed May 6, 2024
1 parent e816fc8 commit eb64991
Show file tree
Hide file tree
Showing 98 changed files with 8,314 additions and 153 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;

namespace Atlas.MatchPrediction.ExternalInterface.Models.HaplotypeFrequencySet
namespace Atlas.Common.Public.Models.MatchPrediction
{
/// <summary>
/// This is the data used to determine which frequency set to use, for both Donors and Patients.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using Atlas.Common.Public.Models.GeneticData;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Atlas.MatchPrediction.Models
namespace Atlas.Common.Public.Models.MatchPrediction
{
/// <summary>
/// Parameters controlling Match Prediction behaviour (in addition to <see cref="SubjectData"/>)
Expand Down Expand Up @@ -33,4 +32,4 @@ public MatchPredictionParameters(ISet<Locus> allowedLoci, string matchingAlgorit
MatchingAlgorithmHlaNomenclatureVersion = matchingAlgorithmHlaNomenclatureVersion;
}
}
}
}
10 changes: 7 additions & 3 deletions Atlas.Common/Sql/BulkInsert/BulkInsertRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Atlas.Common.Utils.Extensions;
using Microsoft.Data.SqlClient;

namespace Atlas.Common.Sql.BulkInsert
Expand All @@ -13,7 +14,7 @@ public interface IBulkInsertRepository<in TEntity> where TEntity : IBulkInsertMo
/// <summary>
/// Note, `Id` and properties annotated with <see cref="BulkInsertIgnoreAttribute"/> will not be included in the bulk insert.
/// </summary>
Task BulkInsert(IReadOnlyCollection<TEntity> entities);
Task BulkInsert(IEnumerable<TEntity> entities);
}

public abstract class BulkInsertRepository<TEntity> : IBulkInsertRepository<TEntity> where TEntity : IBulkInsertModel
Expand All @@ -29,14 +30,17 @@ protected BulkInsertRepository(string connectionString, string bulkInsertTableNa
this.bulkInsertTableName = bulkInsertTableName;
}

public async Task BulkInsert(IReadOnlyCollection<TEntity> entities)
public async Task BulkInsert(IEnumerable<TEntity> entities)
{
if (!entities.Any())
// ReSharper disable once PossibleMultipleEnumeration - `IsNullOrEmpty` does not enumerate the collection
if (entities.IsNullOrEmpty())
{
return;
}

var columnNames = GetColumnNames();

// ReSharper disable once PossibleMultipleEnumeration
var dataTable = BuildDataTable(entities, columnNames);

using (var sqlBulk = BuildSqlBulkCopy(columnNames))
Expand Down
6 changes: 6 additions & 0 deletions Atlas.Debug.Client.Models/CHANGELOG_DebugClientModels.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ This package contains client models utilised by the Atlas debug endpoints.
## Changelog
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### 2.2.0
* Created new namespace `Atlas.Debug.Client.Models.MatchPrediction` and moved various models related to debugging match prediction here.
* Extended existing model, `GenotypeImputationResponse`, with new prop, `GenotypeCount`.
* Changed type of prop `MatchedGenotypePairs` on existing model `GenotypeMatcherResponse` from `string` to `IEnumerable<string>`.
* Instead of one, potentially very long, formatted string, the matched genotype pairs are now returned as a collection of formatted strings, one for each matching patient-donor genotype pair.

### 2.1.0
* Creation of new library, `Atlas.Debug.Client.Models`, that contains models used in debug endpoints.
* Moved following models to new project:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using Atlas.MatchPrediction.Models;
using Atlas.Common.Public.Models.MatchPrediction;

namespace Atlas.MatchPrediction.Functions.Models.Debug
namespace Atlas.Debug.Client.Models.MatchPrediction
{
public class GenotypeImputationRequest
{
public SubjectInfo SubjectInfo { get; set; }

/// <summary>
/// <inheritdoc cref="MatchPrediction.Models.MatchPredictionParameters"/>
/// <inheritdoc cref="Common.Public.Models.MatchPrediction.MatchPredictionParameters"/>
/// </summary>
public MatchPredictionParameters MatchPredictionParameters { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Atlas.MatchPrediction.ExternalInterface.Models.HaplotypeFrequencySet;
using Atlas.MatchPrediction.Models;
using Atlas.Client.Models.Search.Results.MatchPrediction;
using Atlas.Common.Public.Models.MatchPrediction;

namespace Atlas.MatchPrediction.Functions.Models.Debug
namespace Atlas.Debug.Client.Models.MatchPrediction
{
public class GenotypeImputationResponse
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using Atlas.MatchPrediction.Models;
using Atlas.Common.Public.Models.MatchPrediction;

namespace Atlas.MatchPrediction.Functions.Models.Debug
namespace Atlas.Debug.Client.Models.MatchPrediction
{
public class GenotypeMatcherRequest
{
/// <summary>
/// <inheritdoc cref="MatchPrediction.Models.MatchPredictionParameters"/>
/// <inheritdoc cref="Common.Public.Models.MatchPrediction.MatchPredictionParameters"/>
/// </summary>
public MatchPredictionParameters MatchPredictionParameters { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using Atlas.MatchPrediction.ExternalInterface.Models.HaplotypeFrequencySet;
using Atlas.MatchPrediction.Models;
using System.Collections.Generic;
using Atlas.Client.Models.Search.Results.MatchPrediction;
using Atlas.Common.Public.Models.MatchPrediction;

namespace Atlas.MatchPrediction.Functions.Models.Debug
namespace Atlas.Debug.Client.Models.MatchPrediction
{
public class GenotypeMatcherResponse
{
Expand All @@ -10,25 +11,28 @@ public class GenotypeMatcherResponse
public SubjectResult DonorInfo { get; set; }

/// <summary>
/// Patient-donor genotype pairs (represented as a single, formatted string) and their match counts.
/// Patient-donor genotype pairs and their match counts.
/// </summary>
public string MatchedGenotypePairs { get; set; }
public IEnumerable<string> MatchedGenotypePairs { get; set; }
}

public class SubjectResult
{
public bool IsUnrepresented { get; set; }
public int GenotypeCount { get; set; }
public decimal SumOfLikelihoods { get; set; }
public HaplotypeFrequencySet HaplotypeFrequencySet { get; set; }
public string HlaTyping { get; set; }

public SubjectResult(
bool isUnrepresented,
int genotypeCount,
decimal sumOfLikelihoods,
HaplotypeFrequencySet haplotypeFrequencySet,
string hlaTyping)
{
IsUnrepresented = isUnrepresented;
GenotypeCount = genotypeCount;
SumOfLikelihoods = sumOfLikelihoods;
HaplotypeFrequencySet = haplotypeFrequencySet;
HlaTyping = hlaTyping;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Atlas.Common.Public.Models.GeneticData.PhenotypeInfo.TransferModels;
using Atlas.MatchPrediction.ExternalInterface.Models.HaplotypeFrequencySet;
using Atlas.Common.Public.Models.MatchPrediction;

namespace Atlas.MatchPrediction.Functions.Models.Debug
namespace Atlas.Debug.Client.Models.MatchPrediction
{
public class SubjectInfo
{
Expand Down
2 changes: 1 addition & 1 deletion Atlas.Functions/Services/MatchPredictionInputBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
using Atlas.Common.ApplicationInsights.Timing;
using Atlas.Common.Public.Models.GeneticData;
using Atlas.Common.Public.Models.GeneticData.PhenotypeInfo.TransferModels;
using Atlas.Common.Public.Models.MatchPrediction;
using Atlas.Functions.Settings;
using Atlas.MatchPrediction.ExternalInterface;
using Atlas.MatchPrediction.ExternalInterface.Models.HaplotypeFrequencySet;
using Atlas.MatchPrediction.ExternalInterface.Models.MatchProbability;
using EnumStringValues;
using Microsoft.Extensions.Options;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
public interface IProcessedResultsRepository<in TDbModel>
{
Task DeleteResults(int searchRequestRecordId);
Task BulkInsert(IReadOnlyCollection<TDbModel> results);
Task BulkInsert(IEnumerable<TDbModel> results);
}
}
8 changes: 6 additions & 2 deletions Atlas.ManualTesting.Common/Services/FileReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ namespace Atlas.ManualTesting.Common.Services
{
public interface IFileReader<T>
{
Task<IReadOnlyCollection<T>> ReadAllLines(string delimiter, string filePath);
Task<IReadOnlyCollection<T>> ReadAllLines(string delimiter, string filePath, bool hasHeaderRecord = true);
IAsyncEnumerable<T> ReadAsync(string delimiter, string filePath);
}

public class FileReader<T> : IFileReader<T>
{
public async Task<IReadOnlyCollection<T>> ReadAllLines(string delimiter, string filePath)
public async Task<IReadOnlyCollection<T>> ReadAllLines(
string delimiter,
string filePath,
bool hasHeaderRecord = true)
{
FileChecks(filePath);

Expand All @@ -19,6 +22,7 @@ public async Task<IReadOnlyCollection<T>> ReadAllLines(string delimiter, string
using var csv = new CsvReader(reader);

csv.Configuration.Delimiter = delimiter;
csv.Configuration.HasHeaderRecord = hasHeaderRecord;
csv.Configuration.HeaderValidated = null;
csv.Configuration.MissingFieldFound = null;
csv.Configuration.TypeConverterOptionsCache.GetOptions<string>().NullValues.Add("");
Expand Down
56 changes: 56 additions & 0 deletions Atlas.ManualTesting.Common/Services/HttpRequester.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Newtonsoft.Json;
using Polly;

namespace Atlas.ManualTesting.Common.Services
{
public class AtlasHttpResult<TResult>
{
public bool WasSuccess => Result != null;
public TResult? Result { get; set; }

public AtlasHttpResult(TResult? result)
{
Result = result;
}
}

public abstract class AtlasHttpRequester
{
private readonly HttpClient httpRequestClient;
private readonly string requestUrl;

protected AtlasHttpRequester(HttpClient httpRequestClient, string requestUrl)
{
this.httpRequestClient = httpRequestClient;
this.requestUrl = requestUrl;
}

protected async Task<AtlasHttpResult<TResult>> PostRequest<TRequest, TResult>(TRequest request)
{
var retryPolicy = Policy.Handle<Exception>().RetryAsync(10);

var requestResponse = await retryPolicy.ExecuteAndCaptureAsync(
async () => await SendRequest<TRequest, TResult>(request));

return new AtlasHttpResult<TResult>(requestResponse.Result);
}

private async Task<TResult?> SendRequest<TRequest, TResult>(TRequest request)
{
try
{
var response = await httpRequestClient.PostAsync(
requestUrl, new StringContent(JsonConvert.SerializeObject(request)));
response.EnsureSuccessStatusCode();

return JsonConvert.DeserializeObject<TResult>(await response.Content.ReadAsStringAsync());
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Failed to send request {request}. Details: {ex.Message} " +
"Re-attempting until success or re-attempt count reached.");
throw;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System.IO;
using System.Threading.Tasks;
using Atlas.Common.Public.Models.GeneticData.PhenotypeInfo.TransferModels;
using Atlas.Common.Public.Models.MatchPrediction;
using Atlas.Common.Utils.Http;
using Atlas.MatchPrediction.ExternalInterface.Models.HaplotypeFrequencySet;
using Atlas.MatchPrediction.Functions.Models.Debug;
using Atlas.Debug.Client.Models.MatchPrediction;
using Atlas.MatchPrediction.Functions.Services.Debug;
using Atlas.MatchPrediction.Models;
using Atlas.MatchPrediction.Services.HaplotypeFrequencies;
Expand All @@ -13,7 +13,6 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using MoreLinq;
using Newtonsoft.Json;

namespace Atlas.MatchPrediction.Functions.Functions.Debug
Expand Down Expand Up @@ -52,7 +51,7 @@ public class GenotypeImputationFunctions
{
HlaTyping = input.SubjectInfo.HlaTyping.ToPhenotypeInfo().PrettyPrint(),
MatchPredictionParameters = input.MatchPredictionParameters,
HaplotypeFrequencySet = frequencySet,
HaplotypeFrequencySet = frequencySet.ToClientHaplotypeFrequencySet(),
GenotypeCount = imputedGenotypes.GenotypeLikelihoods.Count,
SumOfLikelihoods = imputedGenotypes.SumOfLikelihoods,
GenotypeLikelihoods = imputedGenotypes.GenotypeLikelihoods.ToSingleDelimitedString()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.IO;
using System.Threading.Tasks;
using Atlas.Common.Public.Models.MatchPrediction;
using Atlas.Common.Utils.Http;
using Atlas.MatchPrediction.ExternalInterface.Models.HaplotypeFrequencySet;
using Atlas.MatchPrediction.ExternalInterface.Models.MatchPredictionSteps.GenotypeLikelihood;
using Atlas.MatchPrediction.Services.GenotypeLikelihood;
using Atlas.MatchPrediction.Services.HaplotypeFrequencies;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
using System.Threading.Tasks;
using Atlas.Common.Public.Models.GeneticData.PhenotypeInfo.TransferModels;
using Atlas.Common.Utils.Http;
using Atlas.Debug.Client.Models.MatchPrediction;
using Atlas.MatchPrediction.ExternalInterface.Models.HaplotypeFrequencySet;
using Atlas.MatchPrediction.Functions.Models.Debug;
using Atlas.MatchPrediction.Functions.Services.Debug;
using Atlas.MatchPrediction.Models;
using Atlas.MatchPrediction.Services.HaplotypeFrequencies;
Expand Down Expand Up @@ -49,15 +49,15 @@ public class MatchCalculationFunctions
MatchPredictionParameters = input.MatchPredictionParameters
});

var response = new GenotypeMatcherResponse
var matcherResponse = new GenotypeMatcherResponse
{
MatchPredictionParameters = input.MatchPredictionParameters,
PatientInfo = BuildSubjectResult(result.PatientResult, frequencySet.PatientSet, input.Patient),
DonorInfo = BuildSubjectResult(result.DonorResult, frequencySet.DonorSet, input.Donor),
MatchedGenotypePairs = result.GenotypeMatchDetails.ToSingleDelimitedString()
MatchedGenotypePairs = result.GenotypeMatchDetails.ToFormattedStrings(),
};

return new JsonResult(response);
return new JsonResult(matcherResponse);
}

private static SubjectResult BuildSubjectResult(
Expand All @@ -67,8 +67,9 @@ public class MatchCalculationFunctions
{
return new SubjectResult(
subjectResult.IsUnrepresented,
subjectResult.GenotypeCount,
subjectResult.SumOfLikelihoods,
set,
set.ToClientHaplotypeFrequencySet(),
subjectInfo.HlaTyping.ToPhenotypeInfo().PrettyPrint());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Threading.Tasks;
using Atlas.Common.AzureEventGrid;
using Atlas.Common.Public.Models.MatchPrediction;
using Atlas.MatchPrediction.ExternalInterface;
using Atlas.MatchPrediction.ExternalInterface.Models.HaplotypeFrequencySet;
using Atlas.MatchPrediction.Models;
Expand Down
Loading

0 comments on commit eb64991

Please sign in to comment.