Skip to main content

ZPL: Export Sequential to Speos Reduced Order Model (ROM) OptDistortionV1

  • November 27, 2025
  • 1 reply
  • 42 views

ZachDerocher

Example ZPL script to generate a Speos ROM V1 (.optdistortion) file from sequential Zemax.

Please see the printed warning regarding UTF encoding before importing the resulting ROM into Speos.

1 reply

MichaelH
Ansys Staff
Forum|alt.badge.img+2
  • Ansys Staff
  • December 1, 2025

Hey Zach, 

This is a great macro and I love seeing the interoperability between OpticStudio and Speos increase.  Since the major limitation of the current macro is converting the OpticStudio output of UTF-16 to Speos input of UTF-8, I think you can add something like the following code to your v2 to allow PowerShell/.NET to automatically convert between the encoding formats.  Starting with Windows 10, PowerShell 5.1 is shipped with the OS and .NET is a prereq for OpticStudio, so this code should work on all computers that can install OpticStudio.

The logic of the code is as follows:

  • Generate the original .optdistortion file in the current macro
  • Write the 14 line PowerShell (.ps1) script to a file, defaulting to the ZPL directory (if it’s not already on disk)
    • The script takes 2 inputs:
      • -InputFile: the filename you want to convert to UTF-8
      • -WithBom: flag to convert to either UTF-8 or UTF-8 BOM (I wasn’t sure what Speos expects as an input) 
  • Use the COMMAND keyword to launch PowerShell and run the script
  • Saves the UTF-8 file to a temporary location, then deletes the original UTF-16 file and renames the new UTF-8 to the original filename

This assumes the input filename is the variable outfn$ so you should be able to copy & paste this code to the end of your macro and have it automatically convert to UTF-8.  

! generate the PS1 file (this could be done only once and cached if desired)
output_full$ = $MACROPATH(), "\convert.ps1"
OUTPUT output_full$
PRINT "param("
PRINT " [Parameter(Mandatory = $true)]"
PRINT " [string] $InputFile,"
PRINT " [switch] $WithBom"
PRINT ")"
PRINT "if (-not (Test-Path $InputFile)) {throw ('Input file not found: ' + $InputFile)}"
PRINT "$enc = New-Object System.Text.UTF8Encoding($WithBom.IsPresent)"
PRINT "$dir = Split-Path $InputFile"
PRINT "$temp = [IO.Path]::Combine($dir, [IO.Path]::GetRandomFileName())"
PRINT "$sw = New-Object System.IO.StreamWriter($temp, $false, $enc)"
PRINT "Get-Content $InputFile | ForEach-Object {$sw.WriteLine($_)}"
PRINT "$sw.Close()"
PRINT "Remove-Item $InputFile -Force"
PRINT "Rename-Item $temp $InputFile"
OUTPUT SCREEN

! need the full path of powershell.exe, not just what is in the ENVVAR
cmd$ = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "
args$ = " -file ", $QUOTE(), output_full$, $QUOTE(), " -InputFile ", $QUOTE(), outfn$, $QUOTE()
!args$ = " -file ", $QUOTE(), output_full$, $QUOTE(), " -InputFile ", $QUOTE(), input$, $QUOTE(), " -WithBom"

! convert to UTF-8
COMMAND cmd$, args$