Skip to main content

Hello everyone,

 

EDIT: I was wrong, NPRO’s last parameter is actually the wave number as pointed out by @MichaelH below. Therefore, there’s no need to use a user-defined operand

EDIT: new version available in my last reply below!

 

I have made a user operand equivalent to INDX for non-sequential systems.

In non-sequential systems, INDX doesn’t work, and one workaround is to use a ZPL operand with the numeric function NPRO using the code 200 (index of refraction of an object). For some time, I used the following code in a ZPLM (I hope the code is self-explanatory but let me know otherwise):

object = PVHX()

OPTRETURN 0, NPRO(1, object, 200, 0)

However, if one has multiple wavelengths defined, it always seem to default to the first one (wave number: 1), and there’s no direct possibility to specify a wavelength in NPRO, whereas this is possible with INDX.

A work around is to use the Multi-Configuration Editor with the operand WAVE and a single wavelength defined in the System Explorer. That way, one can use a CONF operand before ZPLM to specify which configuration needs to be considered. However, this is not always desirable, which is why I made a C# user-operand that calculates the non-sequential refractive index with the wave number as a paramter. The complete code is available on my GitHub, but here is the important part:

// Add your custom code here...

// Object number from which to evaluate material index
int object_number = (int)Hx;

// Wave number at which to evaluate material index
int wave_number = (int)Hy;

// Actual wavelength
double wavelength = TheSystem.SystemData.Wavelengths.GetWavelength(wave_number).Wavelength;

// Wavelength squared
double wavel_squared = wavelength * wavelength;

// Catalog number (following look-up "switch" below, e.g. 1 = Schott)
int catalog_number = (int)Px;

// Catalog look-up
string catalog = "";
switch(catalog_number)
{
case 1:
catalog = "Schott";
break;
// Add other catalogs here
// ...
}

// Get Material name
string material = TheSystem.NCE.GetObjectAt(object_number).Material;

// Open >> Librairies..Materials Catalog
IMaterialsCatalog material_cat = TheSystem.Tools.OpenMaterialsCatalog();

// Select catalog and material
material_cat.SelectedCatalog = catalog;
material_cat.SelectedMaterial = material;

// Run Materials Catalog
material_cat.RunAndWaitForCompletion();

// Initialize dummy refractive index value
double refractive_index = -1.0;

// Look-up index formula
switch (material_cat.MaterialFormula)
{
// Sellmeier 1
case MaterialFormulas.Sellmeier1:
// Initialize fit coefficients
double K1, K2, K3, L1, L2, L3;

// Get fit coefficients
K1 = material_cat.GetFitCoefficient(0);
K2 = material_cat.GetFitCoefficient(2);
K3 = material_cat.GetFitCoefficient(4);
L1 = material_cat.GetFitCoefficient(1);
L2 = material_cat.GetFitCoefficient(3);
L3 = material_cat.GetFitCoefficient(5);

// Refractive index calculation
refractive_index = K1 / (wavel_squared - L1);
refractive_index += K2 / (wavel_squared - L2);
refractive_index += K3 / (wavel_squared - L3);
refractive_index *= wavel_squared;
refractive_index += 1.0;
refractive_index = Math.Sqrt(refractive_index);

break;
// Add other formulas here
// ...
}

// Close Materials Catalog
material_cat.Close();

operandResults>0] = refractive_index;

As you can see, I’ve only implemented the Schott catalog, which only uses the Sellmeier 1 formula, but we can add the other catalogs if people are interested.

The operand parameters are Hx: Object number, Hy: Wave number, Px: Catalog number (Schott = 1). And here is an example with N-BK7:

And the comparison with INDX in the same settings (Surface 2 is N-BK7 and F, d, C wavelength preset):

I’m also attaching the compiled operand UDOC06.exe file to my post.

Take care,

PS: there’s no error trapping. Avoid specifying an object number that hasn’t a material defined and use a wave number > 0

 

David

Hi @David.Nguyen! Thank you. This is great. I tested and it works well.

Since I did the mistake this morning, I thought I’ll share. Copy the exe under {Zemax}\ZOS-API\Operands. If it is not in the right folder (and so if OpticStudio can’t find it), you will get a ShellExcute Error.

 


