Files
wg_cpso/CaeJob/AnalysisJob.cs
2026-03-25 18:20:24 +08:00

871 lines
35 KiB
C#

using CaeGlobals;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace CaeJob
{
//
[Serializable]
public class AnalysisJob : NamedClass, ISerializable
{
// Variables
protected string _workDirectory; // ISerializable
protected string _executable; // ISerializable
protected string _argument; // ISerializable
protected bool _compatibilityMode; // ISerializable
protected JobStatus _jobStatus; // ISerializable
protected int _numCPUs; // ISerializable
protected List<EnvironmentVariable> _environmentVariables; // ISerializable
protected long _datFileLength; // ISerializable
protected string _datFileContents; // ISerializable
protected long _statusFileLength; // ISerializable
protected string _statusFileContents; // ISerializable
protected long _convergenceFileLength; // ISerializable
protected string _convergenceFileContents; // ISerializable
protected DateTime _endTime; // ISerializable
protected FEMSolverEnum _femSolver; // ISerializable
protected bool _onlyCheckModel; // ISerializable
//
[NonSerialized] protected Stopwatch _watch;
[NonSerialized] private Process _exe;
[NonSerialized] private StringBuilder _sbOutput;
[NonSerialized] private StringBuilder _sbAllOutput;
[NonSerialized] private bool _datFileToLong;
[NonSerialized] private string _outputFileName;
[NonSerialized] private string _errorFileName;
[NonSerialized] private object _myLock;
[NonSerialized] private string _inputFileName;
[NonSerialized] private int _numOfRunSteps;
[NonSerialized] private int _currentRunStep;
[NonSerialized] private int _numOfRunIncrements;
[NonSerialized] private int _currentRunIncrement;
[NonSerialized] private object _tag;
[NonSerialized] private bool _useBackgroundWorker;
[NonSerialized] private double _prevWatchMilliseconds;
// Properties
public override string Name
{
get { return base.Name; }
set
{
if (base.Name != value)
{
base.Name = value;
//
if (_femSolver == FEMSolverEnum.Calculix) _argument = Name;
else if (_femSolver == FEMSolverEnum.Abaqus) _argument = "job=" + Name;
else throw new NotSupportedException();
}
}
}
public string WorkDirectory
{
get { return _workDirectory; }
set { _workDirectory = value; }
}
public string Executable
{
get { return _executable; }
set { _executable = value; }
}
public string Argument
{
get { return _argument; }
set { _argument = value; }
}
public string ResultsFileName
{
get
{
if (_femSolver == FEMSolverEnum.Calculix) return Path.Combine(WorkDirectory, _name + ".frd");
else if (_femSolver == FEMSolverEnum.Abaqus) return Path.Combine(WorkDirectory, _name + ".odb");
else throw new NotSupportedException();
}
}
public bool IsUpToDate
{
get
{
DateTime lastWriteTime = File.GetLastWriteTime(ResultsFileName);
return _endTime > lastWriteTime;
}
}
public bool CompatibilityMode { get { return _compatibilityMode; } set { _compatibilityMode = value; } }
public JobStatus JobStatus { get { return _jobStatus; } }
public int NumCPUs
{
get { return _numCPUs; }
set
{
_numCPUs = value;
ProcessStartInfo psi = new ProcessStartInfo();
SetNumberOfProcessors(psi);
}
}
public List<EnvironmentVariable> EnvironmentVariables
{
get { return _environmentVariables; }
set { _environmentVariables = value; }
}
public string DatFileData { get { return _datFileContents; } }
public string StatusFileData { get { return _statusFileContents; } }
public string ConvergenceFileData { get { return _convergenceFileContents; } }
public int CurrentRunStep { get { return _currentRunStep; } }
public int CurrentRunIncrement { get { return _currentRunIncrement; } }
public string InputFileName { get { return _inputFileName; } }
public FEMSolverEnum FEMSolver
{
get { return _femSolver; }
set
{
if (_femSolver != value)
{
_femSolver = value;
//
if (_femSolver == FEMSolverEnum.Calculix) _argument = Name;
else if (_femSolver == FEMSolverEnum.Abaqus) _argument = "job=" + Name;
else throw new NotSupportedException();
}
}
}
public bool OnlyCheckModel { get { return _onlyCheckModel; } set { _onlyCheckModel = value; } }
public object Tag { get { return _tag; } set { _tag = value; } }
// Events
public event Action<AnalysisJob, string> DataOutputEvent;
// Callback
public Action<string, JobStatus> JobStatusChanged;
public Action<AnalysisJob> PreRun;
public Action<AnalysisJob> PostRun;
public Action<AnalysisJob> LastRunCompleted;
// Constructor
public AnalysisJob(string name, string executable, string argument, string workDirectory)
: base(name)
{
_executable = executable;
_argument = argument;
_workDirectory = workDirectory;
_compatibilityMode = false;
_numCPUs = 1;
_environmentVariables = new List<EnvironmentVariable>();
_endTime = DateTime.MinValue;
//
_exe = null;
_jobStatus = JobStatus.None;
_watch = null;
_sbOutput = null;
_sbAllOutput = null;
_onlyCheckModel = false;
}
public AnalysisJob(SerializationInfo info, StreamingContext context)
: base(info, context)
{
// Compatibility v 2.3.5
_femSolver = FEMSolverEnum.Calculix;
//
foreach (SerializationEntry entry in info)
{
switch (entry.Name)
{
case "_workDirectory":
_workDirectory = (string)entry.Value; break;
case "_executable":
_executable = (string)entry.Value; break;
case "_argument":
_argument = (string)entry.Value; break;
case "_compatibilityMode":
_compatibilityMode = (bool)entry.Value; break;
case "_jobStatus":
_jobStatus = (JobStatus)entry.Value; break;
case "_numCPUs":
_numCPUs = (int)entry.Value; break;
case "_environmentVariables":
_environmentVariables = (List<EnvironmentVariable>)entry.Value; break;
case "_datFileLength":
_datFileLength = (long)entry.Value; break;
case "_datFileContents":
_datFileContents = (string)entry.Value; break;
case "_statusFileLength":
_statusFileLength = (long)entry.Value; break;
case "_statusFileContents":
_statusFileContents = (string)entry.Value; break;
case "_convergenceFileLength":
_convergenceFileLength = (long)entry.Value; break;
case "_convergenceFileContents":
_convergenceFileContents = (string)entry.Value; break;
case "_endTime":
_endTime = (DateTime)entry.Value; break;
case "_femSolver":
_femSolver = (FEMSolverEnum)entry.Value; break;
case "_onlyCheckModel":
_onlyCheckModel = (bool)entry.Value; break;
default:
break;
}
}
}
// Event handlers
void Timer_Tick(object sender, EventArgs e)
{
//OutputData();
}
// Methods
public void Submit(int numOfRunSteps, int numOfRunIncrements, bool useBackgroundWorker = true)
{
if (numOfRunSteps < 1 || numOfRunIncrements < 1) throw new NotSupportedException();
_useBackgroundWorker = useBackgroundWorker;
// Reset job
_tag = null;
_jobStatus = JobStatus.None;
//
_inputFileName = Path.Combine(_workDirectory, _name + ".inp"); // must be first for the timer to work
//
_numOfRunSteps = numOfRunSteps;
_currentRunStep = -1;
//
_numOfRunIncrements = numOfRunIncrements;
_currentRunIncrement = -1;
//
_watch = new Stopwatch();
_watch.Start();
_prevWatchMilliseconds = 0;
//
SubmitNextRun();
}
private void SubmitNextRun()
{
// First run
if (_currentRunStep == -1)
{
_currentRunStep = 1;
_currentRunIncrement = 1;
}
// Other runs
else
{
_currentRunIncrement++;
//
if (_currentRunIncrement > _numOfRunIncrements)
{
_currentRunIncrement = 1;
_currentRunStep++;
}
}
//
if (_currentRunStep <= _numOfRunSteps && (_jobStatus == JobStatus.None || _jobStatus == JobStatus.OK))
{
PreRun?.Invoke(this);
SubmitOneRun();
}
else AllRunsCompleted();
}
private void SubmitOneRun()
{
if (_myLock == null) _myLock = new object();
lock (_myLock)
{
if (_sbOutput == null) _sbOutput = new StringBuilder();
_sbOutput.Clear();
//
if (_sbAllOutput == null) _sbAllOutput = new StringBuilder();
_sbAllOutput.Clear();
}
//
AppendDataToOutput(DateTime.Now + Environment.NewLine);
AppendDataToOutput("######## Starting run step number: " + _currentRunStep +
" Increment number: " + _currentRunIncrement + " ########" + Environment.NewLine);
AppendDataToOutput("Running command: " + _executable + " " + GetArgument());
//
_datFileLength = -1;
_datFileToLong = false;
_datFileContents = "";
//
_statusFileLength = -1;
_statusFileContents = "";
//
_convergenceFileLength = -1;
_convergenceFileContents = "";
//
_jobStatus = JobStatus.Running;
//
JobStatusChanged?.Invoke(_name, _jobStatus);
//
if (_useBackgroundWorker)
{
using (BackgroundWorker bwStart = new BackgroundWorker())
{
bwStart.DoWork += bwStart_DoWork;
bwStart.RunWorkerCompleted += bwStart_RunWorkerCompleted;
if (!bwStart.IsBusy) bwStart.RunWorkerAsync();
}
}
else
{
bwStart_DoWork(null, null);
bwStart_RunWorkerCompleted(null, null);
}
}
private void bwStart_DoWork(object sender, DoWorkEventArgs e)
{
string fileName = Path.GetFileName(Name);
_outputFileName = Path.Combine(_workDirectory, "_output_" + fileName + ".txt");
_errorFileName = Path.Combine(_workDirectory, "_error_" + fileName + ".txt");
//
if (File.Exists(_outputFileName)) File.Delete(_outputFileName);
if (File.Exists(_errorFileName)) File.Delete(_errorFileName);
//
if (Tools.IsWindows10orNewer() && !_compatibilityMode) Run_Win10();
else Run_OldWin();
}
private void bwStart_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bool resultsExist = false;
if (_femSolver == FEMSolverEnum.Calculix)
{
string resultsFileName = ResultsFileName;
if (File.Exists(resultsFileName))
{
long length = new FileInfo(resultsFileName).Length;
if (length > 15 * 20) resultsExist = true;
}
}
else if (_femSolver == FEMSolverEnum.Abaqus)
{
string odbFailFileName = Path.Combine(WorkDirectory, _name + ".odb_f");
if (!File.Exists(odbFailFileName)) resultsExist = true;
}
else throw new NotSupportedException();
//
bool continueAnalysis = false;
AppendDataToOutput("");
if (_jobStatus == JobStatus.OK)
{
if (!resultsExist && !(ContainsNoAnalysis(_sbOutput.ToString()) || ContainsNoAnalysis(_sbAllOutput.ToString())))
{
AppendDataToOutput(" Job failed - no results exist.");
_jobStatus = JobStatus.Failed;
}
else if (ContainsError(_sbOutput.ToString()) || ContainsError(_sbAllOutput.ToString()))
{
_jobStatus = JobStatus.FailedWithResults;
}
else
{
PostRun?.Invoke(this);
continueAnalysis = true;
}
}
else if (_jobStatus == JobStatus.Killed)
{
AppendDataToOutput(" Job killed.");
}
else if (_jobStatus == JobStatus.Failed)
{
AppendDataToOutput(" Job failed.");
if (resultsExist) _jobStatus = JobStatus.FailedWithResults;
}
//
if (continueAnalysis) SubmitNextRun();
else AllRunsCompleted();
}
private bool ContainsError(string text)
{
if (_femSolver == FEMSolverEnum.Calculix)
{
//*ERROR reading *DYNAMIC: initial increment size exce eds step size
if (text.Contains("*ERROR"))
{
if (text.Contains("*ERROR reading *DYNAMIC: initial increment size"))
return text.AllIndicesOf("*ERROR").Count() > 1;
else return true;
}
}
else if (_femSolver == FEMSolverEnum.Abaqus)
{
if (text.Contains("Abaqus/Analysis exited with errors")) return true;
}
else throw new NotSupportedException();
//
return false;
}
private bool ContainsNoAnalysis(string text)
{
//*ERROR reading *DYNAMIC: initial increment size exceeds step size
if (text.Contains("*WARNING: no analysis option was chosen")) return true;
else return false;
}
private void AllRunsCompleted()
{
_watch.Stop();
//
AppendDataToOutput("");
AppendDataToOutput("Process elapsed time: " + Math.Round(_watch.Elapsed.TotalSeconds, 3).ToString() + " s");
//AppendDataToOutput(" Peak physical memory usage: " + (Math.Round(_peakWorkingSet / 1048576.0, 3)).ToString() + " MB");
//AppendDataToOutput(" Peak paged memory usage: " + (Math.Round(_peakPagedMem / 1048576.0, 3)).ToString() + " MB");
//Console.WriteLine($" Peak virtual memory usage : {_peakVirtualMem / 1024 / 1024}");
//
Timer_Tick(null, null);
SendDataToOutput();
//
JobStatusChanged?.Invoke(_name, _jobStatus);
LastRunCompleted?.Invoke(this);
//
_endTime = DateTime.Now + TimeSpan.FromSeconds(1);
// Dereference the links to other objects
DataOutputEvent = null;
JobStatusChanged = null;
PreRun = null;
PostRun = null;
LastRunCompleted = null;
}
private void Run_Test()
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = @"C:\Temp\test.bat";
////psi.Arguments = _argument;
//psi.WorkingDirectory = _workDirectory;
//psi.UseShellExecute = false;
////
////SetEnvironmentVariables(psi);
////
_exe = new Process();
_exe.StartInfo = psi;
_exe.Start();
////
int ms = 1000 * 3600 * 24 * 7 * 3; // 3 weeks
if (_exe.WaitForInputIdle(ms))
{
// Process completed. Check process.ExitCode here.
// after Kill() _jobStatus is Killed
_jobStatus = JobStatus.OK;
}
else
{
// Timed out.
Kill("Time out.");
//Debug.WriteLine(DateTime.Now + " Timeout proces: " + Name + " in: " + _workDirectory);
_jobStatus = JobStatus.TimedOut;
}
_exe.Close();
}
private void Run_OldWin()
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = _executable;
psi.Arguments = GetArgument();
psi.WorkingDirectory = _workDirectory;
psi.UseShellExecute = false;
//
//SetEnvironmentVariables(psi);
//
_exe = new Process();
_exe.StartInfo = psi;
_exe.Start();
//
int ms = 1000 * 3600 * 24 * 7 * 3; // 3 weeks
if (_exe.WaitForExit(ms))
{
// Process completed. Check process.ExitCode here.
// after Kill() _jobStatus is Killed
_jobStatus = JobStatus.OK;
}
else
{
// Timed out.
Kill("Time out.");
//Debug.WriteLine(DateTime.Now + " Timeout proces: " + Name + " in: " + _workDirectory);
_jobStatus = JobStatus.TimedOut;
}
_exe.Close();
}
private void Run_Win10()
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.CreateNoWindow = true;
psi.FileName = _executable;
//
psi.Arguments = GetArgument();
psi.WorkingDirectory = _workDirectory;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
//
SetEnvironmentVariables(psi);
//
_exe = new Process();
_exe.StartInfo = psi;
//
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
_exe.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
// the safe wait handle closes on kill
if (!outputWaitHandle.SafeWaitHandle.IsClosed) outputWaitHandle.Set();
}
else
{
AppendDataToOutput(e.Data);
}
};
//
_exe.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
// the safe wait handle closes on kill
if (!errorWaitHandle.SafeWaitHandle.IsClosed) errorWaitHandle.Set();
}
else
{
File.AppendAllText(_errorFileName, e.Data + Environment.NewLine);
AppendDataToOutput(e.Data);
}
};
//
_exe.Start();
//
_exe.BeginOutputReadLine();
_exe.BeginErrorReadLine();
int ms = 1000 * 3600 * 24 * 7 * 3; // 3 weeks
if (_exe.WaitForExit(ms) && outputWaitHandle.WaitOne(ms) && errorWaitHandle.WaitOne(ms))
{
// Process completed. Check process.ExitCode here.
// after Kill() _jobStatus is Killed
if (_jobStatus != JobStatus.Killed) _jobStatus = JobStatus.OK;
}
else
{
// Timed out.
Kill("Time out.");
//Debug.WriteLine(DateTime.Now + " Timeout proces: " + Name + " in: " + _workDirectory);
_jobStatus = JobStatus.TimedOut;
}
_exe.Close();
// Abaqus
//if (_femSolver == FEMSolverEnum.Abaqus)
//{
// string fileName = Path.Combine(_workDirectory, Name + ".dat");
// if (File.Exists(fileName))
// {
// AppendDataToOutput(Environment.NewLine +
// "######## ABAQUS .dat FILE CONTENT ########" +
// Environment.NewLine);
// AppendDataToOutput(File.ReadAllText(fileName));
// }
//}
}
}
public void Kill(string message)
{
try
{
if (_exe != null)
{
if (message != "The string builder run out of space.") AppendDataToOutput(message);
//
_watch.Stop();
//
try
{
UInt32 id = (UInt32)_exe.Id;
KillAllProcessesSpawnedBy(id);
if (!_exe.HasExited) _exe.Kill(); // must be here
}
catch { }
}
}
finally
{
_jobStatus = JobStatus.Killed;
}
}
public static void KillAllProcessesSpawnedBy(UInt32 parentProcessId)
{
// NOTE: Process Ids are reused!
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"SELECT * " +
"FROM Win32_Process " +
"WHERE ParentProcessId=" + parentProcessId);
ManagementObjectCollection collection = searcher.Get();
if (collection.Count > 0)
{
foreach (var item in collection)
{
UInt32 childProcessId = (UInt32)item["ProcessId"];
if ((int)childProcessId != Process.GetCurrentProcess().Id)
{
KillAllProcessesSpawnedBy(childProcessId);
//
try
{
Process childProcess = Process.GetProcessById((int)childProcessId);
childProcess.Kill();
}
catch
{
}
}
}
}
}
//
public string GetAllOutputData()
{
try
{
if (_sbAllOutput != null) return _sbAllOutput.ToString();
else return null;
}
catch
{
return null;
}
}
private void SendDataToOutput()
{
if (_myLock == null) _myLock = new object();
lock (_myLock)
{
string outputData = _sbOutput.ToString();
//
if (_outputFileName != null) File.AppendAllText(_outputFileName, outputData);
//
GetDatFileContents();
GetStatusFileContents();
GetConvergenceFileContents();
//
DataOutputEvent?.Invoke(this, outputData);
//
if (_sbAllOutput.Length > 2_000_000_000) Kill("The string builder run out of space.");
//
_sbAllOutput.Append(_sbOutput);
_sbOutput.Clear();
}
}
private void AppendDataToOutput(string data)
{
if (_myLock == null) _myLock = new object();
lock (_myLock)
{
Application.DoEvents();
_sbOutput.AppendLine(data);
}
//
if (_watch.ElapsedMilliseconds - _prevWatchMilliseconds > 1000)
{
SendDataToOutput();
_prevWatchMilliseconds = _watch.ElapsedMilliseconds;
}
}
private void GetDatFileContents()
{
try
{
if (!_datFileToLong)
{
string datFileName = Path.Combine(_workDirectory, Name + ".dat");
if (!File.Exists(datFileName)) return;
//
long size = new FileInfo(datFileName).Length;
//
if (size != _datFileLength)
{
using (FileStream fileStream = new FileStream(datFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader streamReader = new StreamReader(fileStream))
{
_datFileContents = streamReader.ReadToEnd();
}
}
_datFileLength = size;
}
//
int sizeLimit = 100_000;
if (_datFileLength > sizeLimit)
{
if (!_datFileToLong) // first time
{
_datFileContents = _datFileContents.Substring(0, sizeLimit);
_datFileContents += Environment.NewLine + Environment.NewLine +
"Warning: .dat file is to log to be displayed in the Monitor form.";
}
_datFileToLong = true;
}
}
}
catch
{
}
}
private void GetStatusFileContents()
{
try
{
string statusFileName = Path.Combine(_workDirectory, Name + ".sta");
if (!File.Exists(statusFileName)) return;
//
long size = new FileInfo(statusFileName).Length;
//
if (size != _statusFileLength)
{
using (FileStream fileStream = new FileStream(statusFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader streamReader = new StreamReader(fileStream))
{
_statusFileContents = streamReader.ReadToEnd();
}
}
_statusFileLength = size;
}
}
catch
{
}
}
private void GetConvergenceFileContents()
{
try
{
string convergenceFileName = Path.Combine(_workDirectory, Name + ".cvg");
if (!File.Exists(convergenceFileName)) return;
//
long size = new FileInfo(convergenceFileName).Length;
//
if (size != _convergenceFileLength)
{
using (FileStream fileStream = new FileStream(convergenceFileName, FileMode.Open, FileAccess.Read,
FileShare.ReadWrite))
{
using (StreamReader streamReader = new StreamReader(fileStream))
{
_convergenceFileContents = streamReader.ReadToEnd();
}
}
_convergenceFileLength = size;
}
}
catch
{
}
}
//
public void ClearFileContents()
{
_datFileLength = 0;
_datFileContents = "";
_statusFileLength = 0;
_statusFileContents = "";
_convergenceFileLength = 0;
_convergenceFileContents = "";
}
//
public static bool IsAdministrator()
{
System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);
// DOMAINNAME\Domain Admins RID: 0x200
return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator) || principal.IsInRole(0x200);
}
public void ResetJobStatus()
{
_jobStatus = JobStatus.None;
}
//
private void SetEnvironmentVariables(ProcessStartInfo psi)
{
SetNumberOfProcessors(psi);
if (_environmentVariables != null)
{
foreach (var environmentVariable in _environmentVariables)
{
SetEnvironmentVariable(psi, environmentVariable);
}
}
}
private void SetNumberOfProcessors(ProcessStartInfo psi)
{
EnvironmentVariable numberOfProcessors = new EnvironmentVariable("OMP_NUM_THREADS", _numCPUs.ToString());
SetEnvironmentVariable(psi, numberOfProcessors);
}
private void SetEnvironmentVariable(ProcessStartInfo psi, EnvironmentVariable environmentVariable)
{
try
{
if (environmentVariable.Active)
{
if (psi.EnvironmentVariables.ContainsKey(environmentVariable.Name)) psi.EnvironmentVariables.Remove(environmentVariable.Name);
psi.EnvironmentVariables.Add(environmentVariable.Name, environmentVariable.Value);
if (!psi.EnvironmentVariables.ContainsKey(environmentVariable.Name)) throw new Exception();
}
}
catch
{
AppendDataToOutput("To add environmental variable '" + environmentVariable.Name + "' to the analysis the program must be run with elevated permisions (Run as administrator).");
}
}
private string GetArgument()
{
string argument = "";
if (_femSolver == FEMSolverEnum.Calculix) argument = _argument;
else if (_femSolver == FEMSolverEnum.Abaqus)
{
if (_onlyCheckModel) argument = "datacheck ";
argument += "interactive ask_delete=OFF ";
if (_numCPUs > 1) argument += "cpus=" + _numCPUs + " ";
argument += _argument;
}
else throw new NotSupportedException();
//
return argument;
}
// ISerialization
public new void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
// Using typeof() works also for null fields
info.AddValue("_workDirectory", _workDirectory, typeof(string));
info.AddValue("_executable", _executable, typeof(string));
info.AddValue("_argument", _argument, typeof(string));
info.AddValue("_compatibilityMode", _compatibilityMode, typeof(bool));
info.AddValue("_jobStatus", _jobStatus, typeof(JobStatus));
info.AddValue("_numCPUs", _numCPUs, typeof(int));
info.AddValue("_environmentVariables", _environmentVariables, typeof(List<EnvironmentVariable>));
info.AddValue("_datFileLength", _datFileLength, typeof(long));
info.AddValue("_datFileContents", _datFileContents, typeof(string));
info.AddValue("_statusFileLength", _statusFileLength, typeof(long));
info.AddValue("_statusFileContents", _statusFileContents, typeof(string));
info.AddValue("_convergenceFileLength", _convergenceFileLength, typeof(long));
info.AddValue("_convergenceFileContents", _convergenceFileContents, typeof(string));
info.AddValue("_endTime", _endTime, typeof(DateTime));
info.AddValue("_femSolver", _femSolver, typeof(FEMSolverEnum));
info.AddValue("_onlyCheckModel", _onlyCheckModel, typeof(bool));
}
}
}