idaholab / MontePy

MontePy is the most user friendly Python library (API) to read, edit, and write MCNP input files.
https://www.montepy.org/
MIT License
30 stars 6 forks source link

Optimize Material Update Pointers #518

Closed MicahGale closed 1 month ago

MicahGale commented 1 month ago

Description

This is a fix of a really inefficient implementation of how Material and ThermalScattering are linked together during problem setup. The issue is that in MCNP_Problem:

for data_input in self.data_inputs:
    data_input.update_pointers(self.data_inputs)

This in itself isn't an issue; this is just an O(N) operator, and it's necessary.

But inside of both Material and ThermalScattering there was:

def update_pointers(self, data_innputs):
    for data_input in data_inputs:
        ...

So this effectively became:

for data_input_1 in data_inputs:
    for data_input_2 in data_inputs:
        ...

This is an O(N2) operation. Yikes!

To fix this, I changed:

  1. Removed all code from Material.update_values
  2. Move all linking to ThermalScattering.update_value
  3. Use problem.materials hashing as much as possible to perform the linking operation.

This changes the benchmark run time from 424 seconds to 26 second, a speed up of 398 seconds, or 93%.

The old profiling of the benchmark test:


   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000  272.390  272.390 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/input_parser/input_reader.py:6(read_input)
        1    0.026    0.026  272.390  272.390 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/mcnp_problem.py:236(parse_input)
        1    0.002    0.002  253.773  253.773 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/mcnp_problem.py:304(__update_internal_pointers)
     1001    0.363    0.000  252.721    0.252 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/material.py:173(update_pointers)
   501501    0.203    0.000  250.632    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/material.py:259(__eq__)
   501501   51.196    0.000  250.090    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/material.py:243(__hash__)
 46138092   61.034    0.000   87.767    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/isotope.py:213(__str__)
 50688652   25.463    0.000   47.373    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/utilities.py:76(getter)
 45636591   28.897    0.000   35.159    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/isotope.py:221(__lt__)
 46138092   11.372    0.000   15.170    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/element.py:19(symbol)
 46230184    8.718    0.000   13.946    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/isotope.py:218(__hash__)
     2004    0.013    0.000   13.050    0.007 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/data_parser.py:29(parse_data)
     1001    0.194    0.000   12.057    0.012 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/material.py:33(__init__)
    22041    0.047    0.000   11.893    0.001 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/mcnp_object.py:37(__init__)
     7015    0.017    0.000   11.790    0.002 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/input_parser/parser_base.py:133(parse)

With the vast majority of the costliest operations all being in montepy.data_inputs.Material, with update_pointers taking > 250 seconds.

After this change the new profiling is:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   21.367   21.367 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/input_parser/input_reader.py:6(read_input)
        1    0.026    0.026   21.366   21.366 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/mcnp_problem.py:236(parse_input)
     2004    0.012    0.000   13.293    0.007 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/data_parser.py:29(parse_data)
    22041    0.047    0.000   12.626    0.001 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/mcnp_object.py:37(__init__)
     7015    0.017    0.000   12.523    0.002 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/input_parser/parser_base.py:133(parse)
     1001    0.197    0.000   12.062    0.012 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/material.py:33(__init__)
    19033    0.021    0.000   11.837    0.001 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/data_input.py:55(__init__)
   408452    0.151    0.000    3.058    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/input_parser/mcnp_input.py:200(tokenize)
  4051061    1.811    0.000    3.025    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/utilities.py:76(getter)
     6009    0.176    0.000    2.980    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/numbered_object_collection.py:192(append)
  1514516    0.555    0.000    2.770    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/numbered_object_collection.py:75(numbers)
        1    0.002    0.002    2.539    2.539 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/mcnp_problem.py:304(__update_internal_pointers)
   194205    0.257    0.000    1.876    0.000 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/input_parser/parser_base.py:304(padding)
     1001    0.305    0.000    1.442    0.001 /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/montepy/data_inputs/thermal_scattering.py:119(update_pointers)

Now this operation takes 1.5 seconds.

Fixes #510

Checklist

MicahGale commented 1 month ago

Consider printing fewer stats, but looks good.

Did you look at the output? The number of row filters is applied before the function regex. So it's not printing 300 lines.