Hi @Sandrine Auriol,

 

Thank you for your message, I hope you are well :)


It should be possible to make a similar operand that searches the material in the glass catalogs, like we did in this post:

That way, we don’t have to specify the vendor to the catalog tool.

Take care,

 

David


Hi everyone,

 

I made a second version of the code (and updated my GitHub repository) where you don’t need to specify the wave number. Instead, you can use the Data field to select what wave number you are interested in:

// Add your custom code here...

// Object number from which to evaluate material index
int object_number = (int)Hx;

// Number of wavelengths
int number_of_wavelengths = TheSystem.SystemData.Wavelengths.NumberOfWavelengths;

// Array of wavelengths
doubleu] wavelengths = new doubleunumber_of_wavelengths];
double wavel_squared = 0;

for (int ii = 0; ii < number_of_wavelengths; ii++)
{
wavelengthsgii] = TheSystem.SystemData.Wavelengths.GetWavelength(ii+1).Wavelength;
}

// Initialize array of refractive indices
doubleu] indices = new doubleunumber_of_wavelengths];

// Catalog number (following look-up "switch" below, e.g. 1 = Schott)
int catalog_number = (int)Hy;

// Catalog look-up
string catalog = "";
switch(catalog_number)
{
case 1:
catalog = "Schott";
break;
// Add other catalogs here
// ...
}

// Get Material name
string material = TheSystem.NCE.GetObjectAt(object_number).Material;

// Open >> Librairies..Materials Catalog
IMaterialsCatalog material_cat = TheSystem.Tools.OpenMaterialsCatalog();

// Select catalog and material
material_cat.SelectedCatalog = catalog;
material_cat.SelectedMaterial = material;

// Run Materials Catalog
material_cat.RunAndWaitForCompletion();

// Look-up index formula
switch (material_cat.MaterialFormula)
{
// Sellmeier 1
case MaterialFormulas.Sellmeier1:
// Initialize fit coefficients
double K1, K2, K3, L1, L2, L3;

// Get fit coefficients
K1 = material_cat.GetFitCoefficient(0);
K2 = material_cat.GetFitCoefficient(2);
K3 = material_cat.GetFitCoefficient(4);
L1 = material_cat.GetFitCoefficient(1);
L2 = material_cat.GetFitCoefficient(3);
L3 = material_cat.GetFitCoefficient(5);

// Refractive index calculation
for (int ii = 0; ii < number_of_wavelengths; ii++)
{
wavel_squared = wavelengthsgii] * wavelengthsgii];
indicesiii] = K1 / (wavel_squared - L1);
indicesiii] += K2 / (wavel_squared - L2);
indicesiii] += K3 / (wavel_squared - L3);
indicesiii] *= wavel_squared;
indicesiii] += 1.0;
indicesiii] = Math.Sqrt(indicesiii]);
}

break;
// Add other formulas here
// ...
}

// Close Materials Catalog
material_cat.Close();

// Return indices
for (int ii = 0; ii < number_of_wavelengths; ii++)
{
operandResultsuii] = indicesiii];
}

The corresponding result is as follow:

As you can see, the Data column corresponds to the wave number and the operand is calculated only once for all the results. I’m also attaching the *.exe to my reply.

Take care,

 

David


Added support for MISC catalog and Schott formula


 

Hey David,

Thanks for all the code and always sharing your tips.  Regarding the very first part about NPRO though, can’t you just just change the 4th parameter to be the wavenumber for the 200 data value?  

I can put this into a ZPLM where Hx = Object and Data > 0 is the wavenumber (I really like your idea of putting operandResults in a FOR loop!!!):

FOR i = 1, NWAV(), 1
OPTRETURN i, NPRO(1, PVHX(), 200, i)
NEXT

For FdC light, I get the following output:

 


Dear Michael,

 

Thank you for your reply. I somehow didn’t realized you could use the fourth parameter to specify the wave number in NPRO. Thank you for pointing it out to me. I guess the user-operand is irrelevant now. I’ll update my post.

Take care,

 

David


Reply