-
Notifications
You must be signed in to change notification settings - Fork 18
Implement _collection_ref to link objects to their NumberedObjectCollection parent #867
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
base: develop
Are you sure you want to change the base?
Conversation
|
Thanks for doing this. I'll probably look at this in the next few days. |
MicahGale
left a comment
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 didn't fully evaluate how this works, but I think there are some design changes needed first.
|
// Ipynd files got updated with
|
|
Append to Collection:
Append with Renumber:
Number Changes (500 ops):
Deepcopy Problem:
Detailsimport copy
import time
import montepy
def benchmark_append_to_collection(n_objects: int) -> float:
"""Benchmark appending N objects to a fresh collection."""
collection = montepy.Cells()
cells = [montepy.Cell(f"{i+1} 0 -1") for i in range(n_objects)]
start = time.perf_counter()
for cell in cells:
collection.append(cell)
return time.perf_counter() - start
def benchmark_append_renumber(n_objects: int) -> float:
"""Benchmark appending N objects with renumbering."""
collection = montepy.Cells()
cells = [montepy.Cell(f"{i+1} 0 -1") for i in range(n_objects)]
start = time.perf_counter()
for cell in cells:
collection.append_renumber(cell)
return time.perf_counter() - start
def benchmark_number_changes(n_objects: int) -> float:
"""Benchmark changing object numbers."""
problem = montepy.read_input("tests/inputs/test.imcnp")
base_num = 10000
for i in range(n_objects):
cell = montepy.Cell(f"{base_num + i} 0 -1")
problem.cells.append(cell)
cells = list(problem.cells)
start = time.perf_counter()
for i in range(500):
cell = cells[i % len(cells)]
old_num = cell.number
cell.number = old_num + 100000
cell.number = old_num
return time.perf_counter() - start
def benchmark_deepcopy(n_objects: int) -> float:
"""Benchmark deepcopy of a problem."""
problem = montepy.read_input("tests/inputs/test.imcnp")
for i in range(n_objects):
cell = montepy.Cell(f"{1000 + i} 0 -1")
problem.cells.append(cell)
start = time.perf_counter()
_ = copy.deepcopy(problem)
return time.perf_counter() - start
def print_table(name: str, sizes: list[int], benchmark_func):
"""Run benchmark and print simple table."""
print(f"\n{name}:")
print(f"{'Objects':<10} | {'Time (s)':<12}")
print(f"{'-'*10} | {'-'*12}")
for size in sizes:
elapsed = benchmark_func(size)
print(f"{size:<10} | {elapsed:<12.4f}")
def main():
print("=" * 40)
print("MontePy _collection_ref Benchmark")
print("=" * 40)
sizes = [100, 200, 500, 1000, 4000, 8000]
small_sizes = [100, 200, 500, 1000]
print_table("Append to Collection", sizes, benchmark_append_to_collection)
print_table("Append with Renumber", sizes, benchmark_append_renumber)
print_table("Number Changes (500 ops)", small_sizes, benchmark_number_changes)
print_table("Deepcopy Problem", sizes, benchmark_deepcopy)
# Sanity check
print(f"\n{'='*40}")
print("Sanity Check:")
problem = montepy.read_input("tests/inputs/test.imcnp")
cell = list(problem.cells)[0]
if hasattr(cell, "_collection_ref") and cell._collection is not None:
print(f" ✓ _collection_ref is working")
else:
print(f" ✗ _collection_ref is NOT set")
print("=" * 40)
if __name__ == "__main__":
main() |
MicahGale
left a comment
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 a big improvement, and much more like what I was thinking. I have some more feedback, but it is not major.
Looking at the data you collected this does look like it is indeed linear (O(N)), so that's great that it is no longer O(N^2). I have been thinking more about how to present performance data recently. I think in general, rates should generally be used (e.g., objects/second) over just raw time. My last paper on this though did not use rates, so I'm working on this as well.
|
I can try data in object/second |
|
Append to Collection:
Append with Renumber:
Number Changes (500 ops):
Deepcopy Problem:
|
Pull Request Checklist for MontePy
Description
Added a
_collection_refas a weak_ref which points the object back to its collection.Problems
deepcopygot messed up link "number already in use" another failed test due to surface conflicts._cellpointed to wrong cell objects.Solution:
Rebuild cache after
deepcopyinstead of overwriting_collection_ref.Added
_set_cell methodtohalfspaceDetails
Fixes #849
General Checklist
blackversion 25.LLM Disclosure
Were any large language models (LLM or "AI") used in to generate any of this code?
Documentation Checklist
First-Time Contributor Checklist
pyproject.tomlif you wish to do so.Additional Notes for Reviewers
Ensure that:
📚 Documentation preview 📚: https://montepy--867.org.readthedocs.build/en/867/