Skip to content

[Code Bug]: PowerpointImage.py, _save function passes file rather than path to file_tools.copy_file #260

@e10harvey

Description

@e10harvey

Contact Details

No response

What happened?

RenderControlPowerpointPresentation.presentation fails with:

RuntimeError: ERROR: In copy_file(), requested output directory does not exist: 

Version

develop@9d405367fa1f4030458ca14e522e77b1f72a37c8

What OS are you seeing this on?

MacOS

Relevant dependency versions

Python 3.10.16
ffmpeg version 7.1 Copyright (c) 2000-2024 the FFmpeg developers
built with Apple clang version 16.0.0 (clang-1600.0.26.4)
configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.1_4 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
libavutil      59. 39.100 / 59. 39.100
libavcodec     61. 19.100 / 61. 19.100
libavformat    61.  7.100 / 61.  7.100
libavdevice    61.  3.100 / 61.  3.100
libavfilter    10.  4.100 / 10.  4.100
libswscale      8.  3.100 /  8.  3.100
libswresample   5.  3.100 /  5.  3.100
libpostproc    58.  3.100 / 58.  3.100
Package                       Version
----------------------------- ----------
alabaster                     0.7.13
appnope                       0.1.3
astroid                       3.1.0
asttokens                     2.4.1
attrs                         24.2.0
Babel                         2.14.0
beautifulsoup4                4.12.3
black                         24.3.0
bleach                        6.1.0
certifi                       2023.11.17
chardet                       5.2.0
charset-normalizer            3.3.2
click                         8.1.7
codemetrics                   0.11.7
comm                          0.2.0
contourpy                     1.2.0
coverage                      7.4.0
cycler                        0.12.1
Cython                        3.0.6
debugpy                       1.8.0
decorator                     5.1.1
defusedxml                    0.7.1
dill                          0.3.8
docutils                      0.20.1
et-xmlfile                    1.1.0
exceptiongroup                1.2.0
executing                     2.0.1
fastjsonschema                2.20.0
fonttools                     4.46.0
gitdb                         4.0.11
GitPython                     3.1.43
h5py                          3.12.1
idna                          3.6
imageio                       2.34.1
imagesize                     1.4.1
iniconfig                     2.0.0
ipykernel                     6.29.4
ipython                       8.18.1
isort                         5.13.2
jedi                          0.19.1
Jinja2                        3.1.2
joblib                        1.4.0
jsonschema                    4.23.0
jsonschema-specifications     2023.12.1
jupyter_client                8.6.0
jupyter_core                  5.5.0
jupyterlab_pygments           0.3.0
kiwisolver                    1.4.5
lizard                        1.17.10
lxml                          4.9.3
markdown-it-py                3.0.0
MarkupSafe                    2.1.3
matplotlib                    3.8.2
matplotlib-inline             0.1.6
mccabe                        0.7.0
mdit-py-plugins               0.4.0
mdurl                         0.1.2
mistune                       3.0.2
mpmath                        1.3.0
mypy-extensions               1.0.0
myst-parser                   2.0.0
nbclient                      0.10.0
nbconvert                     7.16.4
nbformat                      5.10.4
nbsphinx                      0.9.5
nest-asyncio                  1.5.8
numpy                         1.26.4
opencv-contrib-python         4.5.5.64
openpyxl                      3.1.2
packaging                     23.2
pandas                        2.2.2
pandocfilters                 1.5.1
parso                         0.8.3
pathspec                      0.12.1
pexpect                       4.9.0
pillow                        10.3.0
pip                           23.3.2
pip-licenses                  4.4.0
platformdirs                  4.1.0
pluggy                        1.5.0
ply                           3.11
prettytable                   3.10.0
prompt-toolkit                3.0.41
psutil                        5.9.6
ptyprocess                    0.7.0
pure-eval                     0.2.2
Pygments                      2.17.2
pygount                       1.6.1
pylint                        3.1.0
Pyomo                         6.7.0
pyparsing                     3.1.1
pyproj                        3.6.1
pypylon                       3.0.0
pysolar                       0.11
pytest                        8.2.1
pytest-cov                    4.1.0
pytest-xvfb                   3.0.0
python-dateutil               2.8.2
python-pptx                   0.6.23
pytz                          2024.1
PyVirtualDisplay              3.0
PyYAML                        6.0.1
pyzmq                         25.1.2
rawpy                         0.21.0
referencing                   0.35.1
requests                      2.31.0
rich                          13.7.1
rpds-py                       0.20.0
scikit-learn                  1.4.2
scipy                         1.13.1
setuptools                    68.2.2
six                           1.16.0
smmap                         5.0.1
snowballstemmer               2.2.0
soupsieve                     2.6
Sphinx                        7.2.6
sphinx-argparse               0.4.0
sphinx-rtd-theme              2.0.0
sphinxcontrib-applehelp       1.0.7
sphinxcontrib-devhelp         1.0.5
sphinxcontrib-htmlhelp        2.0.4
sphinxcontrib-jquery          4.1
sphinxcontrib-jsmath          1.0.1
sphinxcontrib-qthelp          1.0.6
sphinxcontrib-serializinghtml 1.1.9
stack-data                    0.6.3
sympy                         1.12
threadpoolctl                 3.4.0
tinycss2                      1.3.0
tomli                         2.0.1
tomlkit                       0.12.4
tornado                       6.4
tqdm                          4.66.4
traitlets                     5.14.0
typing_extensions             4.9.0
tzdata                        2023.3
urllib3                       2.1.0
wcwidth                       0.2.12
webencodings                  0.5.1
wheel                         0.42.0
XlsxWriter                    3.1.9

python script that produces the error

# Create power point presentation
    presentation = rcpp.RenderControlPowerpointPresentation()
    slide_control = rcps.RenderControlPowerpointSlide()
    images = [pi.PowerpointImage(join(dir_save_cur, "Slope_X_measured_xy.png"))]
    texts = [pt.PowerpointText("slope x measured")]
    slide = ps.PowerpointSlide(slide_control, images, texts)
    presentation.add_slide(slide)
    presentation.save(dir_save_cur)

Relevant console output

ERROR: In copy_file(), requested output directory does not exist: /tmp/tmp/PowerpointImage/images/tmp/0_0.png
FAILED

=============================================================================================================================================== FAILURES ===============================================================================================================================================
____________________________________________________________________________________________________________________________________________ example_laptop ____________________________________________________________________________________________________________________________________________

    def example_laptop():
        """Performs processing of previously collected SOFAST data using a laptop webcam and a cosmetic mirror.
    
        1. Load saved single facet SOFAST collection data from HDF5 file
        2. Save projected sinusoidal fringe images to PNG format
        3. Save captured sinusoidal fringe images and mask images to PNG format
        4. Processes data with SOFAST and save processed data to HDF5
        5. Generate plot suite and save images files
        """
        # General setup
        # =============
    
        # Define save dir
        dir_save = join(dirname(__file__), 'data/output/laptop')
        ft.create_directories_if_necessary(dir_save)
    
        # Set up logger
        lt.logger(join(dir_save, 'example_laptop_log.txt'), lt.log.INFO)
    
        # Phase 1: Setup a sofast laptop experiment by loading the calibration data
        # (note that this data has already been collected for this opencsp example)
        # =========================================================================
    
        # Load the calibration data from physically setting up the laptop and cosmetic mirror in your room.
        dir_calibration_data = join(dirname(__file__), 'data/calibration')
    
        # This calibration data was prepared by doing the following:
        #  1) Get resolution of laptop screen and use this to adjust the display size to the desired location
        #       NOTE: if a screen scale is applied, this may need to be applied to input dimensions as well.
        #       NOTE: If using two screens with difference scales it is recommended to set the scale to be the same for both monitors.
        # file_calibration = join(dir_measurement_data, '20240515_104737_measurement_fringe.h5')
        #  2) We assume that the laptop screen has little to no distortion and use the 2d rectangular definition.
        #       NOTE: for setting up your own laptop sofast, open display_rectangular.h5 via HDFView, set screen x/y in meters, and save it.
        file_display = join(dir_calibration_data, 'screen_laptop_full/display_rectangular.h5')
        #  3) NOTE: We measured the distance from the center of the crosshairs on the cosmetic mirror to the center of the laptop webcam lens
        #       NOTE: for setting up your own laptop sofast, open spatial_orientation.h5 via HDFView, set optic_oriented to 0, set r_cam_screen to (0, 0, 0), set v_cam_screen_cam to x=?, y=?, z=0, and save it
        file_orientation = join(dir_calibration_data, 'screen_laptop_full/spatial_orientation.h5')
        #  4) NOTE: camera.h5 was measured by following 2.4.1 of the sofast user guide. See https://sandia-csp.app.box.com/file/1636393938364.
        file_laptop_camera = join(dir_calibration_data, 'camera_calibration/camera.h5')
    
        # This data was collected by running the sofast command line client with the above calibration data on the cosmetic mirror, and laptop webcam in our room
        dir_measurement_data = join(dirname(__file__), 'data/large_cosmetic_mirror')
        file_measurement = join(dir_measurement_data, 'measurement.h5')
        file_calibration = join(dir_measurement_data, 'calibration.h5')
    
        ex_calibration = ImageCalibrationScaling.load_from_hdf(file_calibration)  # pixel intensity calibration 1-255
    
        ex_display = Display.load_from_hdf(
            file_display
        )  # this is a grid representation of the screen (aruco marker calibration algorithm output)
        ex_orientation = SpatialOrientation.load_from_hdf(file_orientation)  # camera to display
        ex_laptop_camera = Camera.load_from_hdf(file_laptop_camera)
    
        # Phase 2: Load the sofast laptop measurement data
        # (note that this data has already been collected for this opencsp example)
        # =========================================================================
    
        ex_measurement = MeasurementSofastFringe.load_from_hdf(file_measurement)  # the sofast experimental data
    
        # 2. Save projected sinusoidal fringe images to PNG format
        # ========================================================
        fringes = Fringes(ex_measurement.fringe_periods_x, ex_measurement.fringe_periods_y)
        images = fringes.get_frames(
            640, 320, 'uint8', [0, 255]
        )  # writes images we projected from laptop screen "projector" to disk
        dir_save_cur = join(dir_save, '1_images_fringes_projected')
        ft.create_directories_if_necessary(dir_save_cur)
        # Save y images
        for idx_image in range(ex_measurement.num_y_ims):
            image = images[..., idx_image]
            imageio.imwrite(join(dir_save_cur, f'y_{idx_image:02d}.png'), image)
        # Save x images
        for idx_image in range(ex_measurement.num_x_ims):
            image = images[..., ex_measurement.num_y_ims + idx_image]
            imageio.imwrite(join(dir_save_cur, f'x_{idx_image:02d}.png'), image)
    
        # 3. Save captured sinusoidal fringe images and mask images to PNG format
        # =======================================================================
        dir_save_cur = join(dir_save, '2_images_captured')
        ft.create_directories_if_necessary(dir_save_cur)
    
        # Save mask (like a pixel mask value (all 0s, all 255s)) images
        for idx_image in [0, 1]:
            image = ex_measurement.mask_images[..., idx_image]
            img_normalized = (image - image.min()) / (image.max() - image.min()) * 255
            img_normalized = img_normalized.astype(np.uint8)
            imageio.imwrite(join(dir_save_cur, f'mask_{idx_image:02d}.png'), img_normalized)
        # Save y images (when lines were vertical, e.g.)
        for idx_image in range(ex_measurement.num_y_ims):
            image = ex_measurement.fringe_images_y[..., idx_image]
            img_normalized = (image - image.min()) / (image.max() - image.min()) * 255
            img_normalized = img_normalized.astype(np.uint8)
            imageio.imwrite(join(dir_save_cur, f'y_{idx_image:02d}.png'), img_normalized)
        # Save x images (when lines were horizontal, e.g.)
        for idx_image in range(ex_measurement.num_x_ims):
            image = ex_measurement.fringe_images_x[..., idx_image]
            img_normalized = (image - image.min()) / (image.max() - image.min()) * 255
            img_normalized = img_normalized.astype(np.uint8)
            imageio.imwrite(join(dir_save_cur, f'x_{idx_image:02d}.png'), img_normalized)
    
        # 4. Processes data with Sofast and save processed data to HDF5
        # =============================================================
        dir_save_cur = join(dir_save, '3_processed_data')
        ft.create_directories_if_necessary(dir_save_cur)
    
        # Define surface definition (parabolic surface), this is the mirror
        surface = Surface2DParabolic(initial_focal_lengths_xy=(2.0, 2.0), robust_least_squares=False, downsample=5)
    
        # Calibrate fringes - (aka sinosoidal image)
        ex_measurement.calibrate_fringe_images(ex_calibration)
    
        # Instantiate sofast object
        sofast = Sofast(ex_measurement, ex_orientation, ex_laptop_camera, ex_display)
        sofast.params.mask.keep_largest_area = True
    
        # Process
        sofast.process_optic_undefined(surface)
    
        # Save processed data to HDF5 format
        sofast.save_to_hdf(join(dir_save_cur, 'data_sofast_cosmetic_mirror_fringe.h5'))
    
        # Save measurement statistics to JSON
        config = SofastConfiguration()
        config.load_sofast_object(sofast)
        measurement_stats = config.get_measurement_stats()
    
        # Save measurement stats as JSON
        with open(join(dir_save_cur, 'cosmetic_mirror_measurement_statistics.json'), 'w', encoding='utf-8') as f:
            json.dump(measurement_stats, f, indent=3)
    
        # 5. Generate plot suite and save images files
        # ============================================
        dir_save_cur = join(dir_save, '4_processed_output_figures')
        ft.create_directories_if_necessary(dir_save_cur)
    
        # Get measured and reference optics
        mirror_measured = sofast.get_optic('bilinear').mirror.no_parent_copy()
        mirror_reference = MirrorParametric.generate_symmetric_paraboloid(0.55, mirror_measured.region)
    
        # Define viewing/illumination geometry
        # x and y is ground plane
        # z is pointing up to the sky
    
        # target is 100 meters up in air
        v_target_center = Vxyz(
            (0, 0, 0.55)
        )  # TODO: Update docs to specify meters, document that x is up, y is straight into air, and z is left-right
        # TODO: try moving focal length out, etc.
    
        # The normal is pointing down
        v_target_normal = Vxyz((0, 0, -1))
    
        # Pointing angle is pointing straight down (Uxyz(0,0,-1))
        source = LightSourceSun.from_given_sun_position(Uxyz((0, 0, -1)), resolution=40)
    
        # Save optic objects
        plots = StandardPlotOutput()
        plots.optic_measured = mirror_measured
        plots.optic_reference = mirror_reference
    
        # Update visualization parameters
        plots.options_slope_vis.clim = 150  # maximum slope at edge of mirror (we know focal length and radius of mirror, )
        plots.options_slope_vis.resolution = 0.001
        plots.options_slope_vis.quiver_scale = 1200  # TODO: can this be set to auto and computed by default?
        plots.options_slope_vis.quiver_density = 0.05  # TODO: can this be set to auto and computed by default?
    
        plots.options_slope_deviation_vis.clim = 15
        plots.options_slope_deviation_vis.resolution = 0.001
        # TODO: Document why the quiver scale and denisty doesn't need to be updated. (Our magnitude of error is about 15 mrad, CSP mirrors are typically 7-10)
    
        plots.options_curvature_vis.resolution = 0.001
        plots.options_curvature_vis.clim = 50
    
        plots.options_ray_trace_vis.enclosed_energy_max_semi_width = 1
        plots.options_ray_trace_vis.hist_extent = 0.05  # image of light source reflection
        plots.options_ray_trace_vis.hist_bin_res = 0.00075  # TODO: maybe also have a auto default to compute defaults
        plots.options_ray_trace_vis.ray_trace_optic_res = 0.007  # TODO: maybe also have a auto default to compute defaults
    
        plots.options_file_output.to_save = True
        plots.options_file_output.number_in_name = False
        plots.options_file_output.output_dir = dir_save_cur
    
        # Define ray trace parameters
        plots.params_ray_trace.source = source
        plots.params_ray_trace.v_target_center = v_target_center
        plots.params_ray_trace.v_target_normal = v_target_normal
    
        # Create standard output plots
        plots.plot()
    
        # Create power point presentation
        presentation = rcpp.RenderControlPowerpointPresentation()
        slide_control = rcps.RenderControlPowerpointSlide()
        images = [pi.PowerpointImage(join(dir_save_cur, "Slope_X_measured_xy.png"))]
        texts = [pt.PowerpointText("slope x measured")]
        slide = ps.PowerpointSlide(slide_control, images, texts)
>       presentation.add_slide(slide)

example_laptop.py:257: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../opencsp/common/lib/render_control/RenderControlPowerpointPresentation.py:63: in add_slide
    slide.save()
../../opencsp/common/lib/render/PowerpointSlide.py:354: in save
    image.save()
../../opencsp/common/lib/render/lib/PowerpointImage.py:422: in save
    saved_path, body_ext = self._save(image_path_name_ext)
../../opencsp/common/lib/render/lib/PowerpointImage.py:280: in _save
    ft.copy_file(self._val, path_name_ext)
../../opencsp/common/lib/tool/file_tools.py:835: in copy_file
    lt.error_and_raise(

Contribution Guidelines

  • I agree to follow this project's contribution guidelines

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions