Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce HeatSources #282

Draft
wants to merge 32 commits into
base: master
Choose a base branch
from

Conversation

masterleinad
Copy link
Collaborator

@masterleinad masterleinad commented May 3, 2024

This is a step towards #190. This pull request replaces std::vector<std::shared_ptr<adamantine::HeatSource<dim>>> with HeatSources that contains all heat sources as Kokkos::Views and loops over them in its member functions. With this approach, there is no dynamic polymorphism and the compiler could inline all function calls for the heat sources. In particular, this object would be usable on GPUs (apart from function annotations).

@@ -138,7 +140,9 @@ void ScanPath::load_event_series_scan_path(std::string scan_path_file)
segment.power_modifier = last_power;
last_power = std::stod(split_line[4]);

_segment_list.push_back(segment);
if (_segment_list_length == MAX_NUMBER_OF_SEGMENTS)
Kokkos::abort("too many segmnets");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo:

Suggested change
Kokkos::abort("too many segmnets");
Kokkos::abort("too many segments");

@@ -19,6 +19,8 @@
#include <istream>
#include <vector>

#define MAX_NUMBER_OF_SEGMENTS 100
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too low -- if we had a 50-layer print with only two segments per layer, we'd hit this. I'm not sure that we've done enough sliced full parts to know a good upper bound. For example the AOP hourglass has 8055 segments and that's pretty simple as far as "real" parts go. Can we use a Kokkos::View with a runtime-defined length instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was one of my next steps but I would need to manage the allocations for the segments outside the heat sources to avoid Views of managed Views. I'm not sure how much freedom we have to change those APIs.

The current version should be (more or less) device-usable already at least.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, got it. Maybe another option would be to make it a template parameter? Even with the dynamic scan path in #223, we wouldn't be changing the length of the scan path too many times per simulation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, changing it to a template argument for the heat source and the scan path is easy. The question then is if we want to have a runtime dispatch for pre-instantiated maximum sizes or any other mechanism that doesn't require rebuilding the library and the application for certain input files.

Copy link
Member

@Rombur Rombur May 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to do this. We don't know how many segments we will need but it's potentially very large. If someone wants to do point-source raster for PBF, the number of segments will be huge.
In the current code, the scan path is part of the heat source. You need to change that. Move the scan path to HeatSources, add a function that evaluates the scan patch from t_0 to t_1 and fill a Kokkos::View. This way we don't need to know the number of segments and you don't waste memory if you have a ton a segments.

I'm not sure how much freedom we have to change those APIs.

adamantine is not a library. Everything but the input parameters is an implementation detail.

