-
Notifications
You must be signed in to change notification settings - Fork 35
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
Implement framework for optical physics models #1302
base: develop
Are you sure you want to change the base?
Conversation
Does this supersede #1162 ? |
Yes, I'll close that one. I reused any relevant code but had to make enough major changes I thought it was worthwhile to start from a fresh branch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry it's taken some time to go through this: this looks really solid; I think you've got basically all the skeleton there! I've got a thought or two about simplifying some aspects to accelerate the time it takes for us to flesh this out... perhaps the first PR could be just the interactors for rayleigh and absorption; so that way we can unit test them and make sure the initial OpticalInteraction
class is good enough. (You know, we might even be able to leave out code like the secondary stack until later, just to keep things simple.) But I think virtually all of this code will eventually end up in the final version almost unchanged 😄
struct ImportData; | ||
//---------------------------------------------------------------------------// | ||
/*! | ||
* A registry for imported optical material data. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ImportedProcesses
stuff in phys
is a little janky; it also is some of the oldest code that we use. When I wrote it, I was hoping to reduce data copying and lifetime and so forth; but in reality there's just not that much data for us to worry about, especially with optical physics. I think it'd just be simpler and more effective to build each optical model directly from optical import data, so we don't even need this (admittedly lightweight) class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case I think I'd like to change the optical map in ImportData
to be a vector of ImportOpticalMaterial
s and change the map to be a map between GeoMatId
s and OpticalMaterialId
s. We need to just iterate over a list of optical materials in several places, and having a simple vector to index would be convenient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hhollenb I fully support that! It's definitely more consistent with how we treat the other properties. Perhaps instead of a map between geo and optical matIDs, what about having an unsigned int optical_material_id
field in ImportGeoMaterial
? (You could define a static inline constexpr unsigned int unspecified = -1
like we have with ImportVolume
.)
*/ | ||
struct AbsorptionExecutor | ||
{ | ||
inline CELER_FUNCTION Interaction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're going to need an optical interaction type—since it includes changes to polarisation, and I assume we're not ionizing anything so we never make any non-photon secondaries.
// See the top-level COPYRIGHT file for details. | ||
// SPDX-License-Identifier: (Apache-2.0 OR MIT) | ||
//---------------------------------------------------------------------------// | ||
//! \file celeritas/optical/OpticalMfpBuilder.hh |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can put these guys in the detail namespace.
|
||
//---------------------------------------------------------------------------// | ||
/*! | ||
* Build the mean free paths for the model. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Build the mean free paths for the model. | |
* Build the mean free paths for one material for the model. |
* | ||
* Performs the construction of optical physics data and optical models | ||
* from imported data, and provides an interface for accessing this data | ||
* on the host and on the device. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to add a few notes about how this class differs from the main EM physics:
- We interpolate linearly on MFP vs energy, rather than macroscopic XS vs log energy (or scaled log energy)
- There's a one-to-one model/process correlation
- Only a single incident particle type is supported
- Not all materials in the problem have optical data (?)
- ....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* We interpolate linearly on MFP vs energy, rather than macroscopic XS vs log energy (or scaled log energy)
A thought on linear interpolation: this is effectively just due to our choice of grid, right? AFAIK, the code in OpticalPhysicsParams
and determining the discrete action is agnostic of the grid, other than the fact it will calculate some XS / MFP for a given energy value. It's definitely important whether we're using MFP vs macroscopic XS, but otherwise the code behaves mostly the same as in the EM case when dealing with these grids.
I believe @whokion has some preliminary interactors implemented. The absorption interactor is trivial (just returns an absorbed state -- might be fine with just an executor) and doesn't need to be super rigorously tested. Rayleigh is non-trivial, but hopefully I got enough code in here to draft what setting up its data and model would look like. I'll discuss getting another PR up for just the interactions and tests over slack. |
I can add OpticalRayInteractor (which I already have) once we decide how to build required optical data for the interactor - I was using OpticalRaylieghParams class, which can be absorbed to OpticalPhysicsParams or can be added too if we decide to have a separated data Params class for each model. Let's have a consensus first how we support optical material properties. |
@whokion I think the optical rayleigh model should have its own data independent of the physics. I assume it's not needed by the other models? |
@sethrj Yes, the Rayleigh data is independent from other models - actually, there is no required optical data for the OpticalRayleigh interactor if all mfp are taken care by the OpticalPhysicsParams class. It was not clear to me whether each model is responsible to import its own mfp along with other properties or OpticalPhysicsParams manages all mfp. |
The plan is for the models to provide the MFP at setup time (usually by just processing the imported optical data) for the "optical physics" to manage all together at runtime. |
… a map between GeoMaterialIds to OpticalMaterialIds
Made a PR for absorption and Rayleigh interactors here: #1317 |
…and different imported data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These model/Optical...
files should've been deleted, ignore them and I'll remove them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot of great work here! I think the scope of this is just too large for one person and one PR; I apologize for not partitioning the work among us. We'll definitely use all the work you've done here, but we need to break it into more bite-size chunks.
To start, let's drill down on just constructing and evaluating interaction lengths:
- Model
- AbsorptionModel with "not implemented" for the step action
- MfpBuilder
- The minimal subset of physics data (not params yet)
Let's talk about this monday?
struct ImportOpticalModel | ||
{ | ||
optical::ImportModelClass model_class; | ||
std::vector<ImportPhysicsVector> mfps; //!< per optical material MFPs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is redundant with the ImportOpticalMaterial
.{rayleigh,absorption,wls} data which already tells us the available models and stores absorption_length
(mfp): should we embed model information into the material data, or have separate model classes?
/*!
* Store optical material properties.
*/
struct ImportOpticalMaterial
{
ImportPhysicsVector refractive_index;
ImportScintData scintillation;
bool cerenkov{false};
//! Whether minimal useful data is stored
explicit operator bool() const
{
return static_cast<bool>(refractive_index);
}
};
struct ImportOpticalWLSModel
{
ImportPhysicsVector absorption_length; //!< Absorption length [MeV, len]
double mean_num_photons{}; //!< Mean number of re-emitted photons
double time_constant{}; //!< Time delay between absorption and re-emission
ImportPhysicsVector component; //!< Re-emission population [MeV, unitless]
explicit operator bool() const
{
return mfp && mean_num_photons > 0 && time_constant > 0
&& static_cast<bool>(absorption_length)
&& static_cast<bool>(component)
&& absorption_length.vector_type == ImportPhysicsVectorType::free
&& component.vector_type == absorption_length.vector_type;
}
};
struct ImportOpticalAbsorptionModel
{
ImportPhysicsVector absorption_length; //!< Absorption length [MeV, len]
explicit operator bool() const
{
return static_cast<bool>(absorption_length);
}
};
//! Number of optical materials | ||
OpticalMaterialId::size_type num_materials() const | ||
{ | ||
return num_materials_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be obtained from the size of properties already in the table:
return num_materials_; | |
return this->host_ref().refractive_index.size(); |
//! Construct with defaults | ||
Model(ActionId id, std::string const& label, std::string const& description) | ||
: ConcreteAction(id, label, description) | ||
{ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delegate the constructor:
//! Construct with defaults | |
Model(ActionId id, std::string const& label, std::string const& description) | |
: ConcreteAction(id, label, description) | |
{ | |
} | |
// Construct with ID, label, description | |
using ConcreteAction::ConcreteAction; |
} | ||
|
||
//! Build mean free path grids for all optical materials | ||
virtual void build_mfps(detail::MfpBuilder build) const = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
virtual void build_mfps(detail::MfpBuilder build) const = 0; | |
virtual void build_mfps(detail::MfpBuilder& build) const = 0; |
* Brief class description. | ||
* | ||
* Optional detailed class description, and possibly example usage: | ||
* \code | ||
MfpBuilder ...; | ||
\endcode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add documentation
GenericGridInserter inserter(&data.reals, &data.grids); | ||
std::vector<ValueGridId> grid_ids; | ||
|
||
model.build_mfps(detail::MfpBuilder{&inserter, &grid_ids}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The grid inserter should be outside this loop so that it can deduplicate data across models. I think we can also move most of this function into the implementation of MfpBuilder
, which could include all the builders: see celeritas/optical/detail/MatScintSpecInserter.hh
.
This is an initial implementation of optical models and their associated data structures.
General overview:
OpticalModel
: acts like both a process (building cross sections / mean free paths) and as a model (action to run the interactor).ImportedOpticalMaterials
: physics data for optical models is really just optical material properties. This serves as a list of imported optical material data that models will access directly to get their physics data.OpticalModelBuilder
: constructs theImportedOpticalMaterials
and is responsible for building the appropriate models based on the user's selection.OpticalPhysicsParams
: responsible for building each optical model, adding them to the action registry, and building their MFP grids inOpticalPhysicsParamsData
.OpticalMfpBuilder
: A helper class to have optical models build MFP grids on a per optical material basis.AbsorptionModel
: An almost trivial optical model. Has no data and just kills the track when called.RayleighModel
: A more complex optical model. Included to make sure API for building model-specific data is sensible.This PR isn't merge ready yet, and is meant to be a discussion point for how we want to organize optical models. Some functions and classes are empty, and I'm in the middle of adding tests.
Thoughts / discussion questions:
ImportData
:OpticalMaterialParams
? Is there ever a point where we need to processImportOpticalMaterial
s and store the data outside of optical model specific data collections?ImportOpticalModel
structure? A lambda table inImportOpticalModel
would duplicate the mean free paths inImportOpticalMaterial
...OpticalMfpBuilder
is a bit awkward. There should be a better way to do this that is also portable to Cerenkov and scintillation parameter building.