Skip to content

Commit

Permalink
Add new evaluate() overload to Model
Browse files Browse the repository at this point in the history
Until now when users evaluate a Model, the Model internally creates the
Image object that will hold the result, and then returns it to the user.
This way, each time a new evaluation happens, a new Image object is
created, then eventually destroyed.

Although for small images this doesn't cause too much of an overhead,
for bigger images where allocation times are noticeable this can become
one of the driving costs (e.g., a 10k x 10k Image object takes ~350 ms
to be created). To help take that cost down, and allow users reuse
allocated memory/Images, this commit adds a new evaluate() overload that
takes in an Image reference rather than returning one. The given image
is checked, and if its size is exactly that needed by the Model internal
evaluation routines then it is simply zero'd out and then used for
drawing pixels on. If on the other hand the image's size is not exactly
that needed by the Model, a new one is created with the required
dimensions and used instead.

With these changes, the existing evaluate() overload becomes a thin
wrapper around the new one, creating an empty Image object, passing it
to the new overload, then returning it to the user.

Signed-off-by: Rodrigo Tobar <[email protected]>
  • Loading branch information
rtobar committed Jul 10, 2024
1 parent a77c0cc commit 20c7cbb
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 9 deletions.
6 changes: 6 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ Changelog

.. rubric:: Development version

* :class:`Model` offers a new flavour of the ``evaluate`` function
where users can give a pre-existing :class:`Image` object
on which the result will be written.
If this user-provided :class:`Image` object
is not of the size internally needed by :class:`Model`
then it will be internally resized automatically.
* A new ``get_drawing_dimensions`` method
has been added to the :class:`Model` class.
* A new ``null`` convolver has been added
Expand Down
29 changes: 21 additions & 8 deletions src/profit/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,23 +262,36 @@ Dimensions Model::get_drawing_dimensions() const
}

Image Model::evaluate(Point &offset_out)
{
Image image;
evaluate(image, offset_out);
return image;
}

void Model::evaluate(Image &image, Point &offset_out)
{
auto analysis = analyze_inputs();

if (image.getDimensions() == analysis.drawing_dims) {
image.zero();
}
else {
image = Image{analysis.drawing_dims};
}

/* so long folks! */
if (dry_run) {
inform_offset({0, 0}, offset_out);
return Image{analysis.drawing_dims};
return;
}

// Adjust mask before passing it down to profiles
Point offset;
Image image;
Mask adjusted_mask;
if (adjust_mask && analysis.mask_needs_adjustment) {
adjusted_mask = mask;
adjust(adjusted_mask, psf, finesampling, analysis);
image = produce_image(adjusted_mask, analysis, offset);
produce_image(image, adjusted_mask, analysis, offset);
}
else {
if (!adjust_mask && mask.getDimensions() != analysis.drawing_dims) {
Expand All @@ -287,7 +300,7 @@ Image Model::evaluate(Point &offset_out)
<< mask.getDimensions() << " != " << analysis.drawing_dims;
throw invalid_parameter(os.str());
}
image = produce_image(mask, analysis, offset);
produce_image(image, mask, analysis, offset);
}

// Remove PSF padding if one was added, and downsample if necessary
Expand Down Expand Up @@ -321,14 +334,15 @@ Image Model::evaluate(Point &offset_out)
}

inform_offset(offset, offset_out);
return image;
return;
}

Image Model::produce_image(const Mask &mask, const input_analysis &analysis,
void Model::produce_image(Image &model_image, const Mask &mask, const input_analysis &analysis,
Point &offset)
{
assert(model_image.getDimensions() == analysis.drawing_dims);

// Avoiding memory allocation if no convolution is needed
Image model_image{analysis.drawing_dims};
Image to_convolve;
if (analysis.convolution_required) {
to_convolve = Image{analysis.drawing_dims};
Expand Down Expand Up @@ -361,7 +375,6 @@ Image Model::produce_image(const Mask &mask, const input_analysis &analysis,
}

/* Done! Good job :-) */
return model_image;
}

std::map<std::string, std::shared_ptr<ProfileStats>> Model::get_stats() const {
Expand Down
7 changes: 6 additions & 1 deletion src/profit/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ class PROFIT_API Model {
*/
Image evaluate(Point &offset_out = NO_OFFSET);

/**
* Like evaluate(Point &), but the user provides an Image to write data on.
*/
void evaluate(Image &image, Point &offset_out = NO_OFFSET);

/**
* Returns the dimensions that this model will need to use internally when
* drawing profile images, considering any effects like PSF padding,
Expand Down Expand Up @@ -395,7 +400,7 @@ class PROFIT_API Model {
ProfilePtr make_profile(const std::string &name);

// Actually produce the image from the profiles and convolve it against the psf
Image produce_image(const Mask &mask, const input_analysis &analysis, Point &offset);
void produce_image(Image &model_image, const Mask &mask, const input_analysis &analysis, Point &offset);

// Analyze the model's inputs and produce information needed by other steps
input_analysis analyze_inputs() const;
Expand Down

0 comments on commit 20c7cbb

Please sign in to comment.