Comment on lines 343 to 353
template <typename MemorySpace, int dim>
std::vector<ScanPath<MemorySpace>>
HeatSources<MemorySpace, dim>::get_scan_paths() const
{
std::vector<ScanPath<MemorySpace>> scan_paths;
for (unsigned int i = 0; i < _electron_beam_heat_sources.size(); ++i)
scan_paths.push_back(_electron_beam_heat_sources(i).get_scan_path());
for (unsigned int i = 0; i < _goldak_heat_sources.size(); ++i)
scan_paths.push_back(_goldak_heat_sources(i).get_scan_path());
return scan_paths;
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it important for the order here to match the input file?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it's not. There is no order in the input file. You can reorder everything and the same input file will work.

@masterleinad masterleinad changed the title [WIP] Introduce HeatSources Introduce HeatSources May 20, 2024
@masterleinad masterleinad marked this pull request as ready for review May 20, 2024 21:28
Copy link
Member

@Rombur Rombur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will need to rebase the PR on develop. There was some small changes in ScanPath.

// coarsest mesh we may need to add other points to check (e.g.
// quadrature points, vertices).
for (unsigned int f = 0; f < cell->reference_cell().n_faces(); ++f)
if (heat_sources.max_value(cell->face(f)->center(), current_source_height) >
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should just use value. In practice, value and max_value will probably always be the same because heat sources do not overlap.

@@ -609,14 +606,16 @@ void refine_mesh(
const double refinement_beam_cutoff =
refinement_database.get<double>("beam_cutoff", 1.0e-15);

adamantine::HeatSources<dim, dealii::MemorySpace::Host> host_heat_sources = heat_sources.copy_to(dealii::MemorySpace::Host{});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use heat_sources_host instead of host_heat_sources. We use the suffixes _host and _dev instead of the prefixes host_ and dev_. This helps when using autocomplete.

@@ -936,11 +935,13 @@ run(MPI_Comm const &communicator, boost::property_tree::ptree const &database,
mechanical_physics, displacement, material_properties, timers);
++n_time_step;

adamantine::HeatSources<dim, dealii::MemorySpace::Host> host_heat_sources = heat_sources.copy_to(dealii::MemorySpace::Host{});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment

@@ -9,11 +9,12 @@
#include <instantiation.hh>
#include <types.hh>

#include <deal.II/base/memory_space.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you add this include?

@@ -17,7 +19,7 @@ namespace adamantine
* used for verification purpose.
*/
template <int dim>
class CubeHeatSource final : public HeatSource<dim>
class CubeHeatSource final
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class CubeHeatSource final
class CubeHeatSource

}
_current_source_height = temp_height;
_current_source_height =
_heat_sources.copy_to(dealii::MemorySpace::Host{}).get_current_height(t);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above

@@ -19,9 +19,6 @@ namespace adamantine
// Forward declarations
class Timer;

template <int dim>
class HeatSource;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need a forward declaration because you are relying on the order of the includes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still need a forward declaration, otherwise the code may break if the include are reordered.

}

static std::vector<ScanPathSegment>
extract_scan_paths(std::string scan_path_file, std::string file_format);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like this name. You are just reading from a file.

GoldakHeatSource<2, dealii::MemorySpace::Host> goldak_heat_source(
beam, ScanPath<dealii::MemorySpace::Host>(scan_paths_segments_view));
ElectronBeamHeatSource<2, dealii::MemorySpace::Host> eb_heat_source(
database, ScanPath<dealii::MemorySpace::Host>(scan_paths_segments_view));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put this code in a function instead of copy/pasting three times.

scan_paths_segments_view(scan_path_segments.data(),
scan_path_segments.size());
adamantine::ScanPath<dealii::MemorySpace::Host> scan_path(
scan_paths_segments_view);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this code in a function to avoid the copy/paste.

@masterleinad
Copy link
Collaborator Author

Retest this please.

@Rombur
Copy link
Member

Rombur commented Jun 18, 2024

Let me know when you want another review on this.

@masterleinad
Copy link
Collaborator Author

Let me know when you want another review on this.

This could take another review now. Some notes:

  • I create local copies on the host for the HeatSources object where necessary assuming that we want it by default to be in the memory space specified in the respective template argument for the other operators. It might make sense to keep it in host memory instead and only create device copies or we keep a member variable for both memory spaces (if they don't coincide).
  • I needed to move a bunch of const members in the heat sources to make these classes copyable. I was running into some issues with static variables if used on the device as well. Thus, I moved the respective constants into member functions.
  • The recent changes reusing scan file paths made the HeatSources code a little more complicated. We are now storing those std::strings in HeatSources directly as well and recreating the scan file segments from them if necessary. Since the ScanPath doesn't own the ScanPathSegments, reading the file is a static member instead of a member function named "extract_scan_paths". I'm happy to change it back to some other name like "read_file" again if preferred.
  • I believe I addressed all other comments.

heat_sources_host =
heat_sources.copy_to(dealii::MemorySpace::Host{});
heat_sources_host.update_scan_paths();
heat_sources = heat_sources_host.copy_to(MemorySpaceType{});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that you are copying back and forth such a heavy class just to read a file. update_scan_path() should do the right thing.

@@ -13,7 +13,6 @@ namespace adamantine
{
template <int dim>
CubeHeatSource<dim>::CubeHeatSource(boost::property_tree::ptree const &database)
: HeatSource<dim>()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the copyright date to 2024

@@ -8,7 +8,9 @@
#ifndef CUBE_HEAT_SOURCE_HH
#define CUBE_HEAT_SOURCE_HH

#include <HeatSource.hh>
#include <BeamHeatSourceProperties.hh>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should be removed and the copyright date updated.

{
static const double log_01 = std::log(0.1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

void set_scan_path(ScanPath<MemorySpaceType> const scan_path)
{
_scan_path = scan_path;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the implementation out of the class declaration


for (unsigned int i = 0; i < _goldak_heat_sources.size(); ++i)
_goldak_heat_sources(i).set_scan_path(
ScanPath<MemorySpaceType>{_goldak_scan_path_segments[i]});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we keeping track of the scan path in HeatSources and in each individual sources? We should not duplicate this information.

value += _cube_heat_sources(i).value(point, height);
for (unsigned int i = 0; i < _goldak_heat_sources.size(); ++i)
value += _goldak_heat_sources(i).value(point, height);
return value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?


template <typename MemorySpaceType>
std::vector<ScanPathSegment>
ScanPath<MemorySpaceType>::extract_scan_paths(std::string scan_path_file,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still hate the name

@@ -54,6 +54,7 @@ class ScanPathTester;
* gives the power modifier for the current segment. It reads in the scan path
* from a text file.
*/
template <typename MemorySpaceType>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is is actually necessary to have the ScanPath on the GPU? I feel like this should only exists on the CPU and we should only move part of the data when it's necessary. Otherwise, we will end up using several GBs of memory on the GPU just for the ScanPath.

@@ -19,9 +19,6 @@ namespace adamantine
// Forward declarations
class Timer;

template <int dim>
class HeatSource;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still need a forward declaration, otherwise the code may break if the include are reordered.

@masterleinad masterleinad marked this pull request as draft July 24, 2024 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants