// Command/procedure to document an achr set-up call cmd achrGenDoc( void ) { int OPass = Ocm[ 1 ]; int groupC = Ocm[ 2 ]; char nbrstr[ 129 ]; // Record the invocation sprintf( nbrstr, "achr %1d %1d %.3f %f %f %f %f %f %f", OPass, groupC, Ocm[ 3 ], Ocm[ 4 ], Ocm[ 5 ], Ocm[ 6 ], Ocm[ 7 ], Ocm[ 8 ], Ocm[ 9 ] ); printf( "\n%s\n", nbrstr ); sno6( nbrstr ); } // Command to erase the setup from the lens (save space) cmd achrerase( void ) { int stp_outp_sav = char_pref( outp ); set_preference( outp, off ); opt_oprdccl( def ); operands( new ); end( ); sno6( "" ); if( stp_outp_sav ) { set_preference( outp, on ); } } // Create optimization operands int achrOPass {default(noquery) = 1} int achrgroupC {default(noquery) = 0} double achrFno {default(noquery) = 8.0} double achrGLong {default(noquery) = 0.5} double achrOSCPhase {default(noquery) = -50.0} double achrSphAbPhase {default(noquery) = 22.0} double achrOZCorr {default(noquery) = 75.0} double achrGAstig {default(noquery) = 0.0} double achrLatOff {default(noquery) = 0.0} cmd achr( int achrOPass, int achrgroupC, double achrFno, double achrGLong, double achrOSCPhase, double achrSphAbPhase, double achrOZCorr, double achrGAstig, double achrLatOff ) { int stp_outp_sav = char_pref( outp ); int opnbr = 0; set_preference( outp, off ); // Record the invocation opt_oprdccl( "achropnds" ); operands( new ); // Invocation inputs ++opnbr; op( opnbr, ins, "OCM1 ", 0.0, "OPass" ); Ocm[ opnbr ] = achrOPass; ++opnbr; op( opnbr, ins, "OCM2 ", 0.0, "groupC" ); Ocm[ opnbr ] = achrgroupC; ++opnbr; op( opnbr, ins, "OCM3 ", 0.0, "Fno" ); Ocm[ opnbr ] = achrFno; ++opnbr; op( opnbr, ins, "OCM4 ", 0.0, "GLong" ); Ocm[ opnbr ] = achrGLong; ++opnbr; op( opnbr, ins, "OCM5 ", 0.0, "OSCPhase" ); Ocm[ opnbr ] = achrOSCPhase; ++opnbr; op( opnbr, ins, "OCM6 ", 0.0, "SphAbPhase" ); Ocm[ opnbr ] = achrSphAbPhase; ++opnbr; op( opnbr, ins, "OCM7 ", 0.0, "OZCorr" ); Ocm[ opnbr ] = achrOZCorr; ++opnbr; op( opnbr, ins, "OCM8 ", 0.0, "GAstig" ); Ocm[ opnbr ] = achrGAstig; ++opnbr; op( opnbr, ins, "OCM9 ", 0.0, "LatOff" ); Ocm[ opnbr ] = achrLatOff; achrGenDoc( ); // Other inputs ++opnbr; op( opnbr, ins, "OCM11", 0.0, "MTRD1" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM12", 0.0, "MTRD2" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM13", 0.0, "MTRD3" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM14", 0.0, "MTRD4" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM15", 0.0, "MTRD5" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM16", 0.0, "MTRD6" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM17", 0.0, "MTRD7" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM18", 0.0, "MTRD8" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM19", 0.0, "MTRD9" ); Ocm[ opnbr ] = 0.0; // Outputs ++opnbr; op( opnbr, ins, "OCM20", 0.1, "EFL" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM21", 1.0, "DMean" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM22", 1.0, "DBFL" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM23", 1.0, "LatColor" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM24", 0.1, "LongColor" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM25", 0.1, "AstigError" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM26", 1.0, "OSCError" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM27", 1.0, "SphError" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM28", 1.0, "ZonalError" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM31 - OCM11", 1.0, "Rtl1" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM32 - OCM12", 1.0, "Rtl2" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM33 - OCM13", 1.0, "Rtl3" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM34 - OCM14", 1.0, "Rtl4" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM35 - OCM15", 1.0, "Rtl5" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM36 - OCM16", 1.0, "Rtl6" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM37- OCM17", 1.0, "Rtl7" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM38 - OCM18", 1.0, "Rtl8" ); Ocm[ opnbr ] = 0.0; ++opnbr; op( opnbr, ins, "OCM39 - OCM19", 1.0, "Rtl9" ); Ocm[ opnbr ] = 0.0; end( ); if( stp_outp_sav ) { set_preference( outp, on ); } ose( ); } // Other (post-setup) invocations cmd achrOPass( int achrOPass ) { if( achrOPass >= 0 ) { Ocm[ 1 ] = achrOPass; } achrGenDoc( ); } cmd achrgroupC( int achrgroupC ) { if( achrgroupC >= 0 ) { Ocm[ 2 ] = achrgroupC; } achrGenDoc( ); } double achrMaxSpace {default(noquery) = 0.0} cmd achrgroupS( double achrMaxSpace ) { int lensnum; int srfnum; int lgroupC = 0; int ingroup = 0; int grppwr = 1; for( lensnum = 0, srfnum = 1; srfnum < ims && lensnum < 9; ++srfnum ) { if( ingroup ) { if( rn[ srfnum ][ 1 ] == 1.0 ) { if( th[ srfnum ] > achrMaxSpace ) { // End of the previous group lgroupC += grppwr * ( srfnum - ingroup ); grppwr *= 10; ingroup = 0; } } else { // MOTS ++lensnum; } } else { if( rn[ srfnum ][ 1 ] > 1.0 ) { // Start of a group ingroup = srfnum; ++lensnum; } else { //MOTS grppwr *= 10; } } } // Do the last group, if present if( ingroup ) { lgroupC += grppwr * ( ims - ingroup ); } // Set up the grouping. Ocm[ 2 ] = lgroupC; achrGenDoc( ); } int achrSet {list = achrSetList, default(noquery) = set} double achrDelt {default(noquery) = 0.0} cmd achrFno( int achrSet, double achrFno, double achrDelt ) { if( achrSet == 0 ) { Ocm[ 3 ] = achrFno; } else if( achrSet == 1 ) { Ocm[ 3 ] += achrDelt; } else { Ocm[ 3 ] -= achrDelt; } achrGenDoc( ); } cmd achrGLong( int achrSet, double achrGLong, double achrDelt ) { if( achrSet == 0 ) { Ocm[ 4 ] = achrGLong; } else if( achrSet == 1 ) { Ocm[ 4 ] += achrDelt; } else { Ocm[ 4 ] -= achrDelt; } achrGenDoc( ); } cmd achrOSCPhase( int achrSet, double achrOSCPhase, double achrDelt ) { if( achrSet == 0 ) { Ocm[ 5 ] = achrOSCPhase; } else if( achrSet == 1 ) { Ocm[ 5 ] += achrDelt; } else { Ocm[ 5 ] -= achrDelt; } achrGenDoc( ); } cmd achrSphAbPhase( int achrSet, double achrSphAbPhase, double achrDelt ) { if( achrSet == 0 ) { Ocm[ 6 ] = achrSphAbPhase; } else if( achrSet == 1 ) { Ocm[ 6 ] += achrDelt; } else { Ocm[ 6 ] -= achrDelt; } achrGenDoc( ); } cmd achrOZCorr( int achrSet, double achrOZCorr, double achrDelt ) { if( achrSet == 0 ) { Ocm[ 7 ] = achrOZCorr; } else if( achrSet == 1 ) { Ocm[ 7 ] += achrDelt; } else { Ocm[ 7 ] -= achrDelt; } achrGenDoc( ); } cmd achrGAstig( int achrSet, double achrGAstig, double achrDelt ) { if( achrSet == 0 ) { Ocm[ 8 ] = achrGAstig; } else if( achrSet == 1 ) { Ocm[ 8 ] += achrDelt; } else { Ocm[ 8 ] -= achrDelt; } achrGenDoc( ); } cmd achrLatOff( int achrSet, double achrLatOff, double achrDelt ) { if( achrSet == 0 ) { Ocm[ 9 ] = achrLatOff; } else if( achrSet == 1 ) { Ocm[ 9 ] += achrDelt; } else { Ocm[ 9 ] -= achrDelt; } achrGenDoc( ); } // Command to set the offset of the MTRD from the // baseline value. static int achrLensSrf[ 9 ]; static int achrNumLen = 0; int achrMTRDSet {list = achrMTRDSetList, default(noquery) = lis} int achrMTRDLens {lolim = 1, hilim = 9, default(noquery) = 1} double achrMTRD {default(noquery) = 0.0} cmd achrMTRD( int achrMTRDSet, int achrMTRDLens, double achrMTRD, double achrDelt ) { if( achrMTRDSet != 2 ) { if( achrMTRDSet == 0 ) { Ocm[ 10 + achrMTRDLens ] = achrMTRD; } else if( achrMTRDSet == 1 ) { Ocm[ 10 + achrMTRDLens ] += achrDelt; } else { Ocm[ 10 + achrMTRDLens ] -= achrDelt; } if( achrMTRDLens <= achrNumLen ) { printf( "\n" ); aprintf( "%2d %f\n", achrLensSrf[ achrMTRDLens - 1 ], Ocm[ 10 + achrMTRDLens ] ); } else { printf( "\n" ); aprintf( " %f\n", Ocm[ 10 + achrMTRDLens ] ); } } else { int lennum; printf( "\n" ); for( lennum = 0; lennum < achrNumLen; ++lennum ) { aprintf( "%2d %f\n", achrLensSrf[ lennum ], Ocm[ 11 + lennum ] ); } } } // Analysis/Optimization tools. // Procedure to determine the zero-vignetting clear aperture // // Is this sufficient coverage for the majority of cases? static double Diamfby[ 2 ] = { 0.0, 1.0 }; static double Diamfbx[ 2 ] = { 0.0, 0.0 }; static double Diamfbz[ 2 ] = { 0.0, 0.0 }; static double Diamfyrf[ 2 ] = { 0.0, 0.0 }; static double Diamfxrf[ 2 ] = { 0.0, 0.0 }; static int Diamfwav[ 2 ] = { 1, 1 }; static int Diamnumobj = 2; static double DiamFy[ 3 ] = { -1.0, 1.0, 0.0 }; static double DiamFx[ 3 ] = { 0.0, 0.0, 1.0 }; static int Diamnumzon = 3; static double max_CA[ 100 ]; static void calc_CA( void ) { int stp_outp_sav = char_pref( outp ); int ssb_row_sav = sbrow( ); double st_x = trr_fbx; double st_y = trr_fby; double st_z = trr_fbz; double st_rx = trr_fxrf; double st_ry = trr_fyrf; int st_wav = curwav; int objnum; int wavnum; int zonnum; double curMax; int srfnum; // Set up output and buffer set_preference( outp, off ); for( srfnum = 1; srfnum <= ims; ++srfnum ) { max_CA[ srfnum ] = 0.0; } for( objnum = 0; objnum < Diamnumobj; ++objnum ) { ssbuf_reset( ssb_row_sav, 4 ); set_object_point( Diamfby[ objnum ], Diamfbx[ objnum ], Diamfbz[ objnum ], Diamfyrf[ objnum ], Diamfxrf[ objnum ], Diamfwav[ objnum ] ); ssbuf_reset( -ssb_row_sav, 0 ); for( wavnum = 1; wavnum <= numw; ++wavnum ) { for( zonnum = 0; zonnum < Diamnumzon; ++zonnum ) { ssbuf_reset( ssb_row_sav, ims + 1 ); tra( std, loc, All, DiamFy[ zonnum ], DiamFx[ zonnum ], no, wavnum ); for( srfnum = 1; srfnum <= ims; ++srfnum ) { curMax = 2.0 * ssb( srfnum, 1 ); if( curMax < 0.0 ) { curMax = -CurMax; } if( max_CA[ srfnum ] < curMax ) { max_CA[ srfnum ] = curMax; } } ssbuf_reset( -ssb_row_sav, 0 ); } } } // Restore saved conditions ssbuf_reset( ssb_row_sav, 4 ); set_object_point( st_y, st_x, st_z, st_ry, st_rx, st_wav ); ssbuf_reset( -ssb_row_sav, 0 ); if( stp_outp_sav ) { set_preference( outp, on ); } } // Command for same cmd ClearAps( void ) { int srfnum; calc_CA( ); printf( "\n" ); for( srfnum = 1; srfnum <= ims; ++srfnum ) { aprintf( "%2d %12.6f\n", srfnum, max_CA[ srfnum ] ); } } // Procedure to determine the recommended semi-diameters static double recSD[ 100 ]; static double recSag[ 100 ]; static double BaseCA[ 2 ] = { 48.0, 290.0 }; static double SDiamNew[ 2 ] = { 25.0, 150.0 }; static void calc_SD( int achrgroupC ) { int lgroupC = achrgroupC; int remG; int srfnum; int psrfnum; double slope; double intercept; double curMax; double locMax = 0.0; // Use the passed value or the one in the optimization table? if( lgroupC < 0 ) { lgroupC = Ocm[ 2 ]; } // The semi-diameter recommendation will be based on // the clear aperture: when equal to an entry in the // base clear aperture table, the semi-diameter will // be the corresponding entry of the semi-diameter table. // Algebraicly: // // SD = SD1 + // ((SD2 - SD1)/(CA2 - CA1)) * ( CA - CA1 ) // // Note: Units will cancel in the slope, but not in the // intercept. slope = ( SDiamNew[ 1 ] - SDiamNew[ 0 ] ) / ( BaseCA[ 1 ] - BaseCA[ 0 ] ); intercept = ( SDiamNew[ 0 ] - BaseCA[ 0 ] * slope ) / uni; calc_CA( ); for( remG = lgroupC % 10, locMax = 0.0, psrfnum = 1, srfnum = 1; srfnum <= ims; ++srfnum ) { curMax = slope * max_CA[ srfnum ] + intercept; if( locMax < curMax ) { locMax = curMax; } // Is this the last member of the group? if( --remG < 0 || srfnum >= ims ) { // This recommended semi-diameter is now assigned to each // member of this group. Also calculate the sagitta (conic // only) for each surface at that recommended semi-diameter. // (Do not exceed the legal range of the conic!) while( psrfnum <= srfnum ) { double qp1 = 1.0 + cc[ psrfnum ]; double cty = locMax * cv[ psrfnum ]; double rad = 1.0 - qp1 * cty * cty; if( rad < 0.0 ) { // The curve is too sharp for this size. // Decrease the recommended size to fit it. // // Note: This arm of the test automaticly implies // that the curvature magnitude is large and that // qp1 is positive. // Note sneaking cv^2 inside the radical to get // the absolute value. recSag[ psrfnum ] = 1.0 / ( qp1 * cv[ psrfnum ] ); recSD[ psrfnum ] = sqrt( recSag[ psrfnum ] / cv[ psrfnum ] ); } else { // This is the nominal case. recSD[ psrfnum ] = locMax; recSag[ psrfnum ] = locMax * cty / ( 1.0 + sqrt( rad ) ); } ++psrfnum; } // Go to the next group lgroupC /= 10; remG = lgroupC % 10; locMax = 0.0; } } } // Command for same cmd recSDiam( int achrgroupC ) { int srfnum; calc_SD( achrgroupC ); printf( "\n" ); for( srfnum = 1; srfnum < ims; ++srfnum ) { aprintf( "%2d %12.6f\n", srfnum, recSD[ srfnum ] ); } } // Local procedure to calculate the goal minimum thickness ratio (MTR) // equation. The minimum thickness goal will be: // // MT / SD = MeanTR + DeltaTR * Discrim // // The minimum thickness discriminant of a lens is: // // ( S1 - S2 ) / sqrt( e^2 + S1^2 + S2^2 ) // // where S1 and S2 are the sagittas of the lens. The quantity e is // a small value designed to eliminate the non-number 0/0, but not // interfere with the nature of the solution. The discriminant values // range from -sqrt(0.5) to sqrt(0.5). The respective limits are // approached for isoconcave and isoconvex lenses. // // A biproduct is the determination of the actual lenses in the // system. static double MeanMTR[ 9 ]; static double DeltMTR[ 9 ]; // The values of MeanTR and DeltaTR are linearly dependent on the // semi-diameter of the lens, but will result in the values of // minimum thickness ratios given in the following tables (for the // semi-diameters given above ( 25 and 150 mm ). static double CXRatios[ 2 ] = { 0.125, 0.085 }; static double CCRatios[ 2 ] = { 0.140, 0.115 }; static void calc_MDequ( int achrgroupC ) { double mean[ 2 ]; double delt[ 2 ]; double meanSlope; double meanIntercept; double deltSlope; double deltIntercept; int srfnum; int lensnum; // Derive the mean and delta ratios from the given // convex and concave ratios. Note the sqrt( 0.5 ) // to account for the fact that the discriminant // will range from -sqrt(0.5) to sqrt(0.5). mean[ 0 ] = 0.5 * ( CXRatios[ 0 ] + CCRatios[ 0 ] ); mean[ 1 ] = 0.5 * ( CXRatios[ 1 ] + CCRatios[ 1 ] ); delt[ 0 ] = 0.5 * ( CXRatios[ 0 ] - CCRatios[ 0 ] ) / sqrt( 0.5 ); delt[ 1 ] = 0.5 * ( CXRatios[ 1 ] - CCRatios[ 1 ] ) / sqrt( 0.5 ); // These are then to be hit at the specified sizes // via a linear relationship: // // mean = mean1 + // ((mean2 - mean1)/(SD2 - SD1)) * ( SD - SD1 ) // delt = delt1 + // ((delt2 - delt1)/(SD2 - SD1)) * ( SD - SD1 ) // // Note that the table values must be converted to units that // will match the semi-diameters. meanSlope = ( mean[ 1 ] - mean[ 0 ] ) / ( uni * ( SDiamNew[ 1 ] - SDiamNew[ 0 ] ) ); meanIntercept = mean[ 0 ] - meanSlope * ( uni * SDiamNew[ 0 ] ); deltSlope = ( delt[ 1 ] - delt[ 0 ] ) / ( uni * ( SDiamNew[ 1 ] - SDiamNew[ 0 ] ) ); deltIntercept = delt[ 0 ] - meanSlope * ( uni * SDiamNew[ 0 ] ); // Get the recommended semi-diameters calc_SD( achrgroupC ); // Now calculate the mean and delta minimum thickness ratios // for each surface. for( lensnum = 0, srfnum = 1; srfnum < ims && lensnum < 9; ++srfnum ) { if( rn[ srfnum ][ 1 ] > 1.0 ) { // The use of the minimum of the recommended semi-diameters // is being conservative, in that the minimum thickness // ratios get smaller for larger lenses. // Later, when the actual value is calculated, the larger // semi-diameter will be used. double minSD = recSD[ srfnum ]; if( minSD > recSD[ srfnum + 1 ] ) { minSD = recSD[ srfnum + 1 ]; } // This function also identifies the actual lenses of // the system. achrLensSrf[ lensnum ] = srfnum; MeanMTR[ lensnum ] = meanIntercept + minSD * meanSlope; DeltMTR[ lensnum ] = deltIntercept + minSD * deltSlope; ++lensnum; } } // Lastly, indicate the number of lenses. achrNumLen = lensnum; } // Procedure to calculate the shape dependent goal For the // Minimum Thickness Ratio. static double default_MTRgoal[ 9 ]; static double eps = 1.0e-10; static void calc_MTRgoal( int achrgroupC ) { int lensnum; double small = eps * eps / uni / uni; // Calculate the first few lens' MTR goal calc_MDequ( achrgroupC ); for( lensnum = 0; lensnum < achrNumLen; ++lensnum ) { int srfnum = achrLensSrf[ lensnum ]; double S1 = recSag[ srfnum ]; double S2 = recSag[ srfnum + 1 ]; // The shape of the lens must now be taken double discrim = ( S1 - S2 ) / sqrt( small + S1 * S1 + S2 * S2 ); default_MTRgoal[ lensnum ] = meanMTR[ lensnum ] + discrim * deltMTR[ lensnum ]; } } // Command for the same cmd MTRgoals( int achrgroupC ) { int lensnum; calc_MTRgoal( achrgroupC ); for( lensnum = 0; lensnum < achrNumLen; ++lensnum ) { aprintf( "%2d %12.6f\n", achrLensSrf[ lensnum ], default_MTRgoal[ lensnum ] ); } } // Optimization call-back procedure cmd achropnds( void ) { int stp_outp_sav = char_pref( outp ); int ssb_row_sav = sbrow( ); double st_x = trr_fbx; double st_y = trr_fby; double st_z = trr_fbz; double st_rx = trr_fxrf; double st_ry = trr_fyrf; int st_wav = curwav; char cmdstr[ 81 ]; int parmix; int OPass; double EFL; double field0; double fieldVal; double minField = 0.0; double maxField = 0.0; int fldnum; double SA_3; double CMA_3; double AST_3; int wavnum; double LatPos[ 4 ]; double LongDelt[ 4 ]; double AxColorM3; double AxColor2M; double LongErr[ 3 ]; double EFLErr[ 3 ]; int lensnum; set_preference( outp, off ); get_system_note( 6 ); strtoken( cmdstr, system_note, " " ); if( ! strcmp( cmdstr, "achr" ) ) { for( parmix = 1; parmix < 10; ++parmix ) { strtoken( cmdstr, "", " " ); Ocm[ parmix ] = atof( cmdstr ); } } OPass = Ocm[ 1 ]; // Find the difference from the desired effective focal length. // The requirement here is that the focal length be correct // for the user supplied f# and entry beam radius. ssbuf_reset( ssb_row_sav, 1 ); paraxial_constants( y, 1 ); EFL = ssb( 1, 1 ); ssbuf_reset( -ssb_row_sav, 0 ); Ocm[ 20 ] = EFL - 2.0 * ebr * Ocm[ 3 ]; // Find the focal surface. The requirement here is that the // image surface (plus its delta, if any) lie near the mean // of the sagittal and tangential surfaces. ssbuf_reset( ssb_row_sav, 20 + 1 ); field( n, 20 ); field0 = 0.5 * ( ssb( 1, 3 ) + ssb( 1, 4 ) ); for( fldnum = 1; fldnum <= 20; ++fldnum ) { fieldVal = 0.5 * ( ssb( fldnum + 1, 3 ) + ssb( fldnum + 1, 4 ) ) - field0; if( minField > fieldVal ) { minField = fieldVal; } else if( maxField < fieldVal ) { maxField = fieldVal; } } ssbuf_reset( -ssb_row_sav, 0 ); Ocm[ 21 ] = field0; Ocm[ 22 ] = 0.5 * ( minField + maxField ); // Lateral Color -- measured at the 84% field zone ssbuf_reset( ssb_row_sav, 4 ); set_object_point( sqrt( sqrt( 0.5 ) ), 0.0, 0.0, 0.0, 0.0, 1 ); ssbuf_reset( -ssb_row_sav, 0 ); for( wavnum = 1; wavnum <= 3; ++wavnum ) { ssbuf_reset( ssb_row_sav, 1 + 1 ); tra( std, loc, srf, 0.0, 0.0, 0, 0, no, wavnum ); LatPos[ wavnum ] = ssb( 1, 1 ); ssbuf_reset( -ssb_row_sav, 0 ); } Ocm[ 23 ] = 1.0e6 * ( LatPos[ 3 ] - LatPos[ 2 ] ) / LatPos[ 1 ]; if( OPass ) { Ocm[ 23 ] -= Ocm[ 9 ]; } // Longitudinal Color -- measured on axis // Calculate the intercept relative to the image surface node. // The wav3-wav1 error should be "roughly" equal, but opposite // in sign to the wav1-wav2 error. ssbuf_reset( ssb_row_sav, 4 ); set_object_point( 0.0, 0.0, 0.0, 0.0, 0.0, 1 ); ssbuf_reset( -ssb_row_sav, 0 ); for( wavnum = 1; wavnum <= 3; ++wavnum ) { ssbuf_reset( ssb_row_sav, 2 + 1 ); tra( ful, loc, srf, sqrt( 0.5 ), 0.0, 0, 0, no, wavnum ); LongDelt[ wavnum ] = ssb( 1, 3 ) - ssb( 1, 1 ) * ssb( 2, 3 ) / ssb( 2, 1 ); ssbuf_reset( -ssb_row_sav, 0 ); } AxColorM3 = LongDelt[ 3 ] - LongDelt[ 1 ]; AxColor2M = LongDelt[ 1 ] - LongDelt[ 2 ]; Ocm[ 24 ] = AxColor2M + Ocm[ 4 ] * ( AxColorM3 - AxColor2M ); // Seidel Options (does this depend on on-axis object point?) ssbuf_reset( ssb_row_sav, 1 ); seidel_abers( srf, 0, 0, 1 ); SA_3 = ssb( 1, 1 ); CMA_3 = ssb( 1, 2 ); AST_3 = ssb( 1, 3 ); ssbuf_reset( -ssb_row_sav, 0 ); Ocm[ 25 ] = AST_3; if( ! OPass ) { // Force astigmatism to zero(not to the input value) // As well as coma and spherical aberration Ocm[ 26 ] = CMA_3; Ocm[ 27 ] = SA_3; } else { // Offset astigmatism by the input value Ocm[ 25 ] -= Ocm[ 8 ]; // Calculate values of OSC and Sph // This does require an on-axis object point. ssbuf_reset( ssb_row_sav, 2 + 1 ); tra( ful, loc, srf, 1.0, 0.0, 0, 0, n, 1 ); EFLErr[ 0 ] = -1.0 * ebr / ssb( 2, 1 ) - EFL; Longerr[ 0 ] = ( ssb( 1, 3 ) - ssb( 1, 1 ) * ssb( 2, 3 ) / ssb( 2, 1 ) ) - field0; ssbuf_reset( -ssb_row_sav, 0 ); ssbuf_reset( ssb_row_sav, 2 + 1 ); tra( ful, loc, srf, sqrt( 0.5 ), 0.0, 0, 0, n, 1 ); EFLErr[ 1 ] = -sqrt( 0.5 ) * ebr / ssb( 2, 1 ) - EFL; Longerr[ 1 ] = ( ssb( 1, 3 ) - ssb( 1, 1 ) * ssb( 2, 3 ) / ssb( 2, 1 ) ) - field0; ssbuf_reset( -ssb_row_sav, 0 ); Ocm[ 26 ] = cos( dr * Ocm[ 5 ] ) * EFLErr[ 0 ] + sin( dr * Ocm[ 5 ] ) * EFLErr[ 1 ]; if( OPass <= 1 ) { Ocm[ 27 ] = cos( dr * Ocm[ 6 ] ) * Longerr[ 0 ] + sin( dr * Ocm[ 6 ] ) * Longerr[ 1 ]; // No nulling. Ocm[ 28 ] = 0.0; } else { Ocm[ 27 ] = cos( dr * Ocm[ 6 ] ) * Longerr[ 0 ] - sin( dr * Ocm[ 6 ] ) * Longerr[ 1 ]; // And, add the third, nulling, zone to compute the // error at the null zone. ssbuf_reset( ssb_row_sav, 2 + 1 ); tra( ful, loc, srf, 0.01 * Ocm[ 7 ], 0.0, 0, 0, n, 1 ); Longerr[ 2 ] = ( ssb( 1, 3 ) - ssb( 1, 1 ) * ssb( 2, 3 ) / ssb( 2, 1 ) ) - field0; ssbuf_reset( -ssb_row_sav, 0 ); Ocm[ 28 ] = Longerr[ 2 ]; } } // Update the thickness goals. calc_MTRgoal( -1 ); // Find out the differences from these goals. for( lensnum = 0; lensnum < achrNumLen; ++lensnum ) { int srfnum = achrLensSrf[ lensnum ]; double minTh = th[ srfnum ]; double Sag = recSag[ srfnum ] - recSag[ srfnum + 1 ]; double maxSD = recSD[ srfnum ]; if( maxSD < recSD[ srfnum + 1 ] ) { maxSD = recSD[ srfnum + 1 ]; } if( Sag > 0.0 ) { minTh -= Sag; } Ocm[ 31 + lensnum ] = minTh / MaxSD - default_MTRgoal[ lensnum ]; } // Restore saved conditions ssbuf_reset( ssb_row_sav, 4 ); set_object_point( st_y, st_x, st_z, st_ry, st_rx, st_wav ); ssbuf_reset( -ssb_row_sav, 0 ); if( stp_outp_sav ) { set_preference( outp, on ); } }