Dispersion Model (turtle based)

No preview image

1 collaborator

Tags

(This model has yet to be categorized with any tags)
Visible to everyone | Changeable by the author
Model was written in NetLogo 5.2.0-RC4 • Viewed 687 times • Downloaded 46 times • Run 0 times
Download the 'Dispersion Model (turtle based)' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


WHAT IS IT?

This is an agent-based approach to modeling continuous-flow chemical reactors. By using simple agent-level rules to recreate a number of known reaction engineering phenomena, the model is designed to serve as an educational tool for chemical engineering students. With further validation and development, the model could in principle be used to design and simulate real chemical reactors, albeit at very high computational cost relative to equation-based methods.

The scope of the model is analogous to that of the convection-dispersion-reaction system taught in undergraduate chemical engineering courses. Namely, fluid dynamics and bulk diffusion effects are rolled into a single diffusion mechanism named dispersion.

The model operates from the Lagrangian reference frame, as all notable actions are assigned to mobile turtles. For the Eulerian reference frame, see the accompanying model in the RELATED MODELS section below.

HOW IT WORKS

The reactor is oriented such that the feed stream enters at the left boundary and leaves at the right boundary. The model contains three types of molecular entities: Reactants are blue turtles, Products are red turtles, and Inerts are yellow turtles.

On setup, the far left column of patches sprout reactant at a user-specified concentration (number per patch). If the FILL-REACTOR? option is switched on, all patches are filled with reactant in this manner.

A significant portion of the code was written for analysis purposes and is not relevant to the function of the reactor. Consequently, all such code has been omitted:

At each tick:

1. Reactants react at a rate determined by the specified reaction mechanism.  Three reaction mechanisms are available:
    a. Concentration-Independent: Reactant turtles are randomly converted to products, with probability equal to the REACTION-PROBABILITY.
    b. Concentration-Dependent: Reactant turtles are randomly converted to products, with probability equal to the product of the REACTION-PROBABILITY and the number of other reactants within the reactant's COLLISION-RADIUS.
    c. Bimolecular: Pairs of reactant turtles are converted to products with probability equal to the REACTION-PROBABILITY, but only if two or more reactants are within the COLLISION-RADIUS.

    When a unimolecular reaction occurs, the reactant changes its breed to product.
    When a bimolecular reaction occurs, the primary reactant asks the other reactant within its COLLISION-RADIUS to die. It then changes its breed to product.  


2. All molecules are affected by two modes of transport:
    a. Convection --> Molecules are uniformly transported downstream at the specified FEED-VELOCITY.  The molecules do not immediately move to their new position, but rather store their projected coordinates. 
    b. Diffusion --> Molecules undergo 1-D random walk diffusion by moving forward or backward.  If RANDOM-DIFFUSION? is on, the step size is a random distance less than the DIFFUSIVITY.  If RANDOM-DIFFUSION? is off, the step size is the DIFFUSIVITY. The molecules do not immediately move to their new position, but rather add their projected random walk to the coordinates projected during the convection step. 


3. The effluent is analyzed:    
    a. All molecules with a projected position beyond the end of the reactor are added to the effluent stream agentset.
    b. The number and type of molecules entering and leading the reactor are stored such that they may be analyzed later.

4. Molecular motion is executed
    a. All molecules in the effluent are asked to die.
    b. All molecules with projected position before the feed to the reactor are moved to the reactor inlet.
    c. All other molecules are moved to their projected position.
    d. All surviving molecules are asked to increment their residence time.

5. The feed stream enters the reactor. The patches lining the reactor inlet are asked to sprout reactant at the user-specified concentration.

HOW TO USE IT

The best way to the learn the model is to play around with parameters and view the results. The model is essentially 1-D, but has been constructed in 2-D so as to improve its interpretability. To run the model:

1. Select a desired FEED-CONCENTRATION. Note most results are normalized, so the main benefit of higher concentration is less noise in the resultant data.  The notable exception are the CONCENTRATION-DEPENDENT and BIMOLECULAR reaction mechanisms, which are density dependent.  Note that higher concentrations substantially increase computational expense.

2. Select a FEED-VELOCITY to set the convection rate.

3. Select a DIFFUSIVITY to set the dispersion rate.

4. Select a REACTION-PROBABILITY, COLLISION-RADIUS, and REACTION-TYPE to set the reaction rate.  Note that the COLLISION-RADIUS is not relevant for the CONCENTRATION-INDEPENDENT mechanism.

5. Click Go

6. Vary the SAMPLING-WINDOW to change the time span over which effluent samples are averaged.  Larger windows are less sensitive to noise, but have longer dynamic responses.

OPTIONAL: To run a tracer experiment, you can either click the TRACER-PULSE button or switch the TRACER-STEP? on.  

OPTIONAL: To import parameters from the patch-based model, click the EXPORT PARAMETERS button in the patch-based model, then click the IMPORT PATCH MODEL PARAMETERS button on the turtle model's interface.  For the reverse, click EXPORT PARAMETERS on the turtle-model interface then click the IMPORT TURTLE MODEL PARAMETERS button on the patch model's interface.

The use of these optional features are described below under THINGS TO TRY.

THINGS TO NOTICE

At very low diffusivities relative to feed velocity (convection >> dispersion), the residence time distribution (RTD) converges to a Gaussian. In the limiting case, the RTD approaches the space-time. This result is predicted by the analytical 1-D dispersion model, and is synonymous with the "ideal PFR" discussed in undergraduate chemical engineering courses. In the opposite limit, as dispersion >> convection, the RTD converges to an exponential decay. This result is also predicted by the 1-D dispersion model, and is synonymous to the "ideal CSTR." Similarly results can be obtained by performing tracer response experiments. The responses exhibited by the model to both pulse and step tracer experiments are identical to those predicted analytically. Near the low dispersion limit, the variance of the Gaussian tracer pulse response is inversely proportional to the Peclet number. Note that the dimensionless Peclet number expresses the ratio of convective transport to diffusive transport, and is quantitatively reported on the interface.

The Damkohler number expresses the ratio of reaction rate to convection rate, and is reported on the interface. When this ratio is very high, reactants are rapidly consumed upon entering the reactor, resulting in a sharp drop in concentration near the inlet. This scenario corresponds to an oversized reactor in which reactants remain in the reactor longer than necessary. When the ratio is very low, convection dominates and conversion remains low leading to a uniform concentration profile throughout the reactor. In this limit, reactants flow out of the reactor before they can react.

The model is able to capture dynamic behavior, including startup. This is not typically coded into high level reactor models, and allows for some interesting analysis as well as potential for development of control strategies.

Several reaction mechanisms are provided, but these mechanisms are not specified in the deterministic rate expression form. These stochastic mechanisms can be mapped to deterministic expressions using the export feature.

THINGS TO TRY

A number of known limiting system states are listed in the upper right corner of the interface. All of these phenomena can be reproduced in this model - try varying the parameters that determine the rates of convection, dispersion, and reaction to see if you can recreate these states. Real reactors operate somewhere in the space between these limits, and can be reproduced by tuning the model parameters to match a real-world system. In particular, FEED-VELOCITY, DIFFUSIVITY, and REACTION-PROBABILITY are directly proportional to the convection, dispersion, and reaction rates, respectively.

The SAMPLING-WINDOW is the time span over which effluent measurements are averaged. What happens to the effluent measurement noise as the window increases? What happens to the measurements' response times to perturbations in the system parameters?

Inert tracers are used to characterize flow patterns in real reactors. In a pulse experiment, an ephemeral pulse of inert tracer is added to the reactor feed stream, and the tracer concentration of the effluent is monitored. In a step experiment, a step change is made to the steady state tracer concentration in the feed stream. Try running a few of each experiment. What does the tracer response tell you about the residence time distribution? Could you characterize the relative rates of convection and dispersion using only this experimental tool?

A number of different reaction mechanisms are provided. By using the EXPORT PARAMETERS feature and the accompanying patch-based model, can you map these stochastic reaction mechanisms to deterministic rate expressions?

EXTENDING THE MODEL

Potential extensions could entail:

1. Building a means to import a reaction network, complete with multiple products, reactants, and stoichiometries.
2. Additional analytical tools, such as curve fitting.
3. Residence time distributions or tracer pulse responses could be converted to probability density and cumulative distribution functions.

RELATED MODELS

An accompanying patch-based model is available on the NetLogo Modeling Commons. This model handles everything from the perspective of stationary points in the reactor. :

http://modelingcommons.org/browse/onemodel/4402#modeltabsbrowseinfo

CREDITS AND REFERENCES

The model was created for EECS 472 by Sebastian Bernasek at Northwestern University. The latest version of this model is available on the NetLogo Modeling Commons:

http://modelingcommons.org/browse/onemodel/4401#modeltabsbrowseinfo

Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

breed [inerts inert]
breed [reactants reactant]
breed [products product]
turtles-own [conv-xcor conv-ycor diff-xcor diff-ycor res-time]
globals [effluent effluent-reactant effluent-product effluent-rtd-list effluent-rtd reactant-profile reactant-profile-patches]


;;GLOBAL VARIABLES:
  ;;effluent = agentset of turtles leaving the right system boundary at each time point
  ;;effluent-reactant = effluent with reactant breed
  ;;effluent-product = effluent with product breed
  ;;effluent-rtd-list = list of lists containing the residence times of all agents in the effluent. At each tick, a new list for the current effluent is appended to the end, and the first list is removed if the sampling window is exceeded.
  ;;effluent-rtd = single list of residence times of all effluent within the sampling window
  ;;reactant-profile = list of total reactant count in the current model for each value of pxcor, ordered by pxcor
  ;;reactant-profile-patches = list of total reactant count imported from the patch-based model for each value of pxcor, ordered by pxcor


;;TURTLE VARIABLES:
  ;;conv-xcor/conv-ycor = the projected x-y coordinates of each turtle after convection
  ;;diff-xcor/diff-ycor = the projected x-y coordinates of each turtle after convection and dispersion
  ;;res-time = the residence time of an individual turtle, incremented at each tick

to setup
  clear-all
    
  ;;Set default shapes
  set-default-shape turtles "circle"
  
  ;;Initialize sets and lists
  set reactant-profile ([pycor] of patches with [pycor = 0])  ;;Create an array of zeroes with length equal to reactor length
  set effluent (turtles with [xcor = max-pxcor])
  set effluent-reactant 0
  set effluent-product 0
  set effluent-rtd-list []
  set effluent-rtd []
  
  ;;Fill reactor 
  ifelse fill-reactor? 
    [fill-reactor]
    [ask patches with [pxcor = min-pxcor] [feed-reactor]]
  
  reset-ticks  
end 

to fill-reactor
;;Fills entire reactor with reactant at setup.  This avoids time delay due to convection, but still incurs delay due to residence time.

  ;;Ask patches with xcor equal to multiple of flow discretization to sprout reactant
  ask patches with [pxcor = feed-velocity * floor (pxcor / feed-velocity)]
    [sprout-reactants feed-concentration
      [set color blue
        set size 1
        set heading 90
        set res-time 0]]
end 

to go
;;Note that for units, 1 tick = 1 second
  
  run-kinetics
  convective-transport
  dispersive-transport
  analyze-effluent
  update-plots
  move
  ask patches with [pxcor = min-pxcor] [feed-reactor]
  calculate-profile
  tick
end 

to feed-reactor  ;;Patch procedure
;;ADDS MOLECULAR PACKETS AT REACTOR INLET  
  
  ;;Add reactant to feed
  sprout-reactants feed-concentration
  [set color blue
    set size 1
    set heading 90
    set res-time 0]
  
  
  ;;Add tracer during step experiments
  if tracer-step? 
    [sprout-inerts tracer-density
      [set color yellow
        set size 2
        set heading 90
        set res-time 0]]
end 

to tracer-pulse
  ;;Add single pulse of tracer to feed
  
  ask patches with [pxcor = min-pxcor]
    [sprout-inerts tracer-density
      [set color yellow
        set size 2
        set heading 90
        set res-time 0]]
end 

to run-kinetics
;;RUNS REACTION KINETICS ACCORDING TO SELECTED MECHANISM


  ;;Conc. Independent: Reaction proceeds with equal probability regardless of local concentration
  if reaction-type = "Concentration Independent"
    [ask reactants 
      [if random-float 100 < reaction-probability
        [set breed products
         set color red]]]


  ;;Conc. Dependent:  Reaction probability scales proportionally with the local reactant concentration.
  ;;Reactant concentration is based upon reactants within the collision radius.
   if reaction-type = "Concentration Dependent"
    [ask reactants 
      [if random-float 100 < (reaction-probability * ( count (other reactants in-radius collision-radius) ))
        [set breed products
         set color red]]]

 
  ;;Bimolecular.  Reaction does not proceed unless another reactant is within the collision radius.
   if reaction-type = "Bimolecular"
      ;;Ask reactants to do: I check if I am within the collision-radius of another reactant, if so, 
      ;;and we probabilistically have the correct orientation, we react.  
      ;;When we react, I ask the other reactant to die, then I become the product.
 
    [ask reactants 
      [if (count (other reactants in-radius collision-radius) > 0) and random-float 100 < reaction-probability  
        [ask one-of other reactants in-radius collision-radius 
          [die]
         set breed products
         set color red]]]
end 

to convective-transport
;;BULK FLOW TRANSPORT MECHANISM
    
  ;;Ask turtles to predict their downstream position
  ask turtles [
    set heading 90
    set conv-xcor (xcor + feed-velocity) ]
end 

to dispersive-transport
;;DISPERSIVE TRANSPORT MECHANISM
;;Ask turtles to predict their post-diffusion position relative to their predicted post-convection position.
  
  ;;Tell all turtles: I take a random walk of path-length equal to "diffusivity." 
  ask turtles [ 
    
    ;;If random diffusion is on, the random walk step size is a random float less than the diffusivity.  This helps smooth the data, but isn't a true fixed-step random walk.
    ifelse not random-diffusion?
      [ifelse random 2 = 1
        [set diff-xcor (conv-xcor + (diffusivity))]
        [set diff-xcor (conv-xcor - (diffusivity))]]
    
      [ifelse random 2 = 1
        [set diff-xcor (conv-xcor + (random-float diffusivity))]
        [set diff-xcor (conv-xcor - (random-float diffusivity))]]
    
    
    if diff-xcor < min-pxcor
      [set diff-xcor min-pxcor]]
end 

to analyze-effluent
;;BOOKKEEPING OF ELEMENTS LEAVING THE REACTOR
  
  
  ;;IDENTIFY PARTICLES LEAVING THE REACTOR
  
  ;;Store all molecules leaving the reactor as effluent
  set effluent (turtles with [diff-xcor > max-pxcor])
 
  ;;Store effluent reactant (moving average does not store past values to save memory)
  set effluent-reactant (((sampling-window - 1) / sampling-window) * effluent-reactant) + ((1 / sampling-window) * (count effluent with [breed = reactants]) )

  ;;Store effluent product (moving average does not store past values to save memory)
  set effluent-product (((sampling-window - 1) / sampling-window) * effluent-product) + ((1 / sampling-window) * (count effluent with [breed = products]) )
   
   
  ;;STORE EFFLUENT RESIDENCE TIMES
  
  ;;Add effluent residence times to sliding window. effluent-rtd-list is a list of sets of residence times for the effluent molecules at each tick.
  set effluent-rtd-list lput ([res-time] of effluent) effluent-rtd-list
  
  ;;Removes the oldest set of residence times.
  if (length effluent-rtd-list) > sampling-window
    [set effluent-rtd-list remove-item 0 effluent-rtd-list]
    
  ;;Combines residence time lists into a single list for plotting.
  set effluent-rtd effluent-rtd-merged
end 

to move
;;EXECUTES ACTUAL MOTION

  ;;Remove effluent from reactor
  ask effluent [die]
  
  ;;Turtles reach their projected position after convective + diffusive transport, then increment residence time
  ask turtles [
    set xcor diff-xcor
    set res-time (res-time + 1)]
end 

to calculate-profile
  
  ;;Ask each patch along the longitudinal axis of the reactor to store the current total number of reactants with the same x-coordinate
  ;;This value is then appended to the moving average reactant-profile across the sampling window

  let centerline (patches with [pycor = 0])
  let inst-reactant-profile (map ([sum ([count reactants-here] of patches with [pxcor = [pxcor] of ?])]) (sort-on [pxcor] centerline))
  set reactant-profile (  map [((1 / sampling-window) * ?1) + (((sampling-window - 1) / sampling-window) * ?2)] inst-reactant-profile reactant-profile)
end 




;;End of main model code.  Remaining code is for analysis and import/export.
;;===================================================================================


;;IMPORT EXPORT CODE FOR SYNCING WITH PATCH-BASED MODEL

to import-patch-model
;;FUNCTION IMPORTS PARAMETERS AND RESULTS FROM PATCH-BASED MODEL
;;THEN SETS CURRENT MODEL TO THOSE OPERATING PARAMETERS 
  
  ;;Open file containing data from turtle-based model
  file-open "patch-results.csv"
  
  ;;If file is at the end (i.e. already imported once), close it and reopen it.
  if file-at-end? 
    [file-close-all
      file-open "patch-results.csv"]
  
  ;;Store each of the variables from the other model.  List order is known a priori, not ideal but... no tengo tiempo!
  let dim                 read-from-string (file-read-line)
  resize-world (item 0 dim) (item 1 dim) (item 2 dim) (item 3 dim)   ;;Set dimensions to those of patch model
  set feed-velocity       read-from-string (file-read-line)          ;;Sets feed-velocity to patch-based model's value
  set diffusivity         round (read-from-string (file-read-line))  ;;Sets diffusivity to patch-based model's value.
  set reaction-probability (100 * read-from-string (file-read-line)) ;;Sets reaction-probability to patch-based model's rate-constant
  set reactant-profile-patches read-from-string (file-read-line)          ;;Import results (conc. profile) from patch-based model
  
                                                                          ;;Close file, resetting line count.
  file-close-all
