Added an Estimated Time Remaining label to 2 processes within the Create Genetic Models utility.
This commit is contained in:
parent
72d9c0a04e
commit
019b1a577e
4 changed files with 253 additions and 57 deletions
|
@ -6,6 +6,7 @@ Small and insignificant changes may not be included in this log.
|
|||
|
||||
## Unversioned Changes
|
||||
|
||||
* Added an Estimated Time Remaining label to 2 processes within the Create Genetic Models utility. - *Simon Sarasova*
|
||||
* Split the createGeneticAnalysis package into 2 packages: createPersonGeneticAnalysis and createCoupleGeneticAnalysis. - *Simon Sarasova*
|
||||
* Upgraded Circl to version 1.3.9. - *Simon Sarasova*
|
||||
* Renamed BroadcastTime/SentTime to CreationTime for every instance in which it is a better term to use. - *Simon Sarasova*
|
||||
|
|
|
@ -9,4 +9,4 @@ Many other people have written code for modules which are imported by Seekia. Th
|
|||
|
||||
Name | Date Of First Commit | Number Of Commits
|
||||
--- | --- | ---
|
||||
Simon Sarasova | June 13, 2023 | 256
|
||||
Simon Sarasova | June 13, 2023 | 257
|
|
@ -446,49 +446,52 @@ func GetContentTypeFromContentHash(contentHash []byte)(string, error){
|
|||
|
||||
hashLength := len(contentHash)
|
||||
|
||||
if (hashLength == 26){
|
||||
switch hashLength{
|
||||
|
||||
return "Message", nil
|
||||
case 26:{
|
||||
|
||||
} else if (hashLength == 27){
|
||||
|
||||
metadataByte := contentHash[26]
|
||||
|
||||
if (metadataByte >= 1 && metadataByte <= 6){
|
||||
|
||||
return "Attribute", nil
|
||||
return "Message", nil
|
||||
}
|
||||
case 27:{
|
||||
|
||||
} else if (hashLength == 28){
|
||||
metadataByte := contentHash[26]
|
||||
|
||||
metadataByte := contentHash[27]
|
||||
if (metadataByte >= 1 && metadataByte <= 6){
|
||||
|
||||
if (metadataByte >= 1 && metadataByte <= 6){
|
||||
|
||||
return "Profile", nil
|
||||
return "Attribute", nil
|
||||
}
|
||||
}
|
||||
case 28:{
|
||||
|
||||
} else if (hashLength == 29){
|
||||
metadataByte := contentHash[27]
|
||||
|
||||
metadataByte := contentHash[28]
|
||||
if (metadataByte >= 1 && metadataByte <= 6){
|
||||
|
||||
if (metadataByte >= 1 && metadataByte <= 4){
|
||||
|
||||
return "Review", nil
|
||||
return "Profile", nil
|
||||
}
|
||||
}
|
||||
case 29:{
|
||||
|
||||
} else if (hashLength == 30){
|
||||
metadataByte := contentHash[28]
|
||||
|
||||
metadataByte := contentHash[29]
|
||||
if (metadataByte >= 1 && metadataByte <= 4){
|
||||
|
||||
if (metadataByte >= 1 && metadataByte <= 4){
|
||||
|
||||
return "Report", nil
|
||||
return "Review", nil
|
||||
}
|
||||
}
|
||||
case 30:{
|
||||
|
||||
} else if (hashLength == 31){
|
||||
metadataByte := contentHash[29]
|
||||
|
||||
return "Parameters", nil
|
||||
if (metadataByte >= 1 && metadataByte <= 4){
|
||||
|
||||
return "Report", nil
|
||||
}
|
||||
}
|
||||
case 31:{
|
||||
|
||||
return "Parameters", nil
|
||||
}
|
||||
}
|
||||
|
||||
contentHashHex := encoding.EncodeBytesToHexString(contentHash)
|
||||
|
|
|
@ -39,7 +39,7 @@ import "sync"
|
|||
import "slices"
|
||||
import mathRand "math/rand/v2"
|
||||
import goFilepath "path/filepath"
|
||||
|
||||
import "time"
|
||||
|
||||
func main(){
|
||||
|
||||
|
@ -489,6 +489,7 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
dataArchiveFolderpath := string(fileContents)
|
||||
|
||||
progressDetailsBinding := binding.NewString()
|
||||
estimatedTimeRemainingBinding := binding.NewString()
|
||||
progressPercentageBinding := binding.NewFloat()
|
||||
|
||||
loadingBar := getWidgetCentered(widget.NewProgressBarWithData(progressPercentageBinding))
|
||||
|
@ -504,6 +505,15 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
|
||||
progressDetailsLabelCentered := getWidgetCentered(progressDetailsLabel)
|
||||
|
||||
estimatedTimeRemainingLabel := widget.NewLabelWithData(estimatedTimeRemainingBinding)
|
||||
estimatedTimeRemainingLabel.TextStyle = fyne.TextStyle{
|
||||
Bold: false,
|
||||
Italic: true,
|
||||
Monospace: false,
|
||||
}
|
||||
|
||||
estimatedTimeRemainingLabelCentered := getWidgetCentered(estimatedTimeRemainingLabel)
|
||||
|
||||
// We set this bool to true to stop the createData process
|
||||
var createDataIsStoppedBoolMutex sync.RWMutex
|
||||
createDataIsStoppedBool := false
|
||||
|
@ -517,12 +527,88 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
previousPage()
|
||||
}))
|
||||
|
||||
page := container.NewVBox(title, widget.NewSeparator(), loadingBar, progressDetailsTitle, progressDetailsLabelCentered, widget.NewSeparator(), cancelButton)
|
||||
page := container.NewVBox(title, widget.NewSeparator(), loadingBar, progressDetailsTitle, progressDetailsLabelCentered, estimatedTimeRemainingLabelCentered, widget.NewSeparator(), cancelButton)
|
||||
|
||||
window.SetContent(page)
|
||||
|
||||
createTrainingDataFunction := func(){
|
||||
|
||||
var processProgressMutex sync.RWMutex
|
||||
// This stores the progress of creating the training data (0-1)
|
||||
processProgress := float64(0)
|
||||
|
||||
startUpdateTimeRemainingDisplayFunction := func(){
|
||||
|
||||
// This function updates the estimated time remaining label binding
|
||||
|
||||
updateTimeRemainingDisplayFunction := func()error{
|
||||
|
||||
startTime := time.Now().Unix()
|
||||
|
||||
for{
|
||||
|
||||
createDataIsStoppedBoolMutex.RLock()
|
||||
createDataIsStopped := createDataIsStoppedBool
|
||||
createDataIsStoppedBoolMutex.RUnlock()
|
||||
|
||||
if (createDataIsStopped == true){
|
||||
// User exited the process/Process has completed
|
||||
return nil
|
||||
}
|
||||
|
||||
processProgressMutex.RLock()
|
||||
currentProcessProgress := processProgress
|
||||
processProgressMutex.RUnlock()
|
||||
|
||||
if (currentProcessProgress == 0){
|
||||
estimatedTimeRemainingBinding.Set("Calculating required time...")
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
// We calculate how long we think it will take for the process to complete
|
||||
|
||||
currentTime := time.Now().Unix()
|
||||
|
||||
secondsElapsed := currentTime - startTime
|
||||
|
||||
// processProgress is a float64 which stores the progress as a value between 0-1
|
||||
// To get the estimated total time the process will take, we divide the seconds elapsed by the proportion of progress
|
||||
// For example:
|
||||
// 0.1 (10%) at 10 seconds == Total process will take 100 seconds
|
||||
// 0.5 (50%) at 20 seconds == Total process will take 40 seconds
|
||||
|
||||
totalSeconds := float64(secondsElapsed)/currentProcessProgress
|
||||
|
||||
estimatedSecondsRemaining := int64(totalSeconds) - secondsElapsed
|
||||
|
||||
estimatedTimeRemainingTranslated, err := helpers.ConvertUnixTimeDurationToUnitsTimeTranslated(estimatedSecondsRemaining, false)
|
||||
if (err != nil) { return err }
|
||||
|
||||
estimatedTimeRemainingBinding.Set("Estimated Time Remaining: " + estimatedTimeRemainingTranslated)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
// This should never be reached
|
||||
|
||||
return errors.New("updateTimeRemainingDisplayFunction loop has broken.")
|
||||
}
|
||||
|
||||
err := updateTimeRemainingDisplayFunction()
|
||||
if (err != nil){
|
||||
|
||||
createDataIsStoppedBoolMutex.Lock()
|
||||
createDataIsStoppedBool = true
|
||||
createDataIsStoppedBoolMutex.Unlock()
|
||||
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
go startUpdateTimeRemainingDisplayFunction()
|
||||
|
||||
//Outputs:
|
||||
// -bool: Process completed (true == was not stopped mid-way)
|
||||
// -bool: Data archive is well formed
|
||||
|
@ -624,13 +710,23 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
}
|
||||
}
|
||||
|
||||
// We create folder to store training data
|
||||
// We create folder to store the training data
|
||||
|
||||
_, err = localFilesystem.CreateFolder("./TrainingData")
|
||||
if (err != nil) { return false, false, err }
|
||||
|
||||
_, err = localFilesystem.CreateFolder("./TrainingData/EyeColor")
|
||||
if (err != nil) { return false, false, err }
|
||||
//TODO: Add more traits
|
||||
traitNamesList := []string{"Eye Color"}
|
||||
|
||||
// We create the folders for each trait's training data
|
||||
|
||||
for _, traitName := range traitNamesList{
|
||||
|
||||
folderpath := goFilepath.Join("./TrainingData/", traitName)
|
||||
|
||||
_, err = localFilesystem.CreateFolder(folderpath)
|
||||
if (err != nil) { return false, false, err }
|
||||
}
|
||||
|
||||
numberOfUserPhenotypeDataObjects := len(userPhenotypesList_OpenSNP)
|
||||
maximumIndex := numberOfUserPhenotypeDataObjects-1
|
||||
|
@ -639,15 +735,6 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
|
||||
for index, userPhenotypeDataObject := range userPhenotypesList_OpenSNP{
|
||||
|
||||
trainingProgressPercentage, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 0, 100)
|
||||
if (err != nil) { return false, false, err }
|
||||
|
||||
trainingProgressFloat64 := float64(trainingProgressPercentage)/100
|
||||
|
||||
err = progressPercentageBinding.Set(trainingProgressFloat64)
|
||||
if (err != nil) { return false, false, err }
|
||||
|
||||
|
||||
createDataIsStoppedBoolMutex.RLock()
|
||||
createDataIsStopped := createDataIsStoppedBool
|
||||
createDataIsStoppedBoolMutex.RUnlock()
|
||||
|
@ -664,6 +751,18 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
err = progressDetailsBinding.Set(progressDetailsStatus)
|
||||
if (err != nil) { return false, false, err }
|
||||
|
||||
trainingProgressPercentage, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 0, 100)
|
||||
if (err != nil) { return false, false, err }
|
||||
|
||||
trainingProgressFloat64 := float64(trainingProgressPercentage)/100
|
||||
|
||||
err = progressPercentageBinding.Set(trainingProgressFloat64)
|
||||
if (err != nil) { return false, false, err }
|
||||
|
||||
processProgressMutex.Lock()
|
||||
processProgress = trainingProgressFloat64
|
||||
processProgressMutex.Unlock()
|
||||
|
||||
userID := userPhenotypeDataObject.UserID
|
||||
|
||||
userRawGenomeFilepathsList, exists := userRawGenomeFilepathsMap[userID]
|
||||
|
@ -727,7 +826,6 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
getUserLociValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
||||
|
||||
updatePercentageCompleteFunction := func(_ int)error{
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -766,9 +864,6 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
userLociValuesMap, err := getUserLociValuesMap()
|
||||
if (err != nil) { return false, false, err }
|
||||
|
||||
//TODO: Add more traits
|
||||
traitNamesList := []string{"Eye Color"}
|
||||
|
||||
for _, traitName := range traitNamesList{
|
||||
|
||||
traitNameWithoutWhitespace := strings.ReplaceAll(traitName, " ", "")
|
||||
|
@ -799,11 +894,19 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
}
|
||||
}
|
||||
|
||||
return true, false, nil
|
||||
createDataIsStoppedBoolMutex.Lock()
|
||||
createDataIsStoppedBool = true
|
||||
createDataIsStoppedBoolMutex.Unlock()
|
||||
|
||||
return true, true, nil
|
||||
}
|
||||
|
||||
processIsComplete, archiveIsCorrupt, err := createTrainingData()
|
||||
processIsComplete, archiveIsWellFormed, err := createTrainingData()
|
||||
if (err != nil){
|
||||
createDataIsStoppedBoolMutex.Lock()
|
||||
createDataIsStoppedBool = true
|
||||
createDataIsStoppedBoolMutex.Unlock()
|
||||
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
}
|
||||
|
@ -811,7 +914,7 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
|
|||
// User exited the page
|
||||
return
|
||||
}
|
||||
if (archiveIsCorrupt == true){
|
||||
if (archiveIsWellFormed == false){
|
||||
|
||||
title := getBoldLabelCentered("OpenSNP Archive Is Corrupt")
|
||||
|
||||
|
@ -881,6 +984,7 @@ func setStartAndMonitorTrainModelsPage(window fyne.Window, previousPage func()){
|
|||
//TODO: Verify TrainingData folder integrity
|
||||
|
||||
progressDetailsBinding := binding.NewString()
|
||||
estimatedTimeRemainingBinding := binding.NewString()
|
||||
progressPercentageBinding := binding.NewFloat()
|
||||
|
||||
loadingBar := getWidgetCentered(widget.NewProgressBarWithData(progressPercentageBinding))
|
||||
|
@ -896,6 +1000,15 @@ func setStartAndMonitorTrainModelsPage(window fyne.Window, previousPage func()){
|
|||
|
||||
progressDetailsLabelCentered := getWidgetCentered(progressDetailsLabel)
|
||||
|
||||
estimatedTimeRemainingLabel := widget.NewLabelWithData(estimatedTimeRemainingBinding)
|
||||
estimatedTimeRemainingLabel.TextStyle = fyne.TextStyle{
|
||||
Bold: false,
|
||||
Italic: true,
|
||||
Monospace: false,
|
||||
}
|
||||
|
||||
estimatedTimeRemainingLabelCentered := getWidgetCentered(estimatedTimeRemainingLabel)
|
||||
|
||||
// We set this bool to true to stop the trainModels process
|
||||
var trainModelsIsStoppedBoolMutex sync.RWMutex
|
||||
trainModelsIsStoppedBool := false
|
||||
|
@ -909,12 +1022,88 @@ func setStartAndMonitorTrainModelsPage(window fyne.Window, previousPage func()){
|
|||
previousPage()
|
||||
}))
|
||||
|
||||
page := container.NewVBox(title, widget.NewSeparator(), loadingBar, progressDetailsTitle, progressDetailsLabelCentered, widget.NewSeparator(), cancelButton)
|
||||
page := container.NewVBox(title, widget.NewSeparator(), loadingBar, progressDetailsTitle, progressDetailsLabelCentered, estimatedTimeRemainingLabelCentered, widget.NewSeparator(), cancelButton)
|
||||
|
||||
window.SetContent(page)
|
||||
|
||||
trainModelsFunction := func(){
|
||||
|
||||
var processProgressMutex sync.RWMutex
|
||||
// This stores the amount of progress which has been completed (0-1)
|
||||
processProgress := float64(0)
|
||||
|
||||
startUpdateTimeRemainingDisplayFunction := func(){
|
||||
|
||||
// This function updates the estimated time remaining label binding
|
||||
|
||||
updateTimeRemainingDisplayFunction := func()error{
|
||||
|
||||
startTime := time.Now().Unix()
|
||||
|
||||
for{
|
||||
|
||||
trainModelsIsStoppedBoolMutex.RLock()
|
||||
trainModelsIsStopped := trainModelsIsStoppedBool
|
||||
trainModelsIsStoppedBoolMutex.RUnlock()
|
||||
|
||||
if (trainModelsIsStopped == true){
|
||||
// User exited the process/Process has completed
|
||||
return nil
|
||||
}
|
||||
|
||||
processProgressMutex.RLock()
|
||||
currentProcessProgress := processProgress
|
||||
processProgressMutex.RUnlock()
|
||||
|
||||
if (currentProcessProgress == 0){
|
||||
estimatedTimeRemainingBinding.Set("Calculating required time...")
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
// We calculate how long we think it will take for the process to complete
|
||||
|
||||
currentTime := time.Now().Unix()
|
||||
|
||||
secondsElapsed := currentTime - startTime
|
||||
|
||||
// processProgress is a float64 which stores the progress as a value between 0-1
|
||||
// To get the estimated total time the process will take, we divide the seconds elapsed by the proportion of progress
|
||||
// For example:
|
||||
// 0.1 (10%) at 10 seconds == Total process will take 100 seconds
|
||||
// 0.5 (50%) at 20 seconds == Total process will take 40 seconds
|
||||
|
||||
totalSeconds := float64(secondsElapsed)/currentProcessProgress
|
||||
|
||||
estimatedSecondsRemaining := int64(totalSeconds) - secondsElapsed
|
||||
|
||||
estimatedTimeRemainingTranslated, err := helpers.ConvertUnixTimeDurationToUnitsTimeTranslated(estimatedSecondsRemaining, false)
|
||||
if (err != nil) { return err }
|
||||
|
||||
estimatedTimeRemainingBinding.Set("Estimated Time Remaining: " + estimatedTimeRemainingTranslated)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
// This should never be reached
|
||||
|
||||
return errors.New("updateTimeRemainingDisplayFunction loop has broken.")
|
||||
}
|
||||
|
||||
err := updateTimeRemainingDisplayFunction()
|
||||
if (err != nil){
|
||||
|
||||
trainModelsIsStoppedBoolMutex.Lock()
|
||||
trainModelsIsStoppedBool = true
|
||||
trainModelsIsStoppedBoolMutex.Unlock()
|
||||
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
go startUpdateTimeRemainingDisplayFunction()
|
||||
|
||||
//Outputs:
|
||||
// -bool: Process completed (true == was not stopped mid-way)
|
||||
// -error
|
||||
|
@ -967,12 +1156,13 @@ func setStartAndMonitorTrainModelsPage(window fyne.Window, previousPage func()){
|
|||
|
||||
progressDetailsBinding.Set(numberOfExamplesProgress)
|
||||
|
||||
percentageProgressInt, err := helpers.ScaleNumberProportionally(true, index, 0, finalIndex, 0, 100)
|
||||
if (err != nil) { return false, err }
|
||||
|
||||
newProgressFloat64 := float64(percentageProgressInt)/100
|
||||
newProgressFloat64 := float64(index)/float64(finalIndex)
|
||||
|
||||
progressPercentageBinding.Set(newProgressFloat64)
|
||||
|
||||
processProgressMutex.Lock()
|
||||
processProgress = newProgressFloat64
|
||||
processProgressMutex.Unlock()
|
||||
}
|
||||
|
||||
// Network training is complete.
|
||||
|
@ -996,6 +1186,11 @@ func setStartAndMonitorTrainModelsPage(window fyne.Window, previousPage func()){
|
|||
|
||||
processIsComplete, err := trainModels()
|
||||
if (err != nil){
|
||||
|
||||
trainModelsIsStoppedBoolMutex.Lock()
|
||||
trainModelsIsStoppedBool = true
|
||||
trainModelsIsStoppedBoolMutex.Unlock()
|
||||
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
}
|
||||
|
@ -1198,10 +1393,7 @@ func setStartAndMonitorTestModelsPage(window fyne.Window, previousPage func()){
|
|||
|
||||
progressDetailsBinding.Set(numberOfExamplesProgress)
|
||||
|
||||
percentageProgressInt, err := helpers.ScaleNumberProportionally(true, index, 0, finalIndex, 0, 100)
|
||||
if (err != nil) { return false, err }
|
||||
|
||||
newProgressFloat64 := float64(percentageProgressInt)/100
|
||||
newProgressFloat64 := float64(index)/float64(finalIndex)
|
||||
|
||||
progressPercentageBinding.Set(newProgressFloat64)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue