Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions doc/source/example/sofast_fringe/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ Generating Standard Mirror Output Plots
:members:
:show-inheritance:


Running SOFAST in Debug Mode
============================

.. currentmodule:: example.sofast_fringe.example_process_in_debug_mode

.. automodule:: example.sofast_fringe.example_process_in_debug_mode


Generate Rectangular Screen Definition
======================================

Expand All @@ -46,6 +55,7 @@ Generate Rectangular Screen Definition
:members:
:show-inheritance:


Process SOFAST Temperature Experiment Data
==========================================

Expand Down
12 changes: 12 additions & 0 deletions example/sofast_fringe/data/input/incorrect_facet_definition.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"v_facet_corners": {
"x": [0.606, -0.606, -0.606, 0.606],
"y": [-0.606, -0.606, 1.606, 1.606],
"z": [0.0, 0.0, 0.0, 0.0]
},
"v_centroid_facet": {
"x": [0.0],
"y": [0.0],
"z": [0.0]
}
}
127 changes: 127 additions & 0 deletions example/sofast_fringe/example_process_in_debug_mode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"""
Processes SOFAST data with debug mode enabled.

This module provides a function to process optical measurements using the SOFAST
framework while enabling debug mode. The function performs the following tasks:
loading necessary data files, calibrating fringe images, and processing the
measurements. If an error occurs during processing, debug figures are saved for
further analysis.

Usage:
To execute the processing with debug mode, run the module directly. The output
figures and log files will be saved in a specified directory structure.
"""

# ChatGPT 4o-mini assisted with docstring creation

from os.path import join, dirname

from opencsp.app.sofast.lib.DisplayShape import DisplayShape as Display
from opencsp.app.sofast.lib.DefinitionFacet import DefinitionFacet
from opencsp.app.sofast.lib.ImageCalibrationScaling import ImageCalibrationScaling
from opencsp.app.sofast.lib.MeasurementSofastFringe import MeasurementSofastFringe
from opencsp.app.sofast.lib.ProcessSofastFringe import ProcessSofastFringe as Sofast
from opencsp.app.sofast.lib.SpatialOrientation import SpatialOrientation
from opencsp.common.lib.camera.Camera import Camera
from opencsp.common.lib.deflectometry.Surface2DParabolic import Surface2DParabolic
from opencsp.common.lib.opencsp_path.opencsp_root_path import opencsp_code_dir
import opencsp.common.lib.tool.file_tools as ft
import opencsp.common.lib.tool.log_tools as lt


def example_process_in_debug_mode():
"""
Processes SOFAST data with debug mode enabled. This example intentionally runs SOFAST
on a single facet with erroneous facet corner location information. When SOFAST is in
debug mode, the cause of the most common errors can easily be diagnosed by looking at
the produced figures from debug mode. Run this script as-is, the look through the output
figures produced (location is printed in terminal) to see the cause of the error (the
erroneous facet corner definition file).

This function performs the following steps:

1. Sets up the necessary directories and logging for output.
2. Loads required data files, including camera, display, spatial orientation,
measurement, calibration, and facet definition data.
3. Calibrates the fringe images from the measurement data.
4. Instantiates a SOFAST processing object and enables debug mode.
5. Processes the optical data for a single facet. If an error occurs during
processing, all debug figures are saved to the specified output directory.

Notes
-----
The function needs the following files to run:

- Measurement data (HDF5 format)
- Camera calibration data (HDF5 format)
- Display shape data (HDF5 format)
- Spatial orientation data (HDF5 format)
- Image calibration data (HDF5 format)
- Facet definition data (JSON format)

Example
-------
To process the SOFAST data with debug mode enabled, simply call the function:

>>> example_process_in_debug_mode()

The resulting debug figures will be saved in the output directory if an error
occurs during processing.
"""
# 1. General setup
# ================

# Define save dir
dir_save = join(dirname(__file__), "data/output/sofast_with_debug_mode_on")
ft.create_directories_if_necessary(dir_save)

# Set up logger
lt.logger(join(dir_save, "log.txt"), lt.log.INFO)

# Define sample data directory
dir_data_sofast = join(opencsp_code_dir(), "test/data/sofast_fringe")
dir_data_common = join(opencsp_code_dir(), "test/data/sofast_common")

# Directory Setup
file_measurement = join(dir_data_sofast, "data_measurement/measurement_facet.h5")
file_camera = join(dir_data_common, "camera_sofast_downsampled.h5")
file_display = join(dir_data_common, "display_distorted_2d.h5")
file_orientation = join(dir_data_common, "spatial_orientation.h5")
file_calibration = join(dir_data_sofast, "data_measurement/image_calibration.h5")
file_facet = join(dirname(__file__), "data/input/incorrect_facet_definition.json")

# 2. Load saved single facet Sofast collection data
# =================================================
camera = Camera.load_from_hdf(file_camera)
display = Display.load_from_hdf(file_display)
orientation = SpatialOrientation.load_from_hdf(file_orientation)
measurement = MeasurementSofastFringe.load_from_hdf(file_measurement)
calibration = ImageCalibrationScaling.load_from_hdf(file_calibration)
facet_data = DefinitionFacet.load_from_json(file_facet)

# 3. Processes data with SOFAST and handle errors
# ===============================================
# Define surface definition (parabolic surface), this is the mirror
surface = Surface2DParabolic(initial_focal_lengths_xy=(300.0, 300.0), robust_least_squares=True, downsample=10)

# Calibrate fringes - (aka sinosoidal image)
measurement.calibrate_fringe_images(calibration)

# Instantiate sofast object
sofast = Sofast(measurement, orientation, camera, display)

# Turn on debug mode
sofast.params.debug_geometry.debug_active = True

# Process
try:
sofast.process_optic_singlefacet(facet_data, surface)
except ValueError:
# Save all debug figures
lt.info(f'An error occured when processing SOFAST data. Saving all debug figures to {dir_save}.')
for idx, fig in enumerate(sofast.params.debug_geometry.figures):
fig.savefig(join(dir_save, f'{idx:02d}.png'))


if __name__ == "__main__":
example_process_in_debug_mode()
38 changes: 26 additions & 12 deletions opencsp/app/sofast/lib/process_optics_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,13 @@ def process_singlefacet_geometry(
plt.title("Expected Optic Corners")

# Refine locations of optic corners with mask
prs = [params.perimeter_refine_axial_search_dist, params.perimeter_refine_perpendicular_search_dist]
loop_facet_image_refine = ip.refine_mask_perimeter(loop_optic_image_exp, v_edges_image, *prs)
data_image_processing_facet.loop_facet_image_refine = loop_facet_image_refine
try:
prs = [params.perimeter_refine_axial_search_dist, params.perimeter_refine_perpendicular_search_dist]
loop_facet_image_refine = ip.refine_mask_perimeter(loop_optic_image_exp, v_edges_image, *prs)
data_image_processing_facet.loop_facet_image_refine = loop_facet_image_refine
except ValueError as er:
lt.critical(repr(er))
lt.error_and_raise(ValueError, "SOFAST failed to find the corners of the optic.")

# Plot refined optic corners
if debug.debug_active:
Expand Down Expand Up @@ -516,12 +520,16 @@ def process_multifacet_geometry(
plt.title("Expected Perimeter Points")

# Refine perimeter points
args = [
params_geometry.perimeter_refine_axial_search_dist,
params_geometry.perimeter_refine_perpendicular_search_dist,
]
loop_ensemble_image_refine = ip.refine_mask_perimeter(loop_ensemble_exp, v_edges_image, *args)
data_image_processing_general.loop_optic_image_refine = loop_ensemble_image_refine
try:
args = [
params_geometry.perimeter_refine_axial_search_dist,
params_geometry.perimeter_refine_perpendicular_search_dist,
]
loop_ensemble_image_refine = ip.refine_mask_perimeter(loop_ensemble_exp, v_edges_image, *args)
data_image_processing_general.loop_optic_image_refine = loop_ensemble_image_refine
except ValueError as er:
lt.critical(repr(er))
lt.error_and_raise(ValueError, "SOFAST failed to find the corners of the optic.")

# Plot refined perimeter points
if debug.debug_active:
Expand Down Expand Up @@ -558,9 +566,15 @@ def process_multifacet_geometry(
]
loops_facets_refined: list[LoopXY] = []
for idx in range(num_facets):
loop = ip.refine_facet_corners(v_facet_corners_image_exp[idx], v_uv_facet_cent_exp[idx], v_edges_image, *args)
loops_facets_refined.append(loop)
data_image_processing_facet[idx].loop_facet_image_refine = loop
try:
loop = ip.refine_facet_corners(
v_facet_corners_image_exp[idx], v_uv_facet_cent_exp[idx], v_edges_image, *args
)
loops_facets_refined.append(loop)
data_image_processing_facet[idx].loop_facet_image_refine = loop
except ValueError as er:
lt.critical(repr(er))
lt.error_and_raise(ValueError, "SOFAST failed to find the corners of the optic.")

# Plot refined perimeter points
if debug.debug_active:
Expand Down
3 changes: 3 additions & 0 deletions opencsp/test/test_DocStringsExist.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

# Assume opencsp is in PYTHONPATH
import opencsp as opencsp
import example.sofast_fringe.example_process_in_debug_mode
import example.sofast_calibration.example_calibration_screen_shape

# Examples
import example.sofast_fringe.example_make_rectangular_screen_definition
import example.sofast_fringe.sofast_temperature_analysis


# TODO: why aren't these imported from import opencsp as opencsp above
from opencsp.app.camera_calibration import CameraCalibration
from opencsp.app.camera_calibration.lib.ViewAnnotatedImages import ViewAnnotatedImages
Expand Down Expand Up @@ -183,6 +185,7 @@ class test_Docstrings(unittest.TestCase):
# TODO: example_sofast_fringe_list
# TODO: example_targetcolor_list
example_list = [
example.sofast_fringe.example_process_in_debug_mode,
example.sofast_fringe.sofast_temperature_analysis,
example.sofast_fringe.example_make_rectangular_screen_definition,
example.sofast_calibration.example_calibration_screen_shape,
Expand Down