void VoxCad::SetupPhysicsWindow(void) { PhysicsDockWidget = new QDockWidget(this); PhysicsDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); PhysicsDlg = new Dlg_Physics(&MainSim, PhysicsDockWidget); PhysicsDockWidget->setWidget(PhysicsDlg); PhysicsDockWidget->setWindowTitle("Physics Settings"); PhysicsDockWidget->setVisible(false); connect(PhysicsDockWidget->toggleViewAction(), SIGNAL(triggered(bool)), this, SLOT(PhysicsMode(bool))); connect(&MainSim, SIGNAL(UpdateText(QString)), PhysicsDlg, SLOT(SetStatusText(QString))); connect(&MainSim, SIGNAL(ReqGLUpdate()), this, SLOT(ReqGLUpdateAll())); connect(&MainSim, SIGNAL(ReqAddPlotPoint(double)), PhysicsDlg, SLOT(AddPlotPoint(double)), Qt::DirectConnection); connect(&MainSim, SIGNAL(StartExternalGLUpdate()), GLWindow, SLOT(StartAutoRedraw())); connect(&MainSim, SIGNAL(StopExternalGLUpdate()), GLWindow, SLOT(StopAutoRedraw())); //connect(FEAInfoDlg, SIGNAL(RequestUpdateGL()), this, SLOT(ReqGLUpdateAll())); //connect(FEAInfoDlg, SIGNAL(GetCurIndex(int*)), this, SLOT(GetCurGLSelected(int*))); //connect(FEAInfoDlg, SIGNAL(GetFEAInfoString(QString*)), &MainFEA, SLOT(GetFEAInfoString(QString*))); //connect(FEAInfoDlg, SIGNAL(GetFEAInfoString(int, QString*)), &MainFEA, SLOT(GetFEAInfoString(int, QString*))); //connect(FEAInfoDlg, SIGNAL(DoneAnalyzing()), this, SLOT(ForceViewMode(void))); addDockWidget(Qt::RightDockWidgetArea, PhysicsDockWidget); }
void QVX_Sim::EndRecording(void) //stops recording { if (!Recording) return; //if already not recording, don't do anything DtThaw(); GLUpdateEveryNFrame = -1; //make sure update every frame is turned off... emit StopExternalGLUpdate(); //stop external display that might be at different speed emit StartExternalGLUpdate(DEFAULT_DISPLAY_UPDATE_MS); //start default display rate again emit ResetGLWindow(); Recording = false; }
void VoxCad::SetupTensileWindow(void) { TensileDockWidget = new QDockWidget(this); TensileDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); TensileDlg = new Dlg_Tensile(&MainEnv, PhysicsDockWidget); TensileDockWidget->setWidget(TensileDlg); TensileDockWidget->setWindowTitle("Tensile Testing"); TensileDockWidget->setVisible(false); connect(TensileDlg, SIGNAL(DoneTensileTesting()), this, SLOT(ViewMode())); connect(&TensileDlg->Tester, SIGNAL(StartExternalGLUpdate(int)), GLWindow, SLOT(StartAutoRedraw(int))); connect(&TensileDlg->Tester, SIGNAL(StopExternalGLUpdate()), GLWindow, SLOT(StopAutoRedraw())); addDockWidget(Qt::RightDockWidgetArea, TensileDockWidget); }
void VoxCad::SetupPhysicsWindow(void) { PhysicsDockWidget = new QDockWidget(this); PhysicsDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); PhysicsDlg = new Dlg_Physics(&MainSim, PhysicsDockWidget); PhysicsDockWidget->setWidget(PhysicsDlg); PhysicsDockWidget->setWindowTitle("Physics Settings"); PhysicsDockWidget->setVisible(false); connect(PhysicsDockWidget->toggleViewAction(), SIGNAL(triggered(bool)), this, SLOT(PhysicsMode(bool))); connect(&MainSim, SIGNAL(UpdateText(QString)), PhysicsDlg, SLOT(SetStatusText(QString))); connect(&MainSim, SIGNAL(ReqGLUpdate()), this, SLOT(ReqGLUpdateAll())); connect(&MainSim, SIGNAL(ReqUiUpdate()), PhysicsDlg, SLOT(UpdateUI())); connect(&MainSim, SIGNAL(ReqGLDrawingStatus(bool*)), GLWindow, SLOT(IsDrawing(bool*))); connect(&MainSim, SIGNAL(IsStatusTextVisible(bool*)), PhysicsDlg, SLOT(IsOutputVisible(bool*)), Qt::DirectConnection); connect(&MainSim, SIGNAL(IsPlotVisible(bool*)), PhysicsDlg, SLOT(IsPlotVisible(bool*)), Qt::DirectConnection); connect(&MainSim, SIGNAL(GetPlotRqdStats(char*)), this, SLOT(GetPlotRqdDataType(char*)), Qt::DirectConnection); connect(&MainSim, SIGNAL(ReqAddPlotPoint(double)), PhysicsDlg, SLOT(AddPlotPoint(double)), Qt::DirectConnection); connect(&MainSim, SIGNAL(SimEndedInternally(QString)), PhysicsDlg, SLOT(UpdateUI())); // connect(&MainSim, SIGNAL(SimEndedInternally(QString)), this, SLOT(ReqGLUpdateAll())); connect(&MainSim, SIGNAL(StartExternalGLUpdate(int)), GLWindow, SLOT(StartAutoRedraw(int))); connect(&MainSim, SIGNAL(StopExternalGLUpdate()), GLWindow, SLOT(StopAutoRedraw())); connect(GLWindow, SIGNAL(FindCamTarget(Vec3D<>*)), &MainSim, SLOT(GetCoM(Vec3D<>*))); connect(GLWindow, SIGNAL(WantAutoSaveFrames(bool*)), &MainSim, SLOT(WantFramesAutoSaved(bool*))); connect(GLWindow, SIGNAL(GetFrameFilePath(QString*)), &MainSim, SLOT(AutoSavePath(QString*))); connect(&MainSim, SIGNAL(ResizeGLWindow(int, int)), this, SLOT(ResizeGlWindowArea(int, int))); connect(&MainSim, SIGNAL(ResetGLWindow()), this, SLOT(ResetGlWindowArea())); //connect(FEAInfoDlg, SIGNAL(RequestUpdateGL()), this, SLOT(ReqGLUpdateAll())); //connect(FEAInfoDlg, SIGNAL(GetCurIndex(int*)), this, SLOT(GetCurGLSelected(int*))); //connect(FEAInfoDlg, SIGNAL(GetFEAInfoString(QString*)), &MainFEA, SLOT(GetFEAInfoString(QString*))); //connect(FEAInfoDlg, SIGNAL(GetFEAInfoString(int, QString*)), &MainFEA, SLOT(GetFEAInfoString(int, QString*))); //connect(FEAInfoDlg, SIGNAL(DoneAnalyzing()), this, SLOT(ForceViewMode(void))); addDockWidget(Qt::RightDockWidgetArea, PhysicsDockWidget); }
void QVX_TensileTest::RunTensileTest(QString* pDispMessage) { QFile File(OutFilePath); if (!File.open(QIODevice::WriteOnly | QIODevice::Text)) { ProgressMessage = "Could not open file. Aborting."; return; } QTextStream out(&File); // double CurMaxDisp = 9e9; std::string IntMsg; vfloat StepPercAmt = 1.0/NumStep; int VoxCount = NumVox(); int count = 0; int MinimumPerStep = 5; int NumBCs = pEnv->GetNumBCs(); for (int j=0; j<NumBCs; j++){ if (pEnv->GetBC(j)->Displace.Length2() == 0 ) continue; //if zero displacement, continue out << "Disp (m)" << "\t" << "Force (N)" << "\t"; if (IsBasicTensile){out << "Strain (%)" << "\t" << "Stress (MPa)" << "\t" << "Modulus (MPa)" << "\t";} } out << "\n"; double LastStress; //so we can calculate modulus at each point... double LastStrain; for (int i=0; i<NumStep; i++){ ProgressMessage = "Performing tensile test..."; for (int j=0; j<VoxCount; j++) VoxArray[j].ScaleExternalInputs((i+1)*StepPercAmt); //wiat to settle between timesteps... int LastBroken = -1; ClearHistories(); //needed so it doesn't immediately "converge" on the next time step while (NumBroken() != LastBroken){ //if one breaks, repeat the settling undtil we're done breaking... LastBroken = NumBroken(); EnableFailure(false); // SetSlowDampZ(CurDamp); count = 0; // bool LastUnder = false; //were we under the threshhold last time? // while (!LastUnder || CurMaxDisp > ConvThresh){ while (!StopConditionMet()){ // if (CurMaxDisp < ConvThresh) LastUnder = true; for (int i=0; i<MinimumPerStep; i++){ if (CancelFlag) break; if (!TimeStep(&IntMsg)){ //always do at least 5 steps... ProgressMessage = "Tensile test failed. \n \n" + IntMsg; CancelFlag = true; //get outta here! } // CurMaxDisp = SS.NormObjDisp; } if (CancelFlag) break; count+=MinimumPerStep; if (count > 20000){ QString Num = QString::number(MaxMoveHistory[0]*1000); ProgressMessage = "Simulation not converging at " + Num.toStdString() + ". \n Retry with larger threshold."; } } if (CancelFlag) break; EnableFailure(true); //do one step to apply breaking and re-settle as needed... if (!TimeStep(&IntMsg)){ ProgressMessage = "Tensile test failed. \n \n" + IntMsg; CancelFlag = true; //get outta here! } } for (int j=0; j<NumBCs; j++){ CVX_FRegion* pThisBC = pEnv->GetBC(j); if (pThisBC->Displace.Length2() != 0 ){ //if non-zero displacement double CurDisp = pThisBC->Displace.Length()*(i+1.0)/((double)NumStep); double tmp2 = -GetSumForceDir(pThisBC); out << CurDisp << "\t" << tmp2 << "\t"; if (IsBasicTensile){ //only two materials, only one with displacement, so we should only ever enter here once!! double ThisStress = tmp2/CSArea; double ThisStrain = CurDisp/IniLength; out << ThisStrain*100 << "\t" << ThisStress/1e6 << "\t"; if (i!=0) out << (ThisStress-LastStress)/(ThisStrain-LastStrain)/1e6 << "\t"; else out << "" << "\t"; LastStress = ThisStress; LastStrain = ThisStrain; } } } out << "\n"; // for (int k=0; k<VoxArray.size(); k++){ // VoxArray[k].ExternalDisp *= (i+2.0)/(i+1.0); // } CurTick = i+1; } int stop = 1; File.close(); ProgressMessage = ""; //flag to not display message boc on return... TestRunning = false; emit StopExternalGLUpdate(); }
void QVX_Sim::BeginRecording(void) //opens record dialog and begins recording { if (Recording) return; //if we're already recording, don't do anything! bool WasPaused = Paused; //pause the sim and remeber whether it was paused or not... if (Running && !WasPaused) SimPauseToggle(); Dlg_VideoCapture VidCapDlg(this); if (StopConditionType == SC_MAX_TIME_STEPS) {VidCapDlg.StopEnabled=true; VidCapDlg.CurStopSettings = SS_TIME_STEPS; VidCapDlg.sNumStep = qRound(StopConditionValue);} if (StopConditionType == SC_MAX_SIM_TIME) {VidCapDlg.StopEnabled=true; VidCapDlg.CurStopSettings = SS_SIM_TIME; VidCapDlg.sSimTime = StopConditionValue;} if (StopConditionType == SC_TEMP_CYCLES) {VidCapDlg.StopEnabled=true; VidCapDlg.CurStopSettings = SS_TEMP_CYCLES; VidCapDlg.sNumCyc = qRound(StopConditionValue);} VidCapDlg.UpdateUI(); VidCapDlg.exec(); if (VidCapDlg.AcceptedDialog){ if (VidCapDlg.ResetSimOnBegin) ResetSim(); emit StopExternalGLUpdate(); //stop external update! GLUpdateEveryNFrame = -1; //make sure update every frame is turned off... double OutFps = VidCapDlg.OutputFps; double OutSpdFctr = VidCapDlg.OutputSpeedFactor; switch(VidCapDlg.CurVidSetting){ case VS_DISPLAY: StartExternalGLUpdate(1000*OutSpdFctr/OutFps); break; case VS_SIMULATION: { DtFreeze(); //this could be bad for sims with non-linear materials that change dramatically in their stability double VideoDt = OutSpdFctr/OutFps; //what the dt step for video should be (in sec) if (dt > VideoDt){ dt = VideoDt; //if simulation timesteps are greater than desired video framerate slow down simulation timesteps GLUpdateEveryNFrame=1; } else { //round dt down so that VideoDt is an even multiple... GLUpdateEveryNFrame = (int)(VideoDt/dt) + 1; dt = VideoDt/((double)GLUpdateEveryNFrame); } } break; case VS_EVERY: GLUpdateEveryNFrame = 1; break; default: break; } if (VidCapDlg.StopEnabled){ switch (VidCapDlg.CurStopSettings){ case SS_TIME_STEPS: StopConditionType = SC_MAX_TIME_STEPS; StopConditionValue = (vfloat)VidCapDlg.sNumStep; break; case SS_SIM_TIME: StopConditionType = SC_MAX_SIM_TIME; StopConditionValue = (vfloat)VidCapDlg.sSimTime; break; case SS_TEMP_CYCLES: StopConditionType = SC_TEMP_CYCLES; StopConditionValue = (vfloat)VidCapDlg.sNumCyc; break; default: StopConditionType = SC_NONE; } } else StopConditionType = SC_NONE; //reset naming for current files in the selected folder VideoOutputFolder=VidCapDlg.CurFolder; CurVideoFrameNumber = 0; emit ResizeGLWindow(VidCapDlg.WidthPix, VidCapDlg.HeightPix); Recording = true; if (!Running){ RequestBeginSim(); Running = true;} else SimPauseToggle(); //always unpause the simulation if we began recording } else { //rejected (canceled) return to running or not state. if (Running && !WasPaused) SimPauseToggle(); //unpause the simulation if it was running before } }
void QVX_Sim::SimLoop(QString* pSimMessage) { std::string tmp; //need to link this up to get info back... if (!Import(NULL, NULL, &tmp)) return; int Count = 0; //Possibly redundant with internal sim count. int LastCount = 0; bool IsStillDrawing; Vec3D<> CurSelPos; QString PosLabel; bool InternalEnding = false; QString Message, DispMessage; std::string RetMsg; QTime tLastPlot; //plot point add every... QTime tLastStatus; //status text box updated... // QTime tLastStatCalc; //simulation max/mins calculated every... tLastPlot.start(); tLastStatus.start(); // tLastStatCalc.start(); emit ReqUiUpdate(); //for slider ranges that depend on dt or other sim params emit StartExternalGLUpdate(DEFAULT_DISPLAY_UPDATE_MS); StopSim = false; Running = true; Paused = false; //initialize the COM at the start of the simulation IniCM=GetCM(); Vec3D<> LastCM = IniCM; int StatusNumber = 1, PlotPointNumber = 1; double UpStatEv = 500; //Updates status pane every X ms int UpPlotEv = 30; //updates plot every X ms when not plotting every point. char PlotDataTypes; bool PlotVis, StatusVis; while (true){ //do this step... if (StopConditionMet()){InternalEnding = true; StatToCalc=CALCSTAT_ALL; UpdateStats(); RetMsg+="Simulation stop condition reached.\n";break;}//if stop condition met... //figure out what stats we need to calculate StatToCalc=CALCSTAT_NONE; emit IsPlotVisible(&PlotVis); bool PlottingPoint = (LogEvery?true:tLastPlot.elapsed() > PlotPointNumber*UpPlotEv) && PlotVis; if (PlottingPoint){ //ensure we calculate the info we want to plot emit GetPlotRqdStats(&PlotDataTypes); StatToCalc |= PlotDataTypes; } emit IsStatusTextVisible(&StatusVis); bool UpdatingStatus = (tLastStatus.elapsed() > StatusNumber*UpStatEv) && StatusVis; if (UpdatingStatus){StatToCalc |= CALCSTAT_COM;} //calc any data we need in the text status box bool DrawingGLLocal = (GLUpdateEveryNFrame != -1 && Count%GLUpdateEveryNFrame==0); if (DrawingGLLocal || NeedStatsUpdate){ //calc any data we need to draw the opengl view... StatToCalc |= StatRqdToDraw(); NeedStatsUpdate = false; if (LockCoMToCenter) StatToCalc |= CALCSTAT_COM; } // if (tLastStatCalc.elapsed() > StatCalcNumber*30){CalcStat=true; StatCalcNumber++; /*tLastStatCalc.restart();*/} if (!TimeStep(&RetMsg)){InternalEnding = true; break;}//if something happened in this timestep if (DrawingGLLocal){ IsStillDrawing = true; ReqGLDrawingStatus(&IsStillDrawing); while (IsStillDrawing){ //wait to finish drawing the previous timestep before continuing LOCALSLEEP(1); ReqGLDrawingStatus(&IsStillDrawing); //are } emit ReqGLUpdate(); } if (StopSim) break; while(Paused){ ActuallyPaused = true; if (StopSim) break; //kick out of the loop if we've stopped... LOCALSLEEP(100); } if(UpdatingStatus){ // emit IsStatusTextVisible... if (CurXSel != -1){PosLabel = "Vox "+QString::number(XtoSIndexMap[CurXSel]) + "(sim)"; CurSelPos = VoxArray[XtoSIndexMap[CurXSel]].GetCurPos()*1000; }//position in mm else {PosLabel = "CoM "; CurSelPos = SS.CurCM*1000;} //center of mass in mm if nothing else selected Message = "Time " + QString::number(CurTime, 'g', 3) + " Sec" + "\nStep Num " + QString::number(CurStepCount) + "\nTime Step = " + QString::number(dt, 'g', 3)+ " Sec" + "\nDisplay Rate = "+ QString::number((Count-LastCount)/(UpStatEv/1000.0), 'g', 3)+" Steps/sec" + "\n" + PosLabel + " X:"+ QString::number(CurSelPos.x, 'g', 3)+" Y:"+ QString::number(CurSelPos.y, 'g', 3)+" Z:"+ QString::number(CurSelPos.z, 'g', 3)+ " mm" + "\nCoM Displacement = "+ QString::number((SS.CurCM-IniCM).Length()*1000, 'g', 3)+" mm" + "\nCoM Velocity = "+ QString::number((SS.CurCM-LastCM).Length()*1000/(dt*(Count-LastCount)), 'g', 3)+" mm/s\n"; if (pEnv->IsFloorEnabled()) Message += "Voxel touching ground: " + QString::number(GetNumTouchingFloor()) + "\n"; Message += "\n"; LastCM = SS.CurCM; if (LogEvery) ApproxMSperLog = (double)tLastStatus.elapsed()/(Count-LastCount); //only update ms per step if its not fixed by the timer LastCount = Count; emit UpdateText(Message); StatusNumber++; } if (PlottingPoint){ if (LogEvery) emit ReqAddPlotPoint(GetCurTime()); else { ApproxMSperLog = UpPlotEv; emit ReqAddPlotPoint(GetCurTime()); PlotPointNumber++; } } // if (StatCalcNumber == INT_MAX){StatCalcNumber=1; tLastStatCalc.restart();} //avoid int rollover for our counters if (StatusNumber == INT_MAX){StatusNumber=1; tLastStatus.restart();} if (PlotPointNumber == INT_MAX){PlotPointNumber=1; tLastPlot.restart();} Count++; } emit StopExternalGLUpdate(); // emit SetExternalGLUpdate(false); Running = false; Paused = false; Message = "Time " + QString::number(CurTime, 'g', 3) + " Sec" + "\nStep Num " + QString::number(CurStepCount) + "\nTime Step = " + QString::number(dt, 'g', 3)+ " Sec" + "\n" + PosLabel + " X:"+ QString::number(CurSelPos.x, 'g', 3)+" Y:"+ QString::number(CurSelPos.y, 'g', 3)+" Z:"+ QString::number(CurSelPos.z, 'g', 3)+ " mm" + "\nCOM_Dist = "+ QString::number((SS.CurCM-IniCM).Length()*1000, 'g', 3)+" mm\n\n"; RetMsg += "Simulation stopped.\n"; Message += RetMsg.c_str(); DispMessage = Message + "\nFinal Conditions:\nStep = " + QString::number(CurStepCount) + "\nTime Step = " + QString::number(dt)+"\nKinetic Energy = " + QString::number(SS.TotalObjKineticE)+"\n" ; emit UpdateText(DispMessage); if (InternalEnding) emit SimEndedInternally(RetMsg.c_str()); // Running = false; }
void QVX_TensileTest::RunTensileTest(QString* pDispMessage) { QFile File(OutFilePath); if (!File.open(QIODevice::WriteOnly | QIODevice::Text)) { ProgressMessage = "Could not open file. Aborting."; return; } QTextStream out(&File); // double CurMaxDisp = 9e9; std::string IntMsg; vfloat StepPercAmt = 1.0/NumStep; int VoxCount = NumVox(); int count = 0; int MinimumPerStep = 5; int NumBCs = pEnv->GetNumBCs(); for (int j=0; j<NumBCs; j++){ if (pEnv->GetBC(j)->Displace.Length2() == 0 ) continue; //if zero displacement, continue out << "Disp (m)" << "\t" << "Force (N)" << "\t"; if (IsBasicTensile){out << "Strain (%)" << "\t" << "Stress (MPa)" << "\t" << "Modulus (MPa)" << "\t";} } out << "\n"; double LastStress; //so we can calculate modulus at each point for simple tensile... double LastStrain; double MaxMotion = -FLT_MAX; //the stop condition will be a threshold of this in auto mode double LastMotion = 0; bool FoundMaxMotion = false; if (AutoConverge){ ConvThresh = 0; SetStopConditionValue(ConvThresh);}//don't stop until we get a max for (int i=0; i<NumStep; i++){ ProgressMessage = "Performing tensile test..."; for (int j=0; j<VoxCount; j++) VoxArray[j].ScaleExternalInputs((i+1)*StepPercAmt); //wiat to settle between timesteps... int LastBroken = -1; ClearHistories(); //needed so it doesn't immediately "converge" on the next time step while (NumBroken() != LastBroken){ //if one breaks, repeat the settling until we're done breaking... LastBroken = NumBroken(); EnableFeature(VXSFEAT_FAILURE, false); // EnableFailure(false); // SetSlowDampZ(CurDamp); count = 0; // bool LastUnder = false; //were we under the threshhold last time? // while (!LastUnder || CurMaxDisp > ConvThresh){ while (!StopConditionMet()){ // if (CurMaxDisp < ConvThresh) LastUnder = true; for (int i=0; i<MinimumPerStep; i++){ if (CancelFlag) break; if (!TimeStep(&IntMsg)){ //always do at least 5 steps... ProgressMessage = "Tensile test failed. \n \n" + IntMsg; CancelFlag = true; //get outta here! } // CurMaxDisp = SS.NormObjDisp; } if (CancelFlag) break; if (!FoundMaxMotion && AutoConverge){ if (MotionZeroed){ //find first max motion (actually max KE, but close enough) FoundMaxMotion = true; ConvThresh = LastMotion / AutoConvergeExp; SetStopConditionValue(ConvThresh); //ProgressMessage = "Auto convergence threshhold calculated: " + QString::number(ConvThresh).toStdString(); } else LastMotion = SS.MaxVoxVel*dt; } if (count%100==0){ ProgressMessage = "Performing tensile test..."; if (AutoConverge && !FoundMaxMotion) ProgressMessage += "\nDetermining convergence threshhold."; //else ProgressMessage += "\nMotion at " + QString::number(MaxMoveHistory[0]*1000000, 'g', 3).toStdString() + "/" + QString::number(ConvThresh, 'g', 3).toStdString(); else ProgressMessage += "\nStep " + QString::number(count, 'g', 3).toStdString() +/*", Max Displacement " + QString::number(SS.MaxVoxDisp, 'g', 3).toStdString() + */", Convergence threshhold " + QString::number(ConvThresh, 'g', 3).toStdString(); if (count > 20000){ ProgressMessage += "\nSimulation not converging.\nConsider retrying with a larger threshold. (Currently " + QString::number(MaxMoveHistory[0]*1000, 'g', 3).toStdString() +")"; } } count+=MinimumPerStep; } if (CancelFlag) break; EnableFeature(VXSFEAT_FAILURE, true); // EnableFailure(true); //do one step to apply breaking and re-settle as needed... if (!TimeStep(&IntMsg)){ ProgressMessage = "Tensile test failed. \n \n" + IntMsg; CancelFlag = true; //get outta here! } } for (int j=0; j<NumBCs; j++){ CVX_FRegion* pThisBC = pEnv->GetBC(j); if (pThisBC->Displace.Length2() != 0 ){ //if non-zero displacement double CurDisp = pThisBC->Displace.Length()*(i+1.0)/((double)NumStep); double tmp2 = -GetSumForceDir(pThisBC); out << CurDisp << "\t" << tmp2 << "\t"; if (IsBasicTensile){ //only two materials, only one with displacement, so we should only ever enter here once!! double ThisStress = tmp2/CSArea; double ThisStrain = CurDisp/IniLength; out << ThisStrain*100 << "\t" << ThisStress/1e6 << "\t"; if (i!=0) out << (ThisStress-LastStress)/(ThisStrain-LastStrain)/1e6 << "\t"; else out << "" << "\t"; LastStress = ThisStress; LastStrain = ThisStrain; } } } out << "\n"; // for (int k=0; k<VoxArray.size(); k++){ // VoxArray[k].ExternalDisp *= (i+2.0)/(i+1.0); // } CurTick = i+1; } int stop = 1; File.close(); ProgressMessage = ""; //flag to not display message boc on return... TestRunning = false; emit StopExternalGLUpdate(); }