end 

to export-results
;;WRITE OPERATING PARAMETERS AND CONCENTRATION PROFILE TO A FILE FROM WHICH IT CAN BE IMPORTED TO PATCH MODEL

  ;;Normalize reactant concentration profile to stable concentration near end of reactor. I've shifted this right because the bounds on random walk cause an anomaly near the inlet.
  let reactant-profile-norm (map [? / (item (world-width - 10) reactant-profile)] reactant-profile )
  
  ;;Create file (or delete old one and reopen)   
  ifelse file-exists? "turtle-results.csv"
    [file-delete "turtle-results.csv"
      file-open "turtle-results.csv" ]
    [file-open "turtle-results.csv"]
  
  ;;Write variables to file.  I've left out labels because I can't figure out how to make the import step recognize them.
  file-print (list min-pxcor max-pxcor min-pycor max-pycor)
  file-print feed-velocity
  file-print diffusivity
  file-print (reaction-probability / 100)  ;;Converted to percentage probability
  file-print reaction-type
  file-print reactant-profile-norm     
  
  ;;Save and close file  
  file-flush
  file-close
end 




;; REPORTERS - ONLY USED FOR ANALYSIS

to-report space-time
;;CALCULATE SPACE TIME (convection/reactor volume)
 
  ifelse feed-velocity > 0
    [report (((2 * max-pxcor) + 1) / feed-velocity)]
    [report "inf"]
end 

to-report conversion
;;CALCULATE CONVERSION  

  let reactant-in (count reactants with [res-time = 0])
  report (( reactant-in - effluent-reactant ) / reactant-in)
end 

to-report peclet []
;;CALCULATE PECLET NUMBER (dimensionless ratio = convection/dispersion)
 
  if length effluent-rtd > 1 
    [ifelse non-dim-res-time?
      [if length effluent-rtd > 1
        [ifelse variance effluent-rtd > 0 
          [report (2 / (variance effluent-rtd))]
          [report "inf."] ]]
      [ifelse variance effluent-rtd != 0
        [report ((2 *  (space-time ^ 2)) / (variance effluent-rtd)) ]
        [report "inf."]]]
end 

to-report effluent-rtd-merged
  
;;CALCULATE RESIDENCE TIME DISTRIBUTION   
 
  ;;Takes list of lists and combines them into a single list of residence times for the given sliding window
  let rtd-list reduce [sentence ?1 ?2] effluent-rtd-list
  
  ;;Nondimensionalize residence times
  ifelse non-dim-res-time? 
    [report map [ ? / (space-time)] rtd-list]
    [report rtd-list]
end 

to-report mean-sq-error [profile1 profile2]
  
  ;;Rescales patch profile based on concentration ten patches from the reactor exit
  let scaled-profile2 (map [? *  (item (world-width - 10) profile1)] profile2)
  
  ;;Filters out first ten and last five entries from profile.  These are the regions where noise has a strong influence.
  let filtered-profile1 sublist profile1 (10) ((length profile1) - 5)
  let filtered-profile2 sublist scaled-profile2 (10) ((length scaled-profile2) - 5)
  
  ;;Calculates sum of mean squared error between profiles
  let squared-errors (map [(?1 - ?2) ^ 2] filtered-profile1 filtered-profile2)

  ;;Report sum of squared error
  report (sum squared-errors)   
end 


There are 6 versions of this model.

Uploaded by When Description Download
Sebastian Bernasek almost 9 years ago Update Info Download this version
Sebastian Bernasek almost 9 years ago updated interface, info Download this version
Sebastian Bernasek almost 9 years ago info tab completed Download this version
Sebastian Bernasek almost 9 years ago import/export capability Download this version
Sebastian Bernasek almost 9 years ago Added reaction mechanisms, RTDs, plot scaling Download this version
Sebastian Bernasek almost 9 years ago Initial upload Download this version

Attached files

File Type Description Last updated
Bernasek_Sebastian_Report_ds.pdf pdf Final Report for EECS472 (double spaced) almost 9 years ago, by Sebastian Bernasek Download
Bernasek_Sebastian_Report_ss.pdf pdf Final Report for EECS472 (single spaced) almost 9 years ago, by Sebastian Bernasek Download

This model does not have any ancestors.

This model does not have any descendants.