| 51 | |
| 52 | [[BR]] |
| 53 | ==== Simulation Data ==== |
| 54 | |
| 55 | All AstroBEAR modules have at least one thing in common: initializing the problem domain. Within our code, the problem domain's data is held in {{{InfoDef}}} structures, which is why so many module subroutines take an {{{InfoDef}}} structure as a parameter. |
| 56 | |
| 57 | There are two major data arrays in {{{InfoDef}}}: the {{{q}}} array and the {{{aux}}} array. {{{q}}} holds the cell-centered data and is used by all AstroBEAR simulations. The {{{q}}} array takes the form {{{q(x,y,z,variable)}}} where {{{variable}}} is itself a 1D array that holds the physical quantities such as density, momentum, energy, etc. The order of the quantities in the {{{variable}}} array is {{{(rho, px, py, pz, E)}}}. The {{{aux}}} array holds face-centered data, and is only used in MHD problems. If you are running a strictly hydrodynamic problem or a hydrodynamic + elliptic problem, then you will not need {{{aux}}}. |
| 58 | |
| 59 | [[BR]] |
| 60 | ==== Dimensions ==== |
| 61 | |
| 62 | Currently, AstroBEAR can only run 2D and 3D problems, but a 1D hydro or MHD problem can be simulated by defining a very narrow 2D problem domain and then making sure all the activity is defined in the x-direction (i.e., no {{{py}}} or {{{pz}}} components). |
| 63 | |
| 64 | The ''core'' region of the {{{Info%q}}} array (which does not include ghost zones) is a {{{1:mx}}} by {{{1:my}}} by {{{1:mz}}} box. Mx, my, and mz denote the number of cells in the x, y, and z directions, respectively. In two dimensions, {{{mz}}} = 1, reducing the box to a rectangle. {{{Info%q}}} is cell-centered, so the values are assumed to be taken from the midpoint of the cell. Thus, the cell-to-space conversion is: |
| 65 | |
| 66 | {{{ |
| 67 | x=(xlower + (REAL(i,xPrec)-half) * dx) |
| 68 | y=(ylower + (REAL(j,xPrec)-half) * dy) |
| 69 | z=(zlower + (REAL(k,xPrec)-half) * dz) |
| 70 | }}} |
| 71 | |
| 72 | [[BR]] |
| 73 | The {{{Info%aux}}} array is a little different. The {{{aux}}} array holds magnetic flux values, which are face-centered. This means that every cell-centered value in {{{Info%q}}} is bracked in each dimension by two {{{Info%aux}}} values. To accommodate the extra values, {{{Info%aux}}} is a {{{1:mx+1}}} by {{{1:my+1}}} by {{{1:mz+1}}} box, but the {{{aux}}} dimensions are actually different for each variable: |
| 74 | |
| 75 | {{{ |
| 76 | Bx = Info%aux(1:mx+1, 1:my, 1:mz, 1) |
| 77 | By = Info%aux(1:mx, 1:my+1, 1:mz, 2) |
| 78 | Bz = Info%aux(1:mx, 1:my, 1:mz+1, 3) |
| 79 | }}} |
| 80 | |
| 81 | The additional cells (the ones in the "upper-front right" corner of the {{{aux}}} array) are not used. |
| 82 | |
| 83 | [[BR]] |
| 84 | |
| 85 | ==== Units and Scaling ==== |
| 86 | |
| 87 | Astrophysical problems involve many different physical units and constants with a wide range of scales. To avoid the loss of precision that comes when computers try to work with, say, a 10^-8^ variable and a 10^24^ constant in the same expression, we scale our units into ''computational units'' before storing them in the data arrays. |
| 88 | |
| 89 | Usually, the physical scales are defined in the [PhysicsDataExplained physics.data] file--you simply enter the scales for density, temperature, velocity, etc in that file, and AstroBEAR will read them in. More complicated scaling would be defined in the {{{ProblemModuleInit()}}} routine (see above). |
| 90 | |
| 91 | You have two options for making sure that you only put scaled quantities in the data arrays: you can scale your input values before you enter them into your input file (and then assume that you are reading in scaled quantities), or you can use physical quantities in your input files and then scale them within your problem module: |
| 92 | |
| 93 | {{{ |
| 94 | scaled_qty = physical_qty / physical_scale |
| 95 | }}} |
| 96 | |
| 97 | Either way, a good sanity check is to print out the physical quantities your program uses after the problem is set up. This verifies that the values you think are going in are the values that are actually getting used. |
| 98 | |
| 99 | [[BR]] |
| 100 | |
| 101 | ==== Initializing a Grid ==== |
| 102 | |
| 103 | Initializing a grid involves taking a spatially-constructed problem setup and discretizing it so that it fits nicely in an array. This process is easiest to explain by dissecting an example, such as the one below, where we are trying to initialize the grid with a density distribution given by {{{rho(x,y,z)}}}: |
| 104 | |
| 105 | Note that during the !ProblemGridInit routine, ghost zones do not need to be initialized (rmbc = 0) - however - during beforestep calculations they should be |
| 106 | |
| 107 | {{{ |
| 108 | q=>Info%q |
| 109 | |
| 110 | rmbc=levels(Info%level)%gmbc(levels(Info%level)%step) |
| 111 | |
| 112 | mx=Info%mX(1); dx=Info%dX(1); xlower=Info%Xlower(1) |
| 113 | my=Info%mX(2); dy=Info%dX(2); ylower=Info%Xlower(2) |
| 114 | mz=Info%mX(3); dz=Info%dX(3); zlower=Info%Xlower(3) |
| 115 | |
| 116 | SELECT CASE(nDim) |
| 117 | CASE(2) |
| 118 | zrmbc=0;mz=1;zl=0;dz=0 |
| 119 | CASE(3) |
| 120 | zrmbc=rmbc |
| 121 | END SELECT |
| 122 | |
| 123 | ! Initialize environment |
| 124 | DO k=1-zrmbc, mz+zrmbc |
| 125 | DO j=1-rmbc, my+rmbc |
| 126 | DO i=1-rmbc, mx+rmbc |
| 127 | |
| 128 | x=(xlower + (REAL(i,xPrec)-half) * dx) |
| 129 | y=(ylower + (REAL(j,xPrec)-half) * dy) |
| 130 | z=(zlower + (REAL(k,xPrec)-half) * dz) |
| 131 | |
| 132 | q(i,j,k) = rho(x,y,z) |
| 133 | END DO |
| 134 | END DO |
| 135 | END DO |
| 136 | }}} |
| 137 | |
| 138 | Each grid (or {{{InfoDef}}} structure) comes with several arrays that describe its geometry: |
| 139 | |
| 140 | * '''''mX(3)''''': The grid's overall size. Each element {{{mx(n)}}} represents the number of cells along the ''n''th dimension. |
| 141 | * '''''Xlower(3)''''': The spatial coordinates of the grid's lower bound in each dimension. These values are ''always'' given in computational units. |
| 142 | * '''''dX(3)''''': The size of a spatial step in a given dimension. {{{dX(n)}}} can also be thought of as the size of a cell along dimension ''n''. |
| 143 | |
| 144 | To make this example more readable (and therefore easier to debug), we assigned the various array values more Cartesian-sounding names (ie., {{{Info%dX(2) = dy}}}). |
| 145 | |
| 146 | Similarly, when calculating the spatial equivalents of an index, we went with {{{x}}}, {{{y}}} and {{{z}}}. The half-step in the position calculations represents the fact that the spatial position is at the ''center'' of the cell, not the left side. |
| 147 | |
| 148 | The check on the number of dimensions makes sure that 2D problem does not accidentally get initialized with ghost cells (see below) or a spatial step. This allows us to use the same initialization code for 2D or 3D problems. |
| 149 | |
| 150 | The {{{levels()}}} array is a global array structures that contain information specific to each level. You can see in this example that we reference the appropriate level by using the {{{Info%level}}} attribute. |
| 151 | |
| 152 | You may have noticed the nested loops don't go from {{{1}}} to {{{mX(n)}}}. This is because the data array size is not the same as the grid size. The size of each grid along dimension ''n'' is {{{mX(n)}}}. The ''data arrays'', however, have a number of "ghost cells" associated with them. The number of ghost cells on the end of a grid is given by the quantity |
| 153 | |
| 154 | {{{ |
| 155 | levels(Info%level)%CoarsenRatio * levels(Info%level)%gmbc |
| 156 | }}} |
| 157 | |
| 158 | These ghost cells only appear along the dimensions of the problem, though, so the data arrays for a 2D problem will not have ghost cells along the third dimension. So the real extents of the data arrays in a 3D problem are: |
| 159 | |
| 160 | {{{ |
| 161 | Info%q(1 - rmbc : mX(1) + rmbc, & |
| 162 | 1 - rmbc : mX(2) + rmbc, & |
| 163 | 1 - rmbc : mX(3) + rmbc, & |
| 164 | NrVars) |
| 165 | }}} |
| 166 | |
| 167 | {{{ |
| 168 | Info%aux(1 - rmbc : mX(1) + rmbc + 1, & |
| 169 | 1 - rmbc : mX(2) + rmbc + 1, & |
| 170 | 1 - rmbc : mX(3) + rmbc + 1, & |
| 171 | NrVars) |
| 172 | }}} |
| 173 | |
| 174 | |
| 175 | [[BR]] |
| 176 | ==== Flagging Cells for Refinement ==== |
| 177 | |
| 178 | |
| 179 | |
| 180 | [[BR]] |
| 181 | Some modules may need specific regions refined, regardless of whether or not there is any obvious error there. AstroBEAR flags cells for refinement using the array |
| 182 | |
| 183 | {{{ |
| 184 | Info%ErrorFlags(1 - rmbc : mX(1) + rmbc, & |
| 185 | 1 - rmbc : mX(2) + rmbc, & |
| 186 | 1 - rmbc : mX(2) + rmbc, & |
| 187 | NrVars) |
| 188 | }}} |
| 189 | |
| 190 | To clear the cell at {{{(i,j,k)}}}, simply set {{{Info%ErrorFlags(i,j,k)}}} to 0. An error flag of 0 means that the cell does not ''need'' to be refined (although it might happen anyway). To mark a cell for refinement, set {{{Info%ErrorFlags(i,j,k)}}} to 1. The best place to do this is in the {{{ProblemSetErrFlags()}}} routine; most conventional physical criteria for refinement are already handled by AstroBEAR itself. |
| 191 | |
| 192 | [[BR]] |
| 193 | |
| 194 | ==== Sample Module ==== |
63 | | }}} |
64 | | |
65 | | ==== Simulation Data ==== |
66 | | |
67 | | All AstroBEAR modules have at least one thing in common: initializing the problem domain. Within our code, the problem domain's data is held in {{{InfoDef}}} structures, which is why so many module subroutines take an {{{InfoDef}}} structure as a parameter. |
68 | | |
69 | | There are two major data arrays in {{{InfoDef}}}: the {{{q}}} array and the {{{aux}}} array. {{{q}}} holds the cell-centered data and is used by all AstroBEAR simulations. The {{{q}}} array takes the form {{{q(x,y,z,variable)}}} where {{{variable}}} is itself a 1D array that holds the physical quantities such as density, momentum, energy, etc. The order of the quantities in the {{{variable}}} array is {{{(rho, px, py, pz, E)}}}. The {{{aux}}} array holds face-centered data, and is only used in MHD problems. If you are running a strictly hydrodynamic problem or a hydrodynamic + elliptic problem, then you will not need {{{aux}}}. |
70 | | |
71 | | [[BR]] |
72 | | ==== Dimensions ==== |
73 | | |
74 | | Currently, AstroBEAR can only run 2D and 3D problems, but a 1D hydro or MHD problem can be simulated by defining a very narrow 2D problem domain and then making sure all the activity is defined in the x-direction (i.e., no {{{py}}} or {{{pz}}} components). |
75 | | |
76 | | The ''core'' region of the {{{Info%q}}} array (which does not include ghost zones) is a {{{1:mx}}} by {{{1:my}}} by {{{1:mz}}} box. Mx, my, and mz denote the number of cells in the x, y, and z directions, respectively. In two dimensions, {{{mz}}} = 1, reducing the box to a rectangle. {{{Info%q}}} is cell-centered, so the values are assumed to be taken from the midpoint of the cell. Thus, the cell-to-space conversion is: |
77 | | |
78 | | {{{ |
79 | | x=(xlower + (REAL(i,xPrec)-half) * dx) |
80 | | y=(ylower + (REAL(j,xPrec)-half) * dy) |
81 | | z=(zlower + (REAL(k,xPrec)-half) * dz) |
82 | | }}} |
83 | | |
84 | | [[BR]] |
85 | | The {{{Info%aux}}} array is a little different. The {{{aux}}} array holds magnetic flux values, which are face-centered. This means that every cell-centered value in {{{Info%q}}} is bracked in each dimension by two {{{Info%aux}}} values. To accommodate the extra values, {{{Info%aux}}} is a {{{1:mx+1}}} by {{{1:my+1}}} by {{{1:mz+1}}} box, but the {{{aux}}} dimensions are actually different for each variable: |
86 | | |
87 | | {{{ |
88 | | Bx = Info%aux(1:mx+1, 1:my, 1:mz, 1) |
89 | | By = Info%aux(1:mx, 1:my+1, 1:mz, 2) |
90 | | Bz = Info%aux(1:mx, 1:my, 1:mz+1, 3) |
91 | | }}} |
92 | | |
93 | | The additional cells (the ones in the "upper-front right" corner of the {{{aux}}} array) are not used. |
94 | | |
95 | | [[BR]] |
96 | | |
97 | | ==== Units and Scaling ==== |
98 | | |
99 | | Astrophysical problems involve many different physical units and constants with a wide range of scales. To avoid the loss of precision that comes when computers try to work with, say, a 10^-8^ variable and a 10^24^ constant in the same expression, we scale our units into ''computational units'' before storing them in the data arrays. |
100 | | |
101 | | Usually, the physical scales are defined in the [PhysicsDataExplained physics.data] file--you simply enter the scales for density, temperature, velocity, etc in that file, and AstroBEAR will read them in. More complicated scaling would be defined in the {{{ProblemModuleInit()}}} routine (see above). |
102 | | |
103 | | You have two options for making sure that you only put scaled quantities in the data arrays: you can scale your input values before you enter them into your input file (and then assume that you are reading in scaled quantities), or you can use physical quantities in your input files and then scale them within your problem module: |
104 | | |
105 | | {{{ |
106 | | scaled_qty = physical_qty / physical_scale |
107 | | }}} |
108 | | |
109 | | Either way, a good sanity check is to print out the physical quantities your program uses after the problem is set up. This verifies that the values you think are going in are the values that are actually getting used. |
110 | | |
111 | | [[BR]] |
112 | | |
113 | | ==== Initializing a Grid ==== |
114 | | |
115 | | Initializing a grid involves taking a spatially-constructed problem setup and discretizing it so that it fits nicely in an array. This process is easiest to explain by dissecting an example, such as the one below, where we are trying to initialize the grid with a density distribution given by {{{rho(x,y,z)}}}: |
116 | | |
117 | | Note that during the !ProblemGridInit routine, ghost zones do not need to be initialized (rmbc = 0) - however - during beforestep calculations they should be |
118 | | |
119 | | {{{ |
120 | | q=>Info%q |
121 | | |
122 | | rmbc=levels(Info%level)%gmbc(levels(Info%level)%step) |
123 | | |
124 | | mx=Info%mX(1); dx=Info%dX(1); xlower=Info%Xlower(1) |
125 | | my=Info%mX(2); dy=Info%dX(2); ylower=Info%Xlower(2) |
126 | | mz=Info%mX(3); dz=Info%dX(3); zlower=Info%Xlower(3) |
127 | | |
128 | | SELECT CASE(nDim) |
129 | | CASE(2) |
130 | | zrmbc=0;mz=1;zl=0;dz=0 |
131 | | CASE(3) |
132 | | zrmbc=rmbc |
133 | | END SELECT |
134 | | |
135 | | ! Initialize environment |
136 | | DO k=1-zrmbc, mz+zrmbc |
137 | | DO j=1-rmbc, my+rmbc |
138 | | DO i=1-rmbc, mx+rmbc |
139 | | |
140 | | x=(xlower + (REAL(i,xPrec)-half) * dx) |
141 | | y=(ylower + (REAL(j,xPrec)-half) * dy) |
142 | | z=(zlower + (REAL(k,xPrec)-half) * dz) |
143 | | |
144 | | q(i,j,k) = rho(x,y,z) |
145 | | END DO |
146 | | END DO |
147 | | END DO |
148 | | }}} |
149 | | |
150 | | Each grid (or {{{InfoDef}}} structure) comes with several arrays that describe its geometry: |
151 | | |
152 | | * '''''mX(3)''''': The grid's overall size. Each element {{{mx(n)}}} represents the number of cells along the ''n''th dimension. |
153 | | * '''''Xlower(3)''''': The spatial coordinates of the grid's lower bound in each dimension. These values are ''always'' given in computational units. |
154 | | * '''''dX(3)''''': The size of a spatial step in a given dimension. {{{dX(n)}}} can also be thought of as the size of a cell along dimension ''n''. |
155 | | |
156 | | To make this example more readable (and therefore easier to debug), we assigned the various array values more Cartesian-sounding names (ie., {{{Info%dX(2) = dy}}}). |
157 | | |
158 | | Similarly, when calculating the spatial equivalents of an index, we went with {{{x}}}, {{{y}}} and {{{z}}}. The half-step in the position calculations represents the fact that the spatial position is at the ''center'' of the cell, not the left side. |
159 | | |
160 | | The check on the number of dimensions makes sure that 2D problem does not accidentally get initialized with ghost cells (see below) or a spatial step. This allows us to use the same initialization code for 2D or 3D problems. |
161 | | |
162 | | The {{{levels()}}} array is a global array structures that contain information specific to each level. You can see in this example that we reference the appropriate level by using the {{{Info%level}}} attribute. |
163 | | |
164 | | You may have noticed the nested loops don't go from {{{1}}} to {{{mX(n)}}}. This is because the data array size is not the same as the grid size. The size of each grid along dimension ''n'' is {{{mX(n)}}}. The ''data arrays'', however, have a number of "ghost cells" associated with them. The number of ghost cells on the end of a grid is given by the quantity |
165 | | |
166 | | {{{ |
167 | | levels(Info%level)%CoarsenRatio * levels(Info%level)%gmbc |
168 | | }}} |
169 | | |
170 | | These ghost cells only appear along the dimensions of the problem, though, so the data arrays for a 2D problem will not have ghost cells along the third dimension. So the real extents of the data arrays in a 3D problem are: |
171 | | |
172 | | {{{ |
173 | | Info%q(1 - rmbc : mX(1) + rmbc, & |
174 | | 1 - rmbc : mX(2) + rmbc, & |
175 | | 1 - rmbc : mX(3) + rmbc, & |
176 | | NrVars) |
177 | | }}} |
178 | | |
179 | | {{{ |
180 | | Info%aux(1 - rmbc : mX(1) + rmbc + 1, & |
181 | | 1 - rmbc : mX(2) + rmbc + 1, & |
182 | | 1 - rmbc : mX(3) + rmbc + 1, & |
183 | | NrVars) |
184 | | }}} |
185 | | |
186 | | |
187 | | [[BR]] |
188 | | ==== Flagging Cells for Refinement ==== |
189 | | |
190 | | |
191 | | |
192 | | [[BR]] |
193 | | Some modules may need specific regions refined, regardless of whether or not there is any obvious error there. AstroBEAR flags cells for refinement using the array |
194 | | |
195 | | {{{ |
196 | | Info%ErrorFlags(1 - rmbc : mX(1) + rmbc, & |
197 | | 1 - rmbc : mX(2) + rmbc, & |
198 | | 1 - rmbc : mX(2) + rmbc, & |
199 | | NrVars) |
200 | | }}} |
201 | | |
202 | | To clear the cell at {{{(i,j,k)}}}, simply set {{{Info%ErrorFlags(i,j,k)}}} to 0. An error flag of 0 means that the cell does not ''need'' to be refined (although it might happen anyway). To mark a cell for refinement, set {{{Info%ErrorFlags(i,j,k)}}} to 1. The best place to do this is in the {{{ProblemSetErrFlags()}}} routine; most conventional physical criteria for refinement are already handled by AstroBEAR itself. |
203 | | |
204 | | [[BR]] |
| 207 | |
| 208 | ! Initialize the module variables |
| 209 | SUBROUTINE ProblemModuleInit(Info) |
| 210 | END SUBROUTINE ProblemModuleInit |
| 211 | |
| 212 | ! Initialize the grid |
| 213 | SUBROUTINE ProblemGridInit(Info) |
| 214 | END SUBROUTINE ProblemGridInit |
| 215 | |
| 216 | ! Use for pre-processing |
| 217 | SUBROUTINE ProblemBeforeStep(Info) |
| 218 | END SUBROUTINE ProblemBeforeStep |
| 219 | |
| 220 | ! Use for post-processing |
| 221 | SUBROUTINE ProblemAfterStep(Info) |
| 222 | END SUBROUTINE ProblemAfterStep |
| 223 | |
| 224 | ! Use for additional refinement |
| 225 | SUBROUTINE ProblemSetErrFlag(Info) |
| 226 | END SUBROUTINE ProblemSetErrFlag |
| 227 | }}} |