fix
This commit is contained in:
+213
-12
@@ -3,15 +3,16 @@ package control_case
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"control/analize"
|
||||
"github.com/che4web/go4rest"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gonum.org/v1/gonum/dsp/fourier"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -22,7 +23,7 @@ type ControlCaseController struct {
|
||||
|
||||
func NewControlCaseController(db *gorm.DB) *ControlCaseController {
|
||||
viewSet := go4rest.NewViewSet[ControlCase](db)
|
||||
viewSet.PreloadField = []string{"Params"}
|
||||
viewSet.PreloadField = []string{"Params", "Params.InitialCondition"}
|
||||
|
||||
return &ControlCaseController{
|
||||
ViewSet: viewSet,
|
||||
@@ -35,9 +36,24 @@ type ParamsController struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
type InitialConditionController struct {
|
||||
*go4rest.ViewSet[InitialCondition]
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewParamsController(db *gorm.DB) *ParamsController {
|
||||
viewSet := go4rest.NewViewSet[Params](db)
|
||||
viewSet.PreloadField = []string{"InitialCondition"}
|
||||
|
||||
return &ParamsController{
|
||||
ViewSet: go4rest.NewViewSet[Params](db),
|
||||
ViewSet: viewSet,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInitialConditionController(db *gorm.DB) *InitialConditionController {
|
||||
return &InitialConditionController{
|
||||
ViewSet: go4rest.NewViewSet[InitialCondition](db),
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
@@ -75,7 +91,7 @@ func (c *ControlCaseController) Launch(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.db.Preload("Params").First(&controlCase, controlCase.ID).Error; err != nil {
|
||||
if err := c.db.Preload("Params").Preload("Params.InitialCondition").First(&controlCase, controlCase.ID).Error; err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
@@ -88,6 +104,20 @@ type CSVSeriesResponse struct {
|
||||
Rows [][]interface{} `json:"rows"`
|
||||
}
|
||||
|
||||
type FFTPoint struct {
|
||||
Frequency float64 `json:"frequency"`
|
||||
Amplitude float64 `json:"amplitude"`
|
||||
}
|
||||
|
||||
type PSISpectrumResponse struct {
|
||||
TimeStep float64 `json:"time_step"`
|
||||
Points map[string][]FFTPoint `json:"points"`
|
||||
}
|
||||
|
||||
type InitialConditionResponse struct {
|
||||
InitialCondition InitialCondition `json:"initial_condition"`
|
||||
}
|
||||
|
||||
func (c *ControlCaseController) ChartData(ctx *gin.Context) {
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
@@ -101,7 +131,7 @@ func (c *ControlCaseController) ChartData(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
csvPath := filepath.Join(".", strconv.FormatUint(uint64(controlCase.ParamsID), 10), "foo.csv")
|
||||
csvPath := controlCase.FooCSVPath()
|
||||
file, err := os.Open(csvPath)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusNotFound, gin.H{"error": "csv file not found"})
|
||||
@@ -138,7 +168,7 @@ func (c *ControlCaseController) ChartData(ctx *gin.Context) {
|
||||
ctx.JSON(http.StatusOK, CSVSeriesResponse{Columns: columns, Rows: rows})
|
||||
}
|
||||
|
||||
func (c *ControlCaseController) RecalculateAnalysis(ctx *gin.Context) {
|
||||
func (c *ControlCaseController) PSISpectrum(ctx *gin.Context) {
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
|
||||
@@ -146,19 +176,160 @@ func (c *ControlCaseController) RecalculateAnalysis(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
var controlCase ControlCase
|
||||
if err := c.db.First(&controlCase, id).Error; err != nil {
|
||||
if err := c.db.Preload("Params").First(&controlCase, id).Error; err != nil {
|
||||
ctx.JSON(http.StatusNotFound, gin.H{"error": "record not found"})
|
||||
return
|
||||
}
|
||||
|
||||
csvPath := filepath.Join(".", strconv.FormatUint(uint64(controlCase.ParamsID), 10), "foo.csv")
|
||||
result, err := analize.AnalyzeCSV(c.db, controlCase.ID, controlCase.Name, csvPath)
|
||||
csvPath := controlCase.FooCSVPath()
|
||||
file, err := os.Open(csvPath)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusNotFound, gin.H{"error": "csv file not found"})
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
reader := csv.NewReader(file)
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if len(records) < 2 {
|
||||
ctx.JSON(http.StatusOK, PSISpectrumResponse{Points: map[string][]FFTPoint{}})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, result)
|
||||
headers := make(map[string]int, len(records[0]))
|
||||
for i, header := range records[0] {
|
||||
headers[strings.ToLower(strings.TrimSpace(header))] = i
|
||||
}
|
||||
|
||||
getIndex := func(name string) (int, error) {
|
||||
idx, ok := headers[strings.ToLower(name)]
|
||||
if !ok {
|
||||
return -1, fmt.Errorf("missing column %q", name)
|
||||
}
|
||||
return idx, nil
|
||||
}
|
||||
|
||||
tIndex, err := getIndex("t")
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
psiMIndex, err := getIndex("psi_m")
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
psiLIndex, err := getIndex("psi_l")
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
times := make([]float64, 0, len(records)-1)
|
||||
psiM := make([]float64, 0, len(records)-1)
|
||||
psiL := make([]float64, 0, len(records)-1)
|
||||
for _, record := range records[1:] {
|
||||
if len(record) <= maxInt(tIndex, psiMIndex, psiLIndex) {
|
||||
continue
|
||||
}
|
||||
|
||||
t, err := parseFloat(record[tIndex])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
m, err := parseFloat(record[psiMIndex])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
l, err := parseFloat(record[psiLIndex])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
times = append(times, t)
|
||||
psiM = append(psiM, m)
|
||||
psiL = append(psiL, l)
|
||||
}
|
||||
|
||||
timeStep := averageDelta(times)
|
||||
if timeStep <= 0 {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid time step"})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, PSISpectrumResponse{
|
||||
TimeStep: timeStep,
|
||||
Points: map[string][]FFTPoint{
|
||||
"psi_m": buildSpectrumPoints(psiM, timeStep),
|
||||
"psi_l": buildSpectrumPoints(psiL, timeStep),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func buildSpectrumPoints(values []float64, dt float64) []FFTPoint {
|
||||
if len(values) < 2 || dt <= 0 {
|
||||
return []FFTPoint{}
|
||||
}
|
||||
|
||||
centered := make([]float64, len(values))
|
||||
mean := 0.0
|
||||
for _, v := range values {
|
||||
mean += v
|
||||
}
|
||||
mean /= float64(len(values))
|
||||
for i, v := range values {
|
||||
centered[i] = v - mean
|
||||
}
|
||||
|
||||
fft := fourier.NewFFT(len(centered))
|
||||
coeffs := fft.Coefficients(nil, centered)
|
||||
limit := len(coeffs) / 2
|
||||
points := make([]FFTPoint, 0, limit+1)
|
||||
for i := 0; i <= limit; i++ {
|
||||
points = append(points, FFTPoint{
|
||||
Frequency: float64(i) / (float64(len(centered)) * dt),
|
||||
Amplitude: math.Hypot(real(coeffs[i]), imag(coeffs[i])) / float64(len(centered)),
|
||||
})
|
||||
}
|
||||
return points
|
||||
}
|
||||
|
||||
func parseFloat(value string) (float64, error) {
|
||||
return strconv.ParseFloat(strings.TrimSpace(value), 64)
|
||||
}
|
||||
|
||||
func maxInt(values ...int) int {
|
||||
max := 0
|
||||
for _, v := range values {
|
||||
if v > max {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
func averageDelta(times []float64) float64 {
|
||||
if len(times) < 2 {
|
||||
return 0
|
||||
}
|
||||
total := 0.0
|
||||
count := 0
|
||||
for i := 1; i < len(times); i++ {
|
||||
delta := times[i] - times[i-1]
|
||||
if delta <= 0 {
|
||||
continue
|
||||
}
|
||||
total += delta
|
||||
count++
|
||||
}
|
||||
if count == 0 {
|
||||
return 0
|
||||
}
|
||||
return total / float64(count)
|
||||
}
|
||||
|
||||
func (c *ControlCaseController) FieldMap(ctx *gin.Context) {
|
||||
@@ -180,8 +351,7 @@ func (c *ControlCaseController) FieldMap(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
h5Path := filepath.Join(".", strconv.FormatUint(uint64(controlCase.ParamsID), 10), "storage.h5")
|
||||
result, err := ReadNearestFieldMap(h5Path, timeValue)
|
||||
result, err := ReadNearestFieldMap(controlCase.StorageH5Path(), timeValue)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
@@ -189,3 +359,34 @@ func (c *ControlCaseController) FieldMap(ctx *gin.Context) {
|
||||
|
||||
ctx.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (c *ControlCaseController) CreateInitialCondition(ctx *gin.Context) {
|
||||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
|
||||
return
|
||||
}
|
||||
|
||||
var controlCase ControlCase
|
||||
if err := c.db.First(&controlCase, id).Error; err != nil {
|
||||
ctx.JSON(http.StatusNotFound, gin.H{"error": "record not found"})
|
||||
return
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(BASE_DIR, "initial_conditions", fmt.Sprintf("control_case_%d", controlCase.ID), "storage.h5")
|
||||
if err := controlCase.CreateStorageH5FromLastState(outputPath); err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
initialCondition := InitialCondition{
|
||||
Name: fmt.Sprintf("control-case-%d", controlCase.ID),
|
||||
FilePath: outputPath,
|
||||
}
|
||||
if err := c.db.Where("file_path = ?", outputPath).Assign(initialCondition).FirstOrCreate(&initialCondition).Error; err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, InitialConditionResponse{InitialCondition: initialCondition})
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package control_case
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -70,6 +72,68 @@ func ReadNearestFieldMap(filePath string, requestedT float64) (*FieldMapResponse
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func CopyLastStateStorageH5(sourcePath, outputPath string) error {
|
||||
if strings.TrimSpace(outputPath) == "" {
|
||||
return fmt.Errorf("output path is empty")
|
||||
}
|
||||
|
||||
sourceAbs, err := filepath.Abs(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
outputAbs, err := filepath.Abs(outputPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sourceAbs == outputAbs {
|
||||
return fmt.Errorf("output path must be different from source path")
|
||||
}
|
||||
|
||||
stageGroups, err := listStageGroups(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(stageGroups) == 0 {
|
||||
return fmt.Errorf("no stage_t groups found")
|
||||
}
|
||||
|
||||
latest := stageGroups[0]
|
||||
for _, stage := range stageGroups[1:] {
|
||||
if stage.stageT > latest.stageT {
|
||||
latest = stage
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(outputPath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpFile, err := os.CreateTemp(filepath.Dir(outputPath), ".storage-*.h5")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpPath := tmpFile.Name()
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
_ = os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
if err := os.Remove(tmpPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := runH5Copy(sourcePath, tmpPath, latest.path, "/map/stage_t=0", "-p"); err != nil {
|
||||
_ = os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Rename(tmpPath, outputPath); err != nil {
|
||||
_ = os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type stageFieldMap struct {
|
||||
path string
|
||||
stageT float64
|
||||
@@ -231,6 +295,17 @@ func runH5Dump(filePath string, args ...string) ([]byte, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func runH5Copy(sourceFile, outputFile, sourcePath, outputPath string, args ...string) error {
|
||||
cmdArgs := []string{"-i", sourceFile, "-o", outputFile, "-s", sourcePath, "-d", outputPath}
|
||||
cmdArgs = append(cmdArgs, args...)
|
||||
cmd := exec.Command("h5copy", cmdArgs...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("h5copy %v failed: %w: %s", cmdArgs, err, strings.TrimSpace(string(out)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func absFloat64(value float64) float64 {
|
||||
if value < 0 {
|
||||
return -value
|
||||
|
||||
+44
-17
@@ -21,20 +21,47 @@ type ControlCase struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (c ControlCase) FooCSVPath() string {
|
||||
paramsID := c.ParamsID
|
||||
if paramsID == 0 {
|
||||
paramsID = c.Params.ID
|
||||
}
|
||||
return filepath.Join(BASE_DIR, fmt.Sprintf("%d", paramsID), "foo.csv")
|
||||
}
|
||||
|
||||
func (c ControlCase) StorageH5Path() string {
|
||||
paramsID := c.ParamsID
|
||||
if paramsID == 0 {
|
||||
paramsID = c.Params.ID
|
||||
}
|
||||
return filepath.Join(BASE_DIR, fmt.Sprintf("%d", paramsID), "storage.h5")
|
||||
}
|
||||
|
||||
func (c ControlCase) CreateStorageH5FromLastState(outputPath string) error {
|
||||
return CopyLastStateStorageH5(c.StorageH5Path(), outputPath)
|
||||
}
|
||||
|
||||
type Params struct {
|
||||
ID uint `gorm:"primaryKey" json:"id" toml:"-" csv:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
|
||||
Rel float64 `json:"rel" toml:"rel" csv:"rel"`
|
||||
RelC float64 `json:"rel_c" toml:"rel_c" csv:"rel_c"`
|
||||
Le float64 `json:"le" toml:"le" csv:"le"`
|
||||
Pr float64 `json:"pr" toml:"pr" csv:"pr"`
|
||||
Pe float64 `json:"pe" toml:"pe" csv:"pe"`
|
||||
Ma float64 `json:"ma" toml:"ma" csv:"ma"`
|
||||
InitialCondition string `json:"initial_condition" toml:"-" csv:"initial_condition"`
|
||||
Time float64 `json:"time" toml:"time" csv:"time"`
|
||||
FolderPath string `json:"folder_path" toml:"-" csv:"-"`
|
||||
ID uint `gorm:"primaryKey" json:"id" toml:"-" csv:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
|
||||
Rel float64 `json:"rel" toml:"rel" csv:"rel"`
|
||||
RelC float64 `json:"rel_c" toml:"rel_c" csv:"rel_c"`
|
||||
Le float64 `json:"le" toml:"le" csv:"le"`
|
||||
Sc float64 `json:"sc" toml:"sc" csv:"sc"`
|
||||
Pe float64 `json:"pe" toml:"pe" csv:"pe"`
|
||||
Ma float64 `json:"ma" toml:"ma" csv:"ma"`
|
||||
InitialConditionID *uint `json:"initial_condition_id" toml:"-" csv:"initial_condition_id"`
|
||||
InitialCondition *InitialCondition `json:"initial_condition" toml:"-" csv:"-"`
|
||||
Time float64 `json:"time" toml:"time" csv:"time"`
|
||||
FolderPath string `json:"folder_path" toml:"-" csv:"-"`
|
||||
}
|
||||
|
||||
type InitialCondition struct {
|
||||
gorm.Model
|
||||
Name string `json:"name"`
|
||||
FilePath string `json:"file_path"`
|
||||
}
|
||||
|
||||
func (p *Params) ToTOML(filename string) error {
|
||||
@@ -49,12 +76,12 @@ func (p *Params) ToTOML(filename string) error {
|
||||
}
|
||||
|
||||
func (p *Params) Exist() (bool, error) {
|
||||
folderPath := filepath.Join("./", fmt.Sprintf("%d", p.ID))
|
||||
folderPath := filepath.Join(BASE_DIR, fmt.Sprintf("%d", p.ID))
|
||||
return exists(folderPath)
|
||||
}
|
||||
func (p *Params) CreateFolder() error {
|
||||
BIN_PATH := "./bio-convect"
|
||||
folderPath := filepath.Join("./", fmt.Sprintf("%d", p.ID))
|
||||
folderPath := filepath.Join(BASE_DIR, fmt.Sprintf("%d", p.ID))
|
||||
if err := os.MkdirAll(folderPath, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -67,9 +94,9 @@ func (p *Params) CreateFolder() error {
|
||||
if err := os.Chmod(execPath, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
if p.InitialCondition != "" && p.InitialCondition != "E" {
|
||||
if p.InitialCondition != nil && p.InitialCondition.FilePath != "" {
|
||||
startPath := filepath.Join("./", folderPath, "storage.h5")
|
||||
err = copy.Copy(p.InitialCondition, startPath)
|
||||
err = copy.Copy(p.InitialCondition.FilePath, startPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+32
-1
@@ -8,19 +8,50 @@ import (
|
||||
|
||||
func RegisterApp(r *gin.Engine, db *gorm.DB) {
|
||||
db.AutoMigrate(&ControlCase{})
|
||||
db.AutoMigrate(&InitialCondition{})
|
||||
db.AutoMigrate(&Params{})
|
||||
migrateParamsPrToSc(db)
|
||||
|
||||
controller := NewControlCaseController(db)
|
||||
params := NewParamsController(db)
|
||||
initialConditions := NewInitialConditionController(db)
|
||||
go4rest.RegisterCRUDRoutes(r, "control_case", controller)
|
||||
go4rest.RegisterCRUDRoutes(r, "params", params)
|
||||
go4rest.RegisterCRUDRoutes(r, "initial_condition", initialConditions)
|
||||
r.POST("/api/control_case/launch", controller.Launch)
|
||||
r.POST("/api/control_case/:id/recalculate-analysis", controller.RecalculateAnalysis)
|
||||
r.GET("/api/control_case/:id/chart-data", controller.ChartData)
|
||||
r.GET("/api/control_case/:id/psi-spectrum", controller.PSISpectrum)
|
||||
r.GET("/api/control_case/:id/field-map", controller.FieldMap)
|
||||
r.POST("/api/control_case/:id/initial-condition", controller.CreateInitialCondition)
|
||||
numJobs := 1
|
||||
//jobs := make(chan Params, numJobs)
|
||||
results := make(chan int, numJobs)
|
||||
go RunControllWorker(db, results)
|
||||
|
||||
}
|
||||
|
||||
func migrateParamsPrToSc(db *gorm.DB) {
|
||||
type columnInfo struct {
|
||||
Name string `gorm:"column:name"`
|
||||
}
|
||||
|
||||
var columns []columnInfo
|
||||
if err := db.Raw("PRAGMA table_info(params)").Scan(&columns).Error; err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hasPr := false
|
||||
hasSc := false
|
||||
for _, column := range columns {
|
||||
switch column.Name {
|
||||
case "pr":
|
||||
hasPr = true
|
||||
case "sc":
|
||||
hasSc = true
|
||||
}
|
||||
}
|
||||
|
||||
if hasPr && hasSc {
|
||||
db.Exec("UPDATE params SET sc = pr WHERE sc IS NULL OR sc = 0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"control/analize"
|
||||
"github.com/gocarina/gocsv"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -26,11 +25,13 @@ func exists(path string) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
const BASE_DIR = "./data"
|
||||
|
||||
func worker(id int, jobs <-chan ControlCase, ctx context.Context, db *gorm.DB) {
|
||||
for j := range jobs {
|
||||
fmt.Printf("Worker %d started job %d \n", id, j.ID)
|
||||
p := j.Params
|
||||
p.FolderPath = filepath.Join(".", fmt.Sprintf("%d", p.ID))
|
||||
p.FolderPath = filepath.Join(BASE_DIR, fmt.Sprintf("%d", p.ID))
|
||||
|
||||
exists, err := p.Exist()
|
||||
if err != nil {
|
||||
@@ -49,12 +50,6 @@ func worker(id int, jobs <-chan ControlCase, ctx context.Context, db *gorm.DB) {
|
||||
}
|
||||
}
|
||||
|
||||
csvPath := filepath.Join(p.FolderPath, "foo.csv")
|
||||
if _, err := analize.AnalyzeCSV(db, j.ID, j.Name, csvPath); err != nil {
|
||||
fmt.Printf("Worker %d failed to analyze job %d: %v\n", id, j.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
j.Status = "R"
|
||||
if err := db.Model(&ControlCase{}).Where("id = ?", j.ID).Update("status", j.Status).Error; err != nil {
|
||||
fmt.Printf("Worker %d failed to update status for job %d: %v\n", id, j.ID, err)
|
||||
@@ -92,6 +87,7 @@ func readFromDb(db *gorm.DB) []ControlCase {
|
||||
_ = db.
|
||||
Where("status IN ?", statuses).
|
||||
Preload("Params").
|
||||
Preload("Params.InitialCondition").
|
||||
Find(&cases).Error
|
||||
return cases
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user