Solved

When running batch ray trace inside a loop in C#, ReadNextResultFull fails after first iteration

  • 21 March 2023
  • 7 replies
  • 160 views

Hello fellow Zemax ZOS-API users!

 

I’m getting my hands dirty with the ZOS-API, and I’m currently running a C# code to allow me to use batch ray trace. This reproduces my  input object onto my output image plane very nicely. However, I then tried to put this into a for loop over the range of thicknesses I want to conisder for one eleemnt in my system. I’m using directpol, and the addrays and readnextresults and ReadNextResultFull, and the method runs perfectly fine on the first lop iteration, but then fails for the concurrent lops. I tried to run the program by putting the loop inside the C# code and by calling it from an external program (MATLAB using system command) but in both cases, the success line fails after the first iteration, even though in MATLAB I am asking for a brand new instance of the C# code. to run. So I am stuck running it one parameter at a time, which is not what I want to do. Anyone else facing this problem?

 

Here is a copy of the relevant part of my C# file:

var z_offset_mm = new double[] { 1 };

foreach (var z in z_offset_mm)
{
// Create the initial connection class
ZOSAPI_Connection TheConnection = new ZOSAPI_Connection();

// Attempt to create a Standalone connection
IZOSAPI_Application TheApplication = TheConnection.CreateNewApplication();
if (TheApplication == null)
{
HandleError("An unknown connection error occurred!");
return;
}

// Check the connection status
if (!TheApplication.IsValidLicenseForAPI)
{
HandleError("Failed to connect to OpticStudio: " + TheApplication.LicenseStatus);
return;
}
if (TheApplication.Mode != ZOSAPI_Mode.Server)
{
HandleError("User plugin was started in the wrong mode: expected Server, found " + TheApplication.Mode.ToString());
return;
}

//open the system
IOpticalSystem TheSystem = TheApplication.PrimarySystem;
TheSystem.LoadFile(model, false);

ILensDataEditor TheLDE = TheSystem.LDE;

//first surface is dummy that we can alter thickness
TheLDE.GetSurfaceAt(1).Thickness = z;

//move to center wavelength and delete all other wavelengths if any
ZOSAPI.SystemData.IWavelengths sysWave = TheSystem.SystemData.Wavelengths;
var nW = sysWave.NumberOfWavelengths;
for (int i = 1; i <= nW; i++)
{
try
{
sysWave.RemoveWavelength(i);
}
catch
{
Console.WriteLine("no more wavelengths");
}
}
var w = 0.405;
sysWave.GetWavelength(1).Wavelength = w;

// apply filter coating to these surfaces
int index_wavelength = centerWavelength.FindIndex(a => a == w);
for (int i = 10; i <= 14; i++)
{
TheSystem.LDE.GetSurfaceAt(i).Coating = filters[index_wavelength];
}

// set up batch ray to ressemble what we have physically for the reference target
//load image thats the right size, so that each pixel represents a 0 for dark pixel, or a 1 for light pixel
var l = 11;//mm for the image height and width
var n = 3036/10; //number of pixels for image, take it down to a tenth the pixels otherwise this is going to take forever

var xl = linspace(-l / 2, l / 2, n);
var yl = linspace(-l / 2, l / 2, n);

//read mask csv
var path = "C:\\Users\\AlexanderDumont\\OneDrive - Cytoveris Inc\\Documents\\R&D\\Reference Checks Analysis\\mask.csv";
var listPixelsMask = new List<List<int>>();
string[] lines = System.IO.File.ReadAllLines(path);
foreach (string line in lines)
{
string[] columns = line.Split(',');
var colInt = Array.ConvertAll(columns,int.Parse);
listPixelsMask.Add(colInt.ToList());
}

// Set up Batch Ray Trace
ZOSAPI.Tools.RayTrace.IBatchRayTrace raytrace = TheSystem.Tools.OpenBatchRayTrace();
int nsur = TheSystem.LDE.NumberOfSurfaces;
var dir_x = linspace(-.1f, .1f, 10);
var dir_y = linspace(-.1f, .1f, 10);
int max_rays = n * n * dir_x.Length * dir_y.Length;
//count up all positions and angles to lauch from
var c = 0;
for (int i = 0; i < xl.Length; i++)
{
for (int j = 0; j < yl.Length; j++)
{
if (listPixelsMask[i][j] > 0)
{
//then we have surface to launch from so proceed
for (int dx = 0; dx < dir_x.Length; dx++)
{
for (int dy = 0; dy < dir_y.Length; dy++)
{
c++;
}
}
}
}
}
Console.WriteLine("# of rays simulated in batch trace: " + c);

var directPolData = raytrace.CreateDirectPol(c, ZOSAPI.Tools.RayTrace.RaysType.Real, 1, 0, 0, 0, 0, nsur-1);

List<double[]> inputParameters = new List<double[]>();

for (int i = 0; i < xl.Length; i++)
{
for(int j = 0;j < yl.Length; j++)
{
if (listPixelsMask[i][j] > 0)
{
//then we have surface to launch from so proceed
for (int dx = 0; dx < dir_x.Length; dx++)
{
for (int dy = 0; dy < dir_y.Length; dy++)
{
//does ray hit lens, if not then dont consider it
var x = xl[i];
var y = yl[j];
//we have an angle relative to the vertical position
var vector_direction = new double[] { dir_x[dx], dir_y[dy] , 1 };
vector_direction = vector_direction.Select(item => item*item).ToArray();
var vector_sum = vector_direction.Sum();
vector_direction = vector_direction.Select(item=>item / vector_sum).ToArray();
//collect input data
inputParameters.Add(new double[] { xl[i], yl[j], 0, vector_direction[0], vector_direction[1], vector_direction[2] });
//add to batch ray trace
directPolData.AddRay(0, xl[i], yl[j], 0, vector_direction[0], vector_direction[1], vector_direction[2]);
}
}
}
}
}
//save input parameters to file
var inputFile = @"C:\\Users\\AlexanderDumont\\OneDrive - Cytoveris Inc\\Documents\\R&D\\Reference Checks Analysis\\input.txt";
using (var writer = new StreamWriter(inputFile))
{
foreach(var item in inputParameters)
{
foreach(var col in item)
{
writer.Write(col + ",");
}
writer.WriteLine();
}
}
raytrace.RunAndWaitForCompletion();
// Read batch raytrace and save results
directPolData.StartReadingResults();
int rayNumber, ErrorCode, vignetteCode;
double xo, yo, zo, lo, mo, no, exr, exi, eyr, eyi, ezr, ezi, intensity;
bool success;

success = directPolData.ReadNextResultFull(out rayNumber, out ErrorCode, out vignetteCode, out xo, out yo, out zo, out lo, out mo, out no, out exr, out exi, out eyr, out eyi, out ezr, out ezi, out intensity);
///save output to file as well
List<double[]> outputParameters = new List<double[]>();
outputParameters.Add(new double[] {rayNumber, xo,yo,zo,lo,mo,no,exr,exi,eyr,eyi,ezr,ezi,intensity });
while (success)
{
success = directPolData.ReadNextResultFull(out rayNumber, out ErrorCode, out vignetteCode, out xo, out yo, out zo, out lo, out mo, out no, out exr, out exi, out eyr, out eyi, out ezr, out ezi, out intensity);
outputParameters.Add(new double[] { rayNumber, xo, yo, zo, lo, mo, no, exr, exi, eyr, eyi, ezr, ezi, intensity });
}
var outputFile = @"C:\\Users\\AlexanderDumont\\OneDrive - Cytoveris Inc\\Documents\\R&D\\Reference Checks Analysis\\output_" + z + ".txt";
using (var writer = new StreamWriter(outputFile))
{
foreach (var item in outputParameters)
{
foreach (var col in item)
{
writer.Write(col + ",");
}
writer.WriteLine();
}
}
//TheSystem.Save();
FinishStandaloneApplication(TheApplication);
}

 

 

