Skip to content

Seeding examples for 1D environment of S&H 2012 as well as 2D environment of M&G2007 #1396

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

Open
wants to merge 55 commits into
base: main
Choose a base branch
from

Conversation

jtbuch
Copy link
Collaborator

@jtbuch jtbuch commented Oct 3, 2024

Update toward solving a subset of goals raised in #1387.

Specifically, I included functionality for selecting cell id, cell origin, and position in cell of the seeded super-droplets (SDs) in Shipway and Hill's (SH2012) kinematic driver environment. For this I had to modify seeding.py, particulator.py, as well as the backend seeding_methods.py files in a way that does not seem to be straightforwardly backward compatible with the parcel model example that @slayoo introduced earlier.

I also made another major assumption: rather than simply using a default value of water mass for the seeded SDs, I update it using the volume attribute derived from the wet, rather than dry, radius of seed SDs at the time of injection. If I use the dry radius, the resulting precipitation is significantly lower. This might be a subtle point that is worth discussing in some detail, even if it is for my own personal clarification.

Here's the .ipynb file containing the full example.

@jtbuch jtbuch requested review from claresinger and slayoo October 3, 2024 01:50
@jtbuch jtbuch mentioned this pull request Oct 3, 2024
Copy link
Collaborator

@claresinger claresinger left a comment

Choose a reason for hiding this comment

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

Some initial comments.

