// checkCheckPoint tests that a checkpoint happened at the requested delay // in seconds (+/- margin) func checkCheckPoint(testDir string, c *jsonParser.TestCase) error { path := file.GetOutputDir(testDir) stamp := filepath.Join(path, c.BaseName+".stamp") stampi, err := os.Stat(stamp) if err != nil { return fmt.Errorf("Failed to stat file %s", stamp) } stampTime := stampi.ModTime() checkpt := filepath.Join(path, c.BaseName+".cp") checkpti, err := os.Stat(checkpt) if err != nil { return fmt.Errorf("Failed to stat file %s", checkpt) } checkTime := checkpti.ModTime() if checkTime.Sub(stampTime).Seconds() < c.Delay-c.Margin { return fmt.Errorf("Realtime checkpoint scheduled for %f seconds but "+ "time between timestamp and checkpoint is less than %f seconds", c.Delay, c.Delay-c.Margin) } if checkTime.Sub(stampTime).Seconds() > c.Delay+c.Margin { return fmt.Errorf("Realtime checkpoint scheduled for %f seconds but "+ "time between timestamp and checkpoint exceeds %f seconds", c.Delay, c.Delay+c.Margin) } return nil }
// createSimJobs is responsible for filling a worker queue with // jobs to be run via the simulation tool. It parses the test // description, assembles a TestDescription struct and adds it // to the simulation job queue. func createSimJobs(includePath string, testPaths []string, simJobs chan *jsonParser.TestDescription) { runID := 0 for _, testDir := range testPaths { testFile := filepath.Join(testDir, "test_description.json") testDescription, err := jsonParser.Parse(testFile, includePath) if err != nil { log.Printf("Error parsing test description in %s: %v", testDir, err) continue } // create output directory outputDir := file.GetOutputDir(testDir) if err := os.Mkdir(outputDir, 0744); err != nil { log.Print(err) continue } // set path and pick a Seed value for run testDescription.Path = testDir testDescription.Run.RunID = runID // schedule requested number of Seeds; if there is just a single // Seed requested we pick one randomly switch testDescription.Run.NumSeeds { case 0: // user didn't set number of Seeds -- assume single Seed testDescription.Run.NumSeeds = 1 testDescription.Run.Seed = rng.Intn(10000) case 1: testDescription.Run.Seed = rng.Intn(10000) default: for i := 1; i < testDescription.Run.NumSeeds; i++ { newTest := testDescription.Copy() newTest.Run.Seed = i testDescription.Run.Seed = i + 1 simJobs <- newTest } } simJobs <- testDescription runID++ } close(simJobs) }
// checkDREAMMV3MolsBin checks the layout for molecule viz data as part of the // binary DREAMM v3 format func checkDREAMMV3MolsBin(testDir string, c *jsonParser.TestCase) error { s, err := misc.CreateMolMeshIters(c.AllIters, c.SurfPosIters, c.SurfOrientIters, c.SurfStateIters) if err != nil { return err } v, err := misc.CreateMolMeshIters(c.AllIters, c.VolPosIters, c.VolOrientIters, c.VolStateIters) if err != nil { return err } molIters := s.AllCombined.Clone().Union(v.AllCombined) dataPath := filepath.Join(file.GetOutputDir(testDir), c.VizPath) lastSurfPos := -1 lastSurfOrient := -1 lastSurfState := -1 lastVolPos := -1 lastVolOrient := -1 lastVolState := -1 for _, i := range s.All { iterPath := filepath.Join(dataPath, "frame_data", "iteration_%d") hadFrame := false // surface positions surfPosFile := filepath.Join(iterPath, "surface_molecules_positions.bin") if err := misc.CheckDREAMMV3IterItems(s.Pos, molIters, i, lastSurfPos, c.SurfEmpty, surfPosFile); err != nil { return err } if s.Pos.Contains(i) { lastSurfPos = i hadFrame = true } // surface orientations surfOrientFile := filepath.Join(iterPath, "surface_molecules_orientations.bin") if err := misc.CheckDREAMMV3IterItems(s.Others, molIters, i, lastSurfOrient, c.SurfEmpty, surfOrientFile); err != nil { return err } if s.Others.Contains(i) { lastSurfOrient = i hadFrame = true } // surface states surfStateFile := filepath.Join(iterPath, "surface_molecules_states.bin") if err := misc.CheckDREAMMV3IterItems(s.States, molIters, i, lastSurfState, c.SurfEmpty, surfStateFile); err != nil { return err } if s.States.Contains(i) { lastSurfState = i hadFrame = true } surfTemplate := filepath.Join(iterPath, "surface_molecules.dx") if err := misc.CheckDREAMMV3DXItems(i, lastSurfPos, lastSurfOrient, lastSurfState, hadFrame, surfTemplate); err != nil { return err } // volume positions hadFrame = false volPosFile := filepath.Join(iterPath, "volume_molecules_positions.bin") if err := misc.CheckDREAMMV3IterItems(v.Pos, molIters, i, lastVolPos, c.VolEmpty, volPosFile); err != nil { return err } if v.Pos.Contains(i) { lastVolPos = i hadFrame = true } // volume orientations volOrientFile := filepath.Join(iterPath, "volume_molecules_orientations.bin") if err := misc.CheckDREAMMV3IterItems(v.Others, molIters, i, lastVolOrient, c.VolEmpty, volOrientFile); err != nil { return err } if v.Others.Contains(i) { lastVolOrient = i hadFrame = true } // volume states volStateFile := filepath.Join(iterPath, "volume_molecules_states.bin") if err := misc.CheckDREAMMV3IterItems(v.States, molIters, i, lastVolState, c.SurfEmpty, volStateFile); err != nil { return err } if v.States.Contains(i) { lastVolState = i hadFrame = true } volTemplate := filepath.Join(iterPath, "volume_molecules.dx") if err := misc.CheckDREAMMV3DXItems(i, lastVolPos, lastVolOrient, lastVolState, hadFrame, volTemplate); err != nil { return err } } return nil }
// checkDREAMMV3Grouped checks the layout for DREAMM V3 grouped format func checkDREAMMV3Grouped(testDir, dataDir string, numIters, numTimes int, haveMeshPos, haveRgnIdx, haveMeshState, noMeshes, haveMolPos, haveMolOrient, haveMolState, noMols bool) error { dataPath := filepath.Join(file.GetOutputDir(testDir), dataDir) // meshes meshPath := dataPath + ".mesh_positions.1.bin" if err := misc.CheckDREAMMV3GroupedItem(meshPath, haveMeshPos, noMeshes); err != nil { return err } regionPath := dataPath + ".region_indices.1.bin" if err := misc.CheckDREAMMV3GroupedItem(regionPath, haveRgnIdx, noMeshes); err != nil { return err } meshStatesPath := dataPath + ".mesh_states.1.bin" if err := misc.CheckDREAMMV3GroupedItem(meshStatesPath, haveMeshState, noMeshes); err != nil { return err } // molecules molPath := dataPath + ".molecule_positions.1.bin" if err := misc.CheckDREAMMV3GroupedItem(molPath, haveMolPos, noMols); err != nil { return err } orientPath := dataPath + ".molecule_orientations.1.bin" if err := misc.CheckDREAMMV3GroupedItem(orientPath, haveMolOrient, noMols); err != nil { return err } molStatesPath := dataPath + ".molecule_states.1.bin" if err := misc.CheckDREAMMV3GroupedItem(molStatesPath, haveMolState, noMols); err != nil { return err } // iterations iterPath := dataPath + ".iteration_numbers.1.bin" if numIters != 0 { ok, err := file.HasSize(iterPath, int64(numIters*12)) if err != nil { return err } if !ok { return fmt.Errorf("file %s has incorrect file size", iterPath) } } else { ok, err := file.IsNonEmpty(iterPath) if err != nil { return err } if !ok { return fmt.Errorf("file %s is not non-empty", iterPath) } } // times timePath := dataPath + ".time_values.1.bin" if numTimes != 0 { ok, err := file.HasSize(timePath, int64(numTimes*8)) if err != nil { return err } if !ok { return fmt.Errorf("file %s has incorrect file size", timePath) } } else { ok, err := file.IsNonEmpty(timePath) if err != nil { return err } if !ok { return fmt.Errorf("file %s is not non-empty", timePath) } } return nil }
// checkDREAMMV3MeshASCII checks the layout for mesh related data within the // DREAMM v3 viz format func checkDREAMMV3MeshASCII(testDir, dataDir string, allIters, posIters, regionIters, stateIters jsonParser.IntList, meshEmpty bool, objects, objectRegions []string) error { m, err := misc.CreateMolMeshIters(allIters, posIters, regionIters, stateIters) if err != nil { return err } if len(objectRegions) == 0 { objectRegions = objects } dataPath := filepath.Join(file.GetOutputDir(testDir), dataDir) lastPos := -1 lastRegion := -1 lastState := -1 for _, i := range m.All { iterPath := filepath.Join(dataPath, "frame_data", "iteration_%d") hadFrame := false // positions for _, obj := range objects { posFile := filepath.Join(iterPath, obj+".positions.dat") if err := misc.CheckDREAMMV3IterItems(m.Pos, m.Combined, i, lastPos, meshEmpty, posFile); err != nil { return err } conFile := filepath.Join(iterPath, obj+".connections.dat") if err := misc.CheckDREAMMV3IterItems(m.Pos, m.Combined, i, lastPos, meshEmpty, conFile); err != nil { return err } } if m.Pos.Contains(i) { lastPos = i misc.UnsetTrackers(i, &lastPos, &lastRegion, &lastState) hadFrame = true } // regions for _, obj := range objectRegions { regionFile := filepath.Join(iterPath, obj+".region_indices.dat") if err := misc.CheckDREAMMV3IterItems(m.Others, m.States, i, lastRegion, meshEmpty, regionFile); err != nil { return err } } if m.Others.Contains(i) { lastRegion = i misc.UnsetTrackers(i, &lastPos, &lastRegion, &lastState) hadFrame = true } // states for _, obj := range objects { statesFile := filepath.Join(iterPath, obj+".states.bin") emptySet := set.NewIntSet() if err := misc.CheckDREAMMV3IterItems(m.States, emptySet, i, lastState, meshEmpty, statesFile); err != nil { return err } } if m.States.Contains(i) { lastState = i misc.UnsetTrackers(i, &lastPos, &lastRegion, &lastState) hadFrame = true } template := filepath.Join(iterPath, "meshes.dx") if err := misc.CheckDREAMMV3DXItems(i, lastPos, lastRegion, lastState, hadFrame, template); err != nil { return err } } return nil }
// checkDREAMMV3MolsASCII checks the layout for molecule viz data as part of the // ASCII DREAMM v3 format func checkDREAMMV3MolsASCII(testDir string, c *jsonParser.TestCase) error { m, err := misc.CreateMolMeshIters(c.AllIters, c.PosIters, c.OrientIters, c.StateIters) if err != nil { return err } dataPath := filepath.Join(file.GetOutputDir(testDir), c.VizPath) lastPos := -1 lastOrient := -1 lastState := -1 for _, i := range m.All { iterPath := filepath.Join(dataPath, "frame_data", "iteration_%d") hadFrame := false // positions for _, obj := range c.MolNames { posFile := filepath.Join(iterPath, obj+".positions.dat") if err := misc.CheckDREAMMV3IterItems(m.Pos, m.Combined, i, lastPos, true, posFile); err != nil { return err } } if m.Pos.Contains(i) { lastPos = i misc.UnsetTrackers(i, &lastPos, &lastOrient, &lastState) hadFrame = true } // orientations for _, obj := range c.MolNames { orientFile := filepath.Join(iterPath, obj+".orientations.dat") if err := misc.CheckDREAMMV3IterItems(m.Others, m.Combined, i, lastOrient, true, orientFile); err != nil { return err } } if m.Others.Contains(i) { lastOrient = i misc.UnsetTrackers(i, &lastPos, &lastOrient, &lastState) hadFrame = true } // states for _, obj := range c.MolNames { stateFile := filepath.Join(iterPath, obj+".states.dat") if err := misc.CheckDREAMMV3IterItems(m.States, m.Combined, i, lastState, true, stateFile); err != nil { return err } } if m.States.Contains(i) { lastState = i misc.UnsetTrackers(i, &lastPos, &lastOrient, &lastState) hadFrame = true } volTemplate := filepath.Join(iterPath, "volume_molecules.dx") if err := misc.CheckDREAMMV3DXItems(i, lastPos, lastOrient, lastState, hadFrame, volTemplate); err != nil { return err } surfTemplate := filepath.Join(iterPath, "surface_molecules.dx") if err := misc.CheckDREAMMV3DXItems(i, lastPos, lastOrient, lastState, hadFrame, surfTemplate); err != nil { return err } } return nil }
// simRunner runs mcell on the mdl file passed in as an // absolute path. The working directory is set to the base path // of the mdl file. func simRunner(mcellPath string, test *jsonParser.TestDescription, output chan *jsonParser.TestDescription) { outputDir := file.GetOutputDir(test.Path) for i, runFile := range test.Run.MdlFiles { // create run command mdlPath := filepath.Join(test.Path, runFile) runLog := fmt.Sprintf("run_%d.%d.log", test.Run.Seed, i) errLog := fmt.Sprintf("err_%d.%d.log", test.Run.Seed, i) argList := append(test.Run.CommandlineOpts, "-seed", strconv.Itoa(test.Run.Seed), "-logfile", runLog, "-errfile", errLog, mdlPath) cmd := exec.Command(mcellPath, argList...) cmd.Dir = outputDir if err := misc.WriteCmdLine(mcellPath, outputDir, argList); err != nil { test.SimStatus = append(test.SimStatus, jsonParser.RunStatus{false, fmt.Sprint(err), "", -1}) output <- test return } // connect stdout and stderr stdOutPath := fmt.Sprintf("stdout_%d.%d.log", test.Run.Seed, i) stdOut, err := os.Create(filepath.Join(outputDir, stdOutPath)) if err != nil { test.SimStatus = append(test.SimStatus, jsonParser.RunStatus{false, fmt.Sprint(err), "", -1}) output <- test return } defer stdOut.Close() cmd.Stdout = stdOut stdErrPath := fmt.Sprintf("stderr_%d.%d.log", test.Run.Seed, i) stdErr, err := os.Create(filepath.Join(outputDir, stdErrPath)) if err != nil { test.SimStatus = append(test.SimStatus, jsonParser.RunStatus{false, fmt.Sprint(err), "", -1}) output <- test return } defer stdErr.Close() cmd.Stderr = stdErr err = cmd.Run() if err != nil { stdErrContent, _ := ioutil.ReadFile(filepath.Join(outputDir, errLog)) exitCode, err := misc.DetermineExitCode(err) if err != nil { exitCode = -1 } test.SimStatus = append(test.SimStatus, jsonParser.RunStatus{false, fmt.Sprint(err), string(stdErrContent), exitCode}) } else { test.SimStatus = append(test.SimStatus, jsonParser.RunStatus{true, "", "", 0}) } } output <- test }