View Javadoc

1   
2   package org.catacomb.numeric.mesh;
3   
4   import java.util.ArrayList;
5   
6   
7   public abstract class Discretizer {
8   
9   
10  
11      /**
12       *    divided into segments with equal integral of
13       *    the square root of the radius, given by disqrtr.
14       *    This balances the charging rate of points in the final
15       *    discretization and its definition is independent of
16       *    the electrical properties of the membrane.
17       *    It provides a more consistent discretization than the
18       *    electrotonic length, and is valid in the absence of
19       *    persistent currents.
20       *
21       *    Tapering segments are treated as such and not approximated by a series
22       *    of cylinders. The discretization does, however, respect the
23       *    actual points of the structure to which clamps or recorders
24       *    may be attached.
25       */
26  
27  
28      public static MeshPoint[] discretize(MeshPoint[] pt,
29                                           double disqrtr, int maxnpt) {
30  
31          int np = pt.length;
32          double[][][] subdiv = new double[np][6][];
33          for (int i = 0; i < np; i++) {
34              pt[i].setWork(i);
35          }
36  
37          int nnp = 0;
38          for (int i = 0; i < np; i++) {
39              MeshPoint cpa = pt[i];
40  
41              int nnbr = cpa.getNeighborCount();
42              MeshPoint[] anbrs = cpa.getNeighbors();
43  
44              for (int j = 0; j < nnbr; j++) {
45                  MeshPoint cpb = anbrs[j];
46  
47                  if (cpa.getWork() < cpb.getWork()) {
48                      subdiv[i][j] = getSubdivision(cpa, cpb, disqrtr);
49                      nnp += subdiv[i][j].length;
50                  }
51              }
52          }
53  
54          if (np + nnp > maxnpt) {
55              Sp("WARNING - not discretizing: needs too many points ("+np+nnp+")");
56              return null;
57          }
58  
59          MeshPoint[] pr = new MeshPoint[np+nnp];
60          for (int i = 0; i < np; i++) {
61              pr[i] = pt[i];
62          }
63          int nxp = np;
64  
65          for (int i = 0; i < np; i++) {
66              MeshPoint cpa = pt[i];
67  
68              int nnbr = cpa.getNeighborCount();
69              MeshPoint[] anbrs = cpa.getNeighbors();
70  
71              for (int j = 0; j < nnbr; j++) {
72                  double[] div = subdiv[i][j];
73                  if (div != null && div.length > 0) {
74  
75                      MeshPoint cpb = anbrs[j];
76                      MeshPoint clast = null;
77  
78                      for (int id = 0; id < div.length; id++) {
79  
80                          MeshPoint cp = cpa.newPoint();
81  
82                          locateBetween(cpa, cpb, div[id], cp);
83                          pr[nxp++] = cp;
84                          if (id == 0) {
85                              cpa.replaceNeighbor(cpb, cp);
86                              cp.addNeighbor(cpa);
87                          }
88                          if (id == div.length-1) {
89                              cpb.replaceNeighbor(cpa, cp);
90                              cp.addNeighbor(cpb);
91                          }
92                          if (clast != null) {
93                              cp.addNeighbor(clast);
94                              clast.addNeighbor(cp);
95                          }
96                          clast = cp;
97                      }
98                  }
99              }
100         }
101         return pr;
102     }
103 
104 
105 
106     public static void locateBetween(MeshPoint cpa, MeshPoint cpb, double f,
107                                      MeshPoint cpn) {
108         double wf = 1. - f;
109         cpn.setX(f * cpb.getX() + wf * cpa.getX());
110         cpn.setY(f * cpb.getY() + wf * cpa.getY());
111         cpn.setZ(f * cpb.getZ() + wf * cpa.getZ());
112         cpn.setR(f * cpb.getR() + wf * cpa.getR());
113 
114     }
115 
116 
117 
118     public static double distanceBetween(MeshPoint cp, MeshPoint cq) {
119         double dx = cp.getX() - cq.getX();
120         double dy = cp.getY() - cq.getY();
121         double dz = cp.getZ() - cq.getZ();
122         double d = Math.sqrt(dx*dx + dy*dy + dz*dz);
123         return d;
124     }
125 
126 
127 
128     public static void movePerp(MeshPoint ca, MeshPoint cb, double dperp,
129                                 MeshPoint cm) {
130         double dx = cb.getX() - ca.getX();
131         double dy = cb.getY() - ca.getY();
132         double f = Math.sqrt(dx*dx + dy*dy);
133         dx /= f;
134         dy /= f;
135         double x = cm.getX();
136         double y = cm.getY();
137         x += dperp * dy;
138         y -= dperp * dx;
139 
140         cm.setX(x);
141         cm.setY(y);
142     }
143 
144 
145 
146     public static MeshPoint[] merge(MeshPoint[] pt,
147                                     double maxdr, double maxlen,
148                                     double tol) {
149 
150 
151         for (int i = 0; i < pt.length; i++) {
152             pt[i].setWork(2);
153         }
154 
155 
156         MeshPoint p0 = pt[0];
157         recMerge(p0, maxdr, maxlen, tol);
158 
159         // remove dead points.
160         int nl = 0;
161         for (int i = 0; i < pt.length; i++) {
162             if (pt[i].getWork() > 0) {
163                 nl++;
164             }
165         }
166         MeshPoint[] pr = p0.newPointArray(nl);
167         nl = 0;
168         for (int i = 0; i < pt.length; i++) {
169             if (pt[i].getWork() > 0) {
170                 pr[nl++] = pt[i];
171             }
172         }
173         return pr;
174     }
175 
176 
177 
178     public static void recMerge(MeshPoint cp, double maxdr, double maxlen,
179                                 double tol) {
180         // may have already been done
181         cp.setWork(1);
182 
183         int nnbr = cp.getNeighborCount();
184         MeshPoint[] anbrs = cp.getNeighbors();
185 
186         for (int j = 0; j < nnbr; j++) {
187             MeshPoint cq = anbrs[j];
188 
189             double rp = cp.getR();
190             double rq = cq.getR();
191 
192 
193             if (cq.getWork() == 2 &&
194                     cq.getNeighborCount() == 2 &&
195                     Math.abs((rq - rp) / (rq + rp)) < 0.5 * maxdr &&
196                     distanceBetween(cp, cq) < maxlen) {
197 
198                 // if nnbr is not two, either it is a terminal, or a branch point:
199                 // in either case there is nothing to do;
200 
201                 MeshPoint cprev = cp;
202                 ArrayList<MeshPoint> vpt = new ArrayList<MeshPoint>();
203                 double ltot = 0.;
204                 double ldtot = 0.;
205 
206 
207                 while (cq.getNeighborCount() == 2 &&
208                         distanceBetween(cprev, cq) < maxlen &&
209                         Math.abs((rq-rp)/(rq+rp)) < 0.5 * maxdr) {
210                     vpt.add(cq);
211                     double dl = distanceBetween(cprev, cq);
212                     ltot += dl;
213                     ldtot += dl * (cprev.getR() + cq.getR());
214 
215                     MeshPoint cnxt;
216                     MeshPoint[] acqn  = cq.getNeighbors();
217                     if (acqn[0] == cprev) {
218                         cnxt = acqn[1];
219                     } else {
220                         cnxt = acqn[0];
221                     }
222 
223                     cprev = cq;
224                     cq = cnxt;
225                     rq = cq.getR();
226                 }
227 
228                 double dl = distanceBetween(cprev, cq);
229                 ltot += dl;
230                 ldtot += dl * (cprev.getR() + cq.getR());
231 
232 
233                 double lab = distanceBetween(cp, cq);
234                 double ldab = lab * (cp.getR() + cq.getR());
235 
236                 int nadd = (int)(ltot / maxlen);
237 
238                 if (nadd > vpt.size()) {
239                     nadd = vpt.size(); //cant happen at present;
240                 }
241                 // recycle nadd points;
242 
243                 boolean cor = (Math.abs((lab-ltot)/(lab+ltot)) > 0.5 * tol ||
244                                Math.abs((ldab-ldtot)/(ldab+ldtot)) > 0.5 * tol);
245                 if (cor && nadd == 0) {
246                     nadd = 1;
247                 }
248 
249                 if (nadd == 0) {
250                     cp.replaceNeighbor(vpt.get(0), cq);
251                     cq.replaceNeighbor(vpt.get(vpt.size()-1), cp);
252 
253                 } else {
254 
255                     for (int i = 0; i < nadd; i++) {
256                         MeshPoint cm = vpt.get(i);
257                         cm.setWork(1);
258                         locateBetween(cp, cq, (1.+ i)/(1.+ nadd), cm);
259                         if (i == nadd-1 && nadd < vpt.size()) {
260                             cm.replaceNeighbor(vpt.get(nadd), cq);
261                             cq.replaceNeighbor(vpt.get(vpt.size()-1), cm);
262                         }
263                     }
264                 }
265 
266 
267                 // just kill the rest;
268                 for (int jd = nadd; jd < vpt.size(); jd++) {
269                     MeshPoint cd = vpt.get(jd);
270                     cd.disconnect();
271                     cd.setWork(0);
272                 }
273 
274 
275                 if (cor) {
276                     double dpar = lab / (nadd+1);
277                     double fl = ltot / lab;
278                     double dperp = Math.sqrt((fl*fl - 1) * dpar*dpar);
279                     double fr = ldtot / (fl * ldab);
280                     for (int i = 0; i < nadd; i++) {
281                         MeshPoint cm = vpt.get(i);
282 
283                         double cmr = cm.getR();
284                         cm.setR(cmr * fr);
285 
286                         if (i % 2 == 0) {
287                             movePerp(cp, cq, ((i/2) % 2 == 0 ? dperp : - dperp), cm);
288                         }
289                     }
290 
291                 }
292 
293 
294 
295 
296             }
297             if (cq.getWork() == 2) {
298                 recMerge(cq, maxdr, maxlen, tol);
299             }
300         }
301     }
302 
303 
304 
305 
306 
307     public static double[] getSubdivision(MeshPoint cpa, MeshPoint cpb,
308                                           double disqrtr) {
309         double dab = distanceBetween(cpa, cpb);
310         double ra = cpa.getR();
311         double rb = cpb.getR();
312 
313 
314 
315         double fdist = 0.0;
316         // fdist is to be the integral in question between pta and ptb;
317         if (rb != ra) {
318             fdist = ((2./3.) * dab  / (rb - ra) *
319                      (Math.pow(rb, 3./2.) - Math.pow(ra, 3./2.)));
320 //	lbya = dab * (1./rb - 1./ra) / (Math.PI * (ra - rb));
321 
322         } else {
323             fdist = dab * Math.sqrt(ra);
324 //	lbya = dab / (Math.PI * ra * ra);
325         }
326 //     double aseg = dab * Math.PI * (ra + rb);
327 
328         int nadd = (int)(fdist / disqrtr);
329 
330         double[] dpos = new double[nadd];
331 
332         if (nadd > 0) {
333 
334             if (Math.abs((ra-rb)/(ra+rb)) < 0.01) {
335                 for (int i = 0; i < nadd; i++) dpos[i] = (1.+i) / (nadd+1.);
336 
337             } else {
338                 // chop up the carrot;
339                 double delf = fdist / (nadd+1);
340                 double ffa = (rb - ra) / dab;      // dr/dx
341                 double xa = ra / ffa;
342                 double xb = rb / ffa;
343                 // xa and xb are the end positions measured from where
344                 // the carrot comes to a point.
345                 double x = xa;
346 
347                 // the integral of sqrt(r) dx is
348                 // 2/3 * dx / (rb-ra) * (rb^3/2 - ra^3/2)
349                 // so need dx such that this is delf (= total_int / nseg)
350 
351                 for (int i = 0; i < nadd+1; i++) {
352                     double ttt = (delf * ffa * 3./2. +
353                                   Math.pow(ffa * x, 3./2.));
354                     double dx = Math.pow(ttt, (2./3.)) / ffa - x;
355                     x += dx;
356                     if (i < nadd) {
357                         dpos[i] = (x - xa) / dab;
358                     }
359                 }
360                 if (Math.abs(xb - x) > 1.e-5) {
361                     Sp("ERROR : ECNet segment division " + xa + " " + xb +
362                        " " + x + " " + nadd + " " +dab + " " +ra+ " " + rb);
363                 }
364             }
365         }
366         return dpos;
367     }
368 
369 
370     public static void Sp(String s) {
371         System.out.println(s);
372     }
373 
374 
375 }
376 
377 
378