Something looks odd to me in the plot of superdroplet count over time for the seeding vs. no seeding case. Why in the seeding case is the sd count constant at 32 during the seeding interval?

) # TODO #1387: does not have to be the same?
v_dry = settings.formulae.trivia.volume(radius=r_dry)
self.seeded_particle_extensive_attributes = {
"water mass": np.array([0.0001 * si.ng] * settings.n_sd_seeding),
Copy link
Collaborator

Choose a reason for hiding this comment

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

should we use equilibrate_wet_radii rather than prescribing a water_mass for the seeds?

@jtbuch
Copy link
Collaborator Author

jtbuch commented Oct 8, 2024

Something looks odd to me in the plot of superdroplet count over time for the seeding vs. no seeding case. Why in the seeding case is the sd count constant at 32 during the seeding interval?

That is due to the int type casting while plotting the mean SD count. I have fixed it now and it looks better here

However, this made me wonder: why are the number of SDs decreasing with time initially even in the no seeding case?

@claresinger
Copy link
Collaborator

However, this made me wonder: why are the number of SDs decreasing with time initially even in the no seeding case?

This is a good question... I thought it was just precip, but the sd_count is decreasing even before precip onset (and actually faster in the initial time than during the precip period). Is there some spin-up that's happening? I don't know why that wouldn't conserve SDs though.

@slayoo
Copy link
Member

slayoo commented Oct 10, 2024

However, this made me wonder: why are the number of SDs decreasing with time initially even in the no seeding case?

This is a good question... I thought it was just precip, but the sd_count is decreasing even before precip onset (and actually faster in the initial time than during the precip period). Is there some spin-up that's happening? I don't know why that wouldn't conserve SDs though.

I expect it to be caused by the updraft which is only present during the first settings.t_1 seconds (10 minutes). It pushes super droplets beyond the top of the domain.

@claresinger
Copy link
Collaborator

I expect it to be caused by the updraft which is only present during the first settings.t_1 seconds (10 minutes). It pushes super droplets beyond the top of the domain.

Oh, this totally makes sense. Thanks, Sylwester!

@jtbuch
Copy link
Collaborator Author

jtbuch commented Jun 4, 2025

Hi @slayoo and @claresinger, I have committed examples for seeding in both 1D and 2D environments that are compatible with the latest PySDM version. Any comments or criticisms would be much appreciated!

@jtbuch jtbuch changed the title Seeding example for 1D environment of S&H 2012 Seeding examples for 1D environment of S&H 2012 as well as 2D environment of M&G2007 Jun 4, 2025
@jtbuch jtbuch requested a review from slayoo June 4, 2025 20:45
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this the same as the kinematic_1d.py file in the PySDM environments? This seems like a lot of code duplication. What have you added? Can it just extend this environment instead of copy/pasting?

Copy link
Collaborator

Choose a reason for hiding this comment

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

This may be a useful function to have outside of the seeding example. Should it go somewhere common like here? https://github.com/open-atmos/PySDM/tree/main/PySDM/exporters

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you write this so it extends the ShipwayHill settings.py? See how it is done here settings1D.py.

Copy link
Collaborator

Choose a reason for hiding this comment

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

plot time on the x-axis in last cell figures

Copy link
Collaborator

Choose a reason for hiding this comment

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

plot time on x-axis in last cell figures

Copy link
Collaborator

Choose a reason for hiding this comment

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

can/should a simulation_common.py file be used for the parcel (0D), 1D, and 2D cases and have all the common ingredients about Dynamics and Products and initialisation?

@jtbuch
Copy link
Collaborator Author

jtbuch commented Jun 19, 2025

Hi @slayoo , @claresinger and I were discussing a potential issue with the Seeding dynamic as implemented. As you see in this attached plot for 1D seeding (it's also the case in the parcel model) below, the number of super-droplets does not change as expected. Specifically, when the seeding dynamic is called, instead of adding the seed super-droplets to the existing super-droplet buffer, it adds it to the initial buffer state. When it's done, the number of super-droplets returns to the (decreased) number of super-droplets with the additional seed ones.

I think this is due to the way attributes are initialized in the __call()__ method here:

self.post_register_setup_when_attributes_are_known()

Unclear, how tricky the fix might be.

Screenshot 2025-06-19 at 12 07 53 PM

@jtbuch
Copy link
Collaborator Author

jtbuch commented Jun 19, 2025

I see your point, @slayoo . I have now removed the update step for cell id etc. but still continue to see the same issue of the whole buffer getting updated when seeding.

@slayoo
Copy link
Member

slayoo commented Jun 19, 2025

I see your point, @slayoo . I have now removed the update step for cell id etc. but still continue to see the same issue of the whole buffer getting updated when seeding.

I must say, I don't yet understand what you described. How does it show up in the parcel model? In the "hello-world" seeding example (https://github.com/open-atmos/PySDM/blob/main/examples/PySDM_examples/seeding/hello_world.ipynb) we clearly see an increase in SD count.

@jtbuch
Copy link
Collaborator Author

jtbuch commented Jun 19, 2025

I must say, I don't yet understand what you described. How does it show up in the parcel model? In the "hello-world" seeding example (https://github.com/open-atmos/PySDM/blob/main/examples/PySDM_examples/seeding/hello_world.ipynb) we clearly see an increase in SD count.

Yes, sorry, this is not an issue in the parcel model (I incorrectly wrote that earlier) since the number of super-droplets does not change between the start of the simulation and the seeding timestep. This assumption does not translate to 1D and 2D where the number of super-droplets decreases as they are pushed outside the domain.

@jtbuch
Copy link
Collaborator Author

jtbuch commented Jun 23, 2025

@slayoo I verified the increase in super-droplet count by calculating the total number of super-droplets for each simulation timestep in the 1D example. The count starts at 2336, reduces to 2059 before increasing to 2337 after adding 1 super-droplet. It keeps increasing to 2395 till the end of the seeding period before sharply reverting to 1881.

Screenshot 2025-06-23 at 3 18 33 PM

Copy link
Member

Choose a reason for hiding this comment

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

doing

np.random.seed(123)
...
formulae= Formulae(seed= np.random.randint(1000)),

seems misleading - would it be more readable to pass the 123 to Formulae ctor?

self.products += [
PySDM_products.WaterMixingRatio(
name="cloud water mixing ratio",
unit="g/kg",
Copy link
Member

Choose a reason for hiding this comment

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

since it is a non-SI unit, suggest renaming the var to cloud water mixing ratio [g/kg]

radius_range=settings.cloud_water_radius_range,
),
PySDM_products.WaterMixingRatio(
name="rain water mixing ratio",
Copy link
Member

Choose a reason for hiding this comment

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

ditto

name="rain averaged terminal velocity",
radius_range=settings.rain_water_radius_range,
),
PySDM_products.AmbientRelativeHumidity(name="RH", unit="%"),
Copy link
Member

Choose a reason for hiding this comment

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

since the unit is non-SI, suggest renaming to "RH [%]"

PySDM_products.RipeningRate(name="ripening"),
PySDM_products.ActivatingRate(name="activating"),
PySDM_products.DeactivatingRate(name="deactivating"),
PySDM_products.PeakSaturation(unit="%"),
Copy link
Member

Choose a reason for hiding this comment

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

since the unit is non-SI, suggest renaming to "... [%]"

Copy link
Member

Choose a reason for hiding this comment

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

as we have multiple simulations in one notebook, sharing a single backend instance across simulations could significantly reduce runtime by avoiding JIT-compiling the same code multiple times.

Copy link
Member

Choose a reason for hiding this comment

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

the realisation spread is definitely worth checking here - how the relevant output fluctuates across simulations with the same settings but different random seeds - sharing backend across simulations will speed things up then as well

@slayoo
Copy link
Member

slayoo commented Jun 29, 2025

@slayoo I verified the increase in super-droplet count by calculating the total number of super-droplets for each simulation timestep in the 1D example. The count starts at 2336, reduces to 2059 before increasing to 2337 after adding 1 super-droplet. It keeps increasing to 2395 till the end of the seeding period before sharply reverting to 1881.
Screenshot 2025-06-23 at 3 18 33 PM

@jtbuch Just confirming I've reproduced it locally and I'm trying to figure out what is the origin of these super-droplet-count jumps

@slayoo
Copy link
Member

slayoo commented Jun 29, 2025

@jtbuch, not necessarily related to the sd-count-per-cell issue, but it seems that as of now:

  • position attributes of seed droplets are initialised to zeros
  • the Displacement dynamic still advects these particles
  • as a result these are seeded to the sixth cell (because the first 5 minutes are enough to move them up by six cells)

Likely not intentional. We should probably modify the displacement dynamic to ignore particles with zero multiplicity, and then to set different than zero position attributes to spawn the seed particles where intended.

@slayoo
Copy link
Member

slayoo commented Jun 29, 2025

as for the SD-count jumps, I'm inclined to blame the incompatibility of seeding with the cell_start-computing logic here:

def _counting_sort_by_cell_id_and_update_cell_start(
new_idx, idx, cell_id, cell_idx, length, cell_start
):
cell_end = cell_start
# Warning: Assuming len(cell_end) == n_cell+1
cell_end[:] = 0
for i in range(length):
cell_end[cell_idx[cell_id[idx[i]]]] += 1
for i in range(1, len(cell_end)):
cell_end[i] += cell_end[i - 1]
for i in range(length - 1, -1, -1):
cell_end[cell_idx[cell_id[idx[i]]]] -= 1
new_idx[cell_end[cell_idx[cell_id[idx[i]]]]] = idx[i]

We need to start with writing a unit test for multi-cell seeding to isolate the problem within a single step and a simplest possible setup (e.g., two cells, two super droplets, etc) - contributions welcome

@jtbuch
Copy link
Collaborator Author

jtbuch commented Jul 1, 2025

Thank you, @claresinger and @slayoo for your helpful review! I will address these now and then respond to some of the major comments that @slayoo raised.

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