简体   繁体   中英

Executing multiple self-avoiding walks, recursively

I have a 3D simple cubic lattice, which I call Grid in my code, with periodic boundary conditions of size 20x20x20 (number are arbitrary). What I want to do is plant multiple polymer chains with a degree of polymerization N (graphs with N nodes) that do no overlap, are self-avoiding.

At the moment, I can plant one polymer recursively. This is my code

const std::vector <int> ex{1,0,0}, nex{-1,0,0}, ey{0,1,0}, ney{0,-1,0}, ez{0,0,1}, nez{0,0,-1};     // unit directions 
const std::vector <std::vector <int>> drns = {ex, nex, ey, ney, ez, nez};                           // vector of unit directions 

void Grid::plant_polymer(int DoP, std::vector <std::vector <int>>* loc_list){
    // loc_list is the list of places the polymer has been 
    // for this function, I provide a starting point 
    if (DoP == 0){
        Polymer p (loc_list); 
        this->polymer_chains.push_back(p); // polymer_chains is the attribute which holds all polymer chains in the grid 
        return; // once the degree of polymerization hits zero, you are done
    }; 

    // until then 
    // increment final vector in loc_list in a unit direction 
    std::vector <int> next(3,0); 
    for (auto v: drns){

        next = add_vectors(&((*loc_list).at((*loc_list).size()-1)), &v);
        
        impose_pbc(&next, this->x_len, this->y_len, this->z_len); 
        
        
        if (this->occupied[next]==0){ // occupied is a map which takes in a location, and spits out if it is occupied (1) or not (0)
// occupied is an attribute of the class Grid
            dop--; // decrease dop now that a monomer unit has been added 
            (*loc_list).push_back(next); // add monomer to list 
            this->occupied[next] == 1; 
            return plant_polymer(DoP, loc_list); 
        } 
    }


    std::cout << "no solution found for the self-avoiding random walk...";
    return; 

This is not a general solution. I am providing a seed for the polymer, and also, I am only planting one polymer. I want to make it such that I can plant multiple polymers, without specifying a seed. Is it possible to recursively hunt for a starting position, every time I want to add a polymer, and then build a polymer while making sure it is not overlapping with other polymers already in the system? Any advice you have would be appreciated.

Self-avoiding walks has been studied at least since the 1960s and there's a vast literature on them. Fortunately, the problem you face belong to the simplest ones (walks' length is fixed at a relatively small value).

1

The first thing you should be aware of is that your question is too broad to have a unique answer. That is, if you plant many polymers in the system, the result you're going to get depends on the dynamics of the polymer planting and growing. There are two major cases. Either you plant a number of seeds and start growing polymers from them, or you grow each polymer "elsewhere" and then try to plant them in the system at a random location, one by one, keeping the condition of self-avoidance. The two methods will result in statistically different distributions of polymers, and there's nothing you can do about it, except to specify the system dynamics in more detail.

I believe the second approach is a bit easier, as it saves you from deciding what to do if some polymers cannot grow to the desired length (restart the simulation?), so let's focus just on it.

The general algorithm might look like this:

  • Set maximum_number_of_attempts to reasonably large, but not too large a value, say a million
  • Set required_number_of_polymers to the required value
  • Set number_of_attempts to 0
  • Set number_of_planted_polymers to 0
  • While number_of_attempts < maximum_number_of_attempts AND number_of_planted_polymers < required_number_of_polymers
    • increase number_of_attempts by 1
    • generate the next random polymer
    • chose a random position (lattice site) in the system
    • check if the polymer can be planted at this position without intersections
    • if and only if yes,
      • accept the polymer (add it to the list of polymers; update the list of occupied lattice nodes)
      • increase number_of_planted_polymers by 1

To speed thing up, you can be choosing the initial positions only from unoccupied sites (eg in a while loop). Another idea is to try and use a polymer, on its first plating failure, several times (but not too many, you'd need to experiment) at different positions.

2

Now the next step: how to generate a self-avoiding random walk. Your code is almost OK, except for a few misconceptions.

In function void Grid::plant_polymer there's one grave error: it always performs the search in the space of possible polymer shapes in exactly the same order . In other words, it is deterministic. For Monte Carlo methods it sounds like a disaster. One thing you might do to handle it is to randomly shuffle the directions.

  auto directions = drns;
  std::shuffle(begin(directions), end(directions), random_generator); // c++17
  for (const auto & v: directions)
  {
    ...

For this to work, you'll need a random number generator already defined and initialized, eg

    std::random_device rd;
    std::mt19937 random_generator(rd());

somewhere much earlier, and only once, in the program.

If you don't use C++17, use std::random_shuffle instead of std::shuffle , but be warned that the latter has been depreciated, see https://en.cppreference.com/w/cpp/algorithm/random_shuffle for the discussion why.


As a side remark, when asking a specific software-related question, please try and provide a Minimal, reproducible example . Answering questions based only on reading code is almost always more time-consuming, and the answers tend to be more sketchy and less accurate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM