Skip to content

Conversation

@alexander-novo
Copy link
Collaborator

Description

Adds sparsity pattern computation into PowerElectronicsModel::allocate().

Closes #301

Checklist

Put an x in the boxes that apply. You can also fill these out after creating
the PR. If you're unsure about any of them, don't hesitate to ask. We're here
to help! This is simply a reminder of what we are going to look for before
merging your code.

  • All tests pass.
  • Code compiles cleanly with flags -Wall -Wpedantic -Wconversion -Wextra.
  • The new code follows GridKit™ style guidelines.
  • There are unit tests for the new code.
  • The new code is documented.
  • The feature branch is rebased with respect to the target branch.
  • I have updated CHANGELOG.md to reflect the changes in this PR. If this is a minor PR that is part of a larger fix already included in the file, state so.

Further comments

I added a couple of helper structs, but these are only there for cache locality and readability purposes. They are local to the function itself. Additionally, I made use of std::vector as a dynamically growing container, but all final products end up as simple pointers.

@alexander-novo
Copy link
Collaborator Author

alexander-novo commented Nov 11, 2025

I also wanted to add an additional comment on the removal of the short-circuiting condition in COO_Matrix::axpy():

I found out yesterday that IDA sets the alpha parameter to 0 during IDACalcIC(), which was causing the sparsity pattern to change. This (for some unknown reason) was what was causing KLU to segmentation fault. So this change also fixes the issue that @abdourahmanbarry noticed in his fault simulation.

Copy link
Collaborator

@pelesh pelesh left a comment

Choose a reason for hiding this comment

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

Great progress. Some design tweaks are needed but we are almost there..

Comment on lines 169 to 170
std::vector<std::vector<ComponentContribution>> reverse_map(size_);
std::vector<CsrSparsity> component_sparsities;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would avoid using STL containers here. What we need to do is to

  • populate row pointers and column indices in the CSR Jacobian matrix
  • have components store mapping from their Jacobian elements to the index of column indices array

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I cannot really remove the STL container for reverse_map... the size of the second level arrays are unknown ahead of time and need to be dynamically grown. I can remove the vector for component_sparsities, though

Comment on lines +151 to +159
// Helper struct for identifying a particular component's local system variable
struct ComponentContribution
{
// The index of the component in `components_`.
size_t comp_idx_;
// The local system variable index
size_t local_row_idx_;
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am not sure this is a good idea. Ideally, one should loop through components and components would read/write at locations determined by the connectivity information. The system composer should remain agnostic of specific details of the components.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well a component cannot write all of its info at once, so I must have some way of differentiating the different parts of info that a component needs to write at once.

@pelesh pelesh marked this pull request as draft November 12, 2025 16:18
Previously, axpy would do no work if a == 0, but this can change sparsity patterns.
Typically, a > 0 during simulations anyway, so this only affects when axpy's are done
e.g. before simulation, when memory is unset.
Also added a unit test which compares sparsity pattern generated by DependencyTracking::Variable and new sparsity pattern on microgrid problem.
@alexander-novo alexander-novo force-pushed the alloc-emt-system-sparsity branch from aab85f1 to 759f22f Compare November 12, 2025 16:41
@alexander-novo
Copy link
Collaborator Author

rebase w.r.t. develop

@alexander-novo alexander-novo changed the base branch from nicholson/real_type-Jacobians to develop November 12, 2025 16:41
@alexander-novo
Copy link
Collaborator Author

I changed the sparsity to be calculated into CsrMatrix object, but because of the aforementioned issue with the assignment operators' implementations in CsrMatrix, there is a use-after-free bug.

@nkoukpaizan maybe it's worth fixing? I can do some wonky stuff to try and avoid it but it seems to me like maybe it's better to just fix the bug?

@nkoukpaizan
Copy link
Collaborator

I changed the sparsity to be calculated into CsrMatrix object, but because of the aforementioned issue with the assignment operators' implementations in CsrMatrix, there is a use-after-free bug.

@nkoukpaizan maybe it's worth fixing? I can do some wonky stuff to try and avoid it but it seems to me like maybe it's better to just fix the bug?

Wouldn't it work if we stored csr_jac_ as a pointer, using new and deallocating in the system model's destructor? My understanding is that we don't want to use the assignment operator.

@alexander-novo
Copy link
Collaborator Author

I changed the sparsity to be calculated into CsrMatrix object, but because of the aforementioned issue with the assignment operators' implementations in CsrMatrix, there is a use-after-free bug.
@nkoukpaizan maybe it's worth fixing? I can do some wonky stuff to try and avoid it but it seems to me like maybe it's better to just fix the bug?

Wouldn't it work if we stored csr_jac_ as a pointer, using new and deallocating in the system model's destructor? My understanding is that we don't want to use the assignment operator.

That's the wonky stuff I meant. Is CsrMatrix only ever meant to exist on the heap, then? That should probably be mentioned somewhere.

@pelesh
Copy link
Collaborator

pelesh commented Nov 13, 2025

Wouldn't it work if we stored csr_jac_ as a pointer, using new and deallocating in the system model's destructor? My understanding is that we don't want to use the assignment operator.

I don't see are need to use assignment operator either (and it might be a good idea to delete it tbh). The implementation should go something like this:

  1. In constructor csr_jac_ is instantiated.
  2. In allocate function, NNZ is computed. After that, the Jacobian is allocated with the computed NNZ.
  3. Next (also in allocate), the sparsity pattern of the Jacobian is computed.

This is what is needed to address #301.

@alexander-novo
Copy link
Collaborator Author

Wouldn't it work if we stored csr_jac_ as a pointer, using new and deallocating in the system model's destructor? My understanding is that we don't want to use the assignment operator.

I don't see are need to use assignment operator either (and it might be a good idea to delete it tbh). The implementation should go something like this:

1. In constructor `css_jac_` is instantiated.

2. In `allocate` function, NNZ is computed. After that, the Jacobian is allocated with the computed NNZ.

3. Next (also in `allocate`), the sparsity pattern of the Jacobian is computed.

This is what is needed to address #301.

But as far as I can tell, there is no way to change the size of the matrix after construction. And the size of the system is not known at construction time for PowerElectronicsModel

@pelesh
Copy link
Collaborator

pelesh commented Nov 13, 2025

That's the wonky stuff I meant. Is CsrMatrix only ever meant to exist on the heap, then? That should probably be mentioned somewhere.

You could also have

class SystemSolverPowerElectronics
{
public:
  // some code

private:
  CsrMatrix jacobian_;
};

In that case Jacobian matrix would be instantiated with a default constructor and you would allocate it and populate its data arrays. That wouldn't change much in the approach.

@pelesh
Copy link
Collaborator

pelesh commented Nov 13, 2025

But as far as I can tell, there is no way to change the size of the matrix after construction. And the size of the system is not known at construction time for PowerElectronicsModel

You implemented CsrMatrix class, so feel free to add methods that may be needed for the system Jacobian assembly. 😄 Adding a resize method would make sense to me in this case.

@alexander-novo
Copy link
Collaborator Author

I copied the implementation from ReSolve, I'm not really familiar with how it works. It kind of seemed to me like there may have been a good reason why there wasn't a resize() method. Would a resize() method that simply sets m,n be correct?

@alexander-novo
Copy link
Collaborator Author

Well, as far as I can tell m_ is used for nothing and n_ is just used for allocating memory, so I think it should probably be harmless to just modify them. Please let me know.

@alexander-novo
Copy link
Collaborator Author

Okay, I went ahead an imposed the correct system vector ordering. The Microgrid examples already have this ordering, but I did have to change the RLCircuit example to have the correct ordering.

Now that the ordering is required to be nice, I went ahead and updated the jacobian sparsity computations to take advantage of it - first the internal rows are done component-by-component, then the heavier reverse-mapping machinery is invoked only for the external rows.

I also realized that I could use the sum of the component Jacobian nnzs as an upper bound for the system Jacobian nnz value and got rid of the vector for global_col_indices by just pre-allocating this upper bound. I don't think that this will be too big an over-estimate to be concerned about the wasted memory.

@alexander-novo
Copy link
Collaborator Author

@pelesh I implemented what we discussed at the SciDAC meeting, and am not depending on the components having their jacobians in CSR form anymore (just using COO).

The two outstanding pieces of feedback, though, I'm waiting for your feedback on. Maybe we can talk about them in a code review?

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.

Implement analysis in SystemModelPowerElectronics class to compute system Jacobian sparsity pattern

4 participants