mit-crpg / OpenMOC

A method of characteristics code for nuclear reactor physics calculations.
https://mit-crpg.github.io/OpenMOC/
Other
149 stars 83 forks source link

Automate Pin Cell Coolant Radial Discretization #230

Closed wbinventor closed 8 years ago

wbinventor commented 8 years ago

We really need to make it simple and easy to discretize the coolant around a fuel pin. Although a user can radially discretize fuel pins and the clad with the Cell.setNumRings(...) routine, this may not be used to discretize an "unbounded" Cell such as the coolant. We should come up with a systematic and agreed upon way to extend our automated radial discretization to the unbounded Cells, since it is particularly important for the moderator.

I'm not yet sure how best to go about this yet. But I really need a method implemented to do this to simplify the workflow for the simulations I'm currently running. If anyone has any ideas on a nice robust way to go about this, post them here!

nathangibson14 commented 8 years ago

Equal volume doesn't make a whole lot of sense for unbounded cells. But you could definitely do fixed delta radius rings. I'd recommend putting in "setNumRings" and "setRingWidth" for these cells.

The other option would be to make some stencils for common discretizations and build those into the code. So you could request a "pin-cell, fine" or "pin-cell, coarse" rather than setting the surfaces all yourself. If we want some weird stencils, this is the way to go, but I haven't heard any of us wanting to do that. Hebert talked about a pretty weird stencil he uses in the last talk I saw from him, so it's not unreasonable to think about this, but I don't think we need it now.

On 12/06/2015 09:03 PM, Will Boyd wrote:

We really need to make it simple and easy to discretize the coolant around a fuel pin. Although a user can radially discretize fuel pins and the clad with the |Cell.setNumRings(...)| routine, this may not be used to discretize an "unbounded" |Cell| such as the coolant. We should come up with a systematic and agreed upon way to extend our automated radial discretization to the unbounded |Cells|, since it is particularly important for the moderator.

I'm not yet sure how best to go about this yet. But I really need a method implemented to do this to simplify the workflow for the simulations I'm currently running. If anyone has any ideas on a nice robust way to go about this, post them here!

— Reply to this email directly or view it on GitHub https://github.com/mit-crpg/OpenMOC/issues/230.

wbinventor commented 8 years ago

@PrezNattyGibbs - I like your idea of a Cell:setRingWidth(...) and/or Cell::setRingWidths(...) method. One of the downsides of this type of API is that it is very hard-coded to the cylindrical coordinate system (albeit, so are the current Cell::setNumRings(...) and Cell::setNumSectors(...) methods). We might also add optional max_radius and conserve parameters to the Cell::setNumRings(...) method. These might have defaults like max_radius=-1 and preserve="volume" to preserve the current behavior of equi-volume rings with automated max radius detection. But the parameters could also accept positive floating point values for the maximum radius and the string "delta radius", respectively.

An alternative could be a separate "meshing" module that abstracts the discretization away from the general and arbitrary Cell class. I have such an implementation in OpenCG, but it does require more code in the input to discretize a pin with this type of abstraction. Because of this, and since OpenMOC is fairly well focused on cylindrical geometries like those in LWRs, I'm inclined to think that the abstraction - while nice from an OO standpoint - is less preferable to a user than what you propose.

Also, by "stencil" in this context do you mean some pre-set spacing of radial rings?

wbinventor commented 8 years ago

I may take a stab this weekend at implementing something to do moderator discretization. samuelshaner and @geogunow do you have any thoughts on this that I should consider before I start?

geogunow commented 8 years ago

I'm not entirely sure what you mean by unbounded cell. Don't we have rings in the moderator? Aren't those bound?

wbinventor commented 8 years ago

One has to explicitly define rings in the moderator right now - see this example for our C5G7 problem. The issue is that it is not convenient explicitly define moderator ring cells every time one models a geometry. This is especially the case when computes MGXS for a problem with OpenMC - where moderator rings are not needed or wanted - and then uses those MGXS in OpenMOC on the same spatial mesh but where moderator rings are indeed needed.

samuelshaner commented 8 years ago

I'll throw out one more option to consider:

Subdivide unbounded cells using pitch of closest parent Lattice The cells are not subdivided until the entire geometry is input, so within the CSG framework it is feasible to get the pitch of a Cell's closest parent Lattice (i.e. this would typically be a Cell's parent Universe's parent Lattice) or the Geometry (if no parent Lattice exists). With this in mind, an option that could work within the current framework and require no further user input besides setting the number of rings and sectors for the unbounded cell is to structure the subdivide cells routines to be recursive. The Geometry::subdivideCells() routine would be called only on the root universe and would pass the "pitch" of the geometry (i.e. (width + height) / 2) to the Universe::subdivideCells() routine. The Universe::subdivideCells() routine would be changed to something like:

void Universe::subdivideCells(double pitch) {

    log_printf(DEBUG, "Subdividing Cells for Universe %d", _id);

    std::map<int, Cell*>::iterator iter1;

    while (iter1 != _cells.end()) {
        for (iter1 = _cells.begin(); iter1 != _cells.end(); ++iter1) {

        if (((*iter1).second)->getType() == MATERIAL) {
           Cell* cell = (*iter1).second;

           if (cell->getNumRings() > 0 || cell->getNumSectors() > 0)
             cell->subdivideCell(pitch);
        }
        else {
          ((*iter1).second)->subdivideCells(pitch);
        }
    }
}

void Lattice::subdivideCells(double pitch) {

    log_printf(DEBUG, "Subdividing Cells for Lattice %d", _id);

    std::map<int, Universe*>::iterator iter1;
    std::map<int, Universe*> universes = getUniqueUniverses();

    pitch = (_width_x + _width_y) / 2.0;

    while (iter1 != universes.end()) {
        for (iter1 = universes.begin(); iter1 != universes.end(); ++iter1) {
          ((*iter1).second)->subdivideCells(pitch);
        }
    }
}

The Cell::subdivideCell() and Cell::ringify() methods would need to be modified to accept a pitch as well. The Cell::ringify() would then need to use the pitch in computing equi-volume rings if the cell is unbounded. This seems like it should work for pin cells as well as complex LWR geometries like BEAVRS, but has at least one caveat. This caveat would be that if a cell is placed in two lattices with different pitches, the Cell would only be ringified based on the first lattice encountered.

wbinventor commented 8 years ago

@samuelshaner I think this is a good idea. It is somewhat similar to the recursive bounding box scheme in OpenCG (though less general, but I really don't want to implement that in OpenMOC right now). @PrezNattyGibbs @geogunow any comments on Sam's proposal?

wbinventor commented 8 years ago

Thanks @samuelshaner for the inspiration! It served as the basis for my implementation for #239. Although there were a few minor complications beyond the tweaks you proposed, most of it directly followed from your example code. The main difference is that instead of passing the lattice pitch, I pass the lattice diagonal - this allows our moderator rings to extend out into the corners of a lattice (i.e., the largest ring in the moderator is just large enough to completely surround the interior lattice cell.