icon

Best answer by David.Nguyen 21 March 2023, 12:34

View original

7 replies

Userlevel 7
Badge +2

Hi Alexander,

 

I haven’t looked at the code in detail, but I might be able to give you a lead. You are calling the method TheSystem.Tools.OpenBatchRayTrace(); multiple times troughout your loop. However, you are not closing the tool in every iteration. This is a problem because OpticStudio can only have a single tool open at any one time. You should either open the batch ray trace outside the loop, or close it at the end of each iteration. Does that make sense? I hope this helps.

 

Take care,


David

Ahhh I knew it must be something simple like this thank you sir!

Userlevel 7
Badge +2

Well, I’m not hundred percent sure, so you should try it before. But if it helps you then I’m happy :)

Take care,

 

David

Hi Dave 

 

Just a quick update, but that did not solve my problem. I’m still looking back at the code, though, as I think you are correct, there is something I am not closing that remains open and blocks up the ray trace the second time around. 

Userlevel 6
Badge +2

Hey Alexander,

Can you try to pull your connection outside your for loop?  I believe you are trying to connect to OpticStudio, run a simulation, (not close your current connection) and then reconnect on the same class.  This is probably throwing the error:

// Create the initial connection class
ZOSAPI_Connection TheConnection = new ZOSAPI_Connection();

// Attempt to create a Standalone connection
IZOSAPI_Application TheApplication = TheConnection.CreateNewApplication();
if (TheApplication == null)
{
HandleError("An unknown connection error occurred!");
return;
}

// Check the connection status
if (!TheApplication.IsValidLicenseForAPI)
{
HandleError("Failed to connect to OpticStudio: " + TheApplication.LicenseStatus);
return;
}
if (TheApplication.Mode != ZOSAPI_Mode.Server)
{
HandleError("User plugin was started in the wrong mode: expected Server, found " + TheApplication.Mode.ToString());
return;
}

Try looking at Samples 22 & 23 for batch ray tracing examples inside a loop with C#.

I took the initialization and destruction functions out of the loop, so the only thing I have inside the loop is the batch ray trace initialization and reading, but it gives me this error now even though I clear the data before going through this process. This happens on the second loop and the first loop behaves just as expected. 

I initialize batch rayu trace and clear data as folllows:

            foreach (var z in z_offset_mm)
{

// Set up Batch Ray Trace
IBatchRayTrace raytrace = TheSystem.Tools.OpenBatchRayTrace();

// set up direct polarized batch ray trace
var directPolData = raytrace.CreateDirectPol(count_rays_launched, RaysType.Real, 1, 0, 0, 0, 0, nsur - 1);

Console.WriteLine("# of rays simulated in batch trace: " + c);

//first surface is dummy that we can alter thickness so alter thickness
TheLDE.GetSurfaceAt(1).Thickness = z;

//clear data in ray trace and fil it back up
directPolData.ClearData();

So I’m gessing that somehow, even though I clear the data, it’s still in the memory and just oiverloads my memory. Not sure how to proceed with this problem. I’ve attached my entire C# script if anyone wants to take a look at it. 

Alex

Okay, that error is acutally due to just asking the ray batch trace to store too much rays in its memory, overflowing the program. When I reduce the number of rays, the problem goes away. Houff. Thank you everyone for your helpful answers. 

 

Alex

Reply