source: XIOS/dev/branch_openmp/extern/src_netcdf4/getvara3.c @ 1501

Last change on this file since 1501 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 36.1 KB
Line 
1/*********************************************************************
2 *   Copyright 1993, UCAR/Unidata
3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 *   $Header: /upc/share/CVS/netcdf-3/libncdap3/getvara3.c,v 1.44 2010/05/27 21:34:08 dmh Exp $
5 *********************************************************************/
6
7#include "ncdap3.h"
8#include "dapodom.h"
9#include "dapdump.h"
10#include "ncd3dispatch.h"
11
12
13#define NEWVARM
14
15/* Define a tracker for memory to support*/
16/* the concatenation*/
17
18struct NCMEMORY {
19    void* memory;
20    char* next; /* where to store the next chunk of data*/
21}; 
22
23/* Forward:*/
24static NCerror moveto(NCDAPCOMMON*, Getvara*, CDFnode* dataroot, void* memory);
25static NCerror movetor(NCDAPCOMMON*, OCdata currentcontent,
26                   NClist* path, int depth,
27                   Getvara*, int dimindex,
28                   struct NCMEMORY*, NClist* segments);
29
30static int findfield(CDFnode* node, CDFnode* subnode);
31static int wholeslicepoint(Dapodometer* odom);
32static NCerror removepseudodims(DCEprojection* proj);
33
34static int extract(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, OClink, OCdata, struct NCMEMORY*);
35static int extractstring(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, OClink, OCdata, struct NCMEMORY*);
36
37/**
381. We build the projection to be sent to the server aka
39the fetch constraint.  We want the server do do as much work
40as possible, so we send it a url with a fetch constraint
41that is the merge of the url constraint with the vara
42constraint.
43
44The url constraint, if any, is the one that was provided
45in the url specified in nc_open().
46
47The vara constraint is the one formed from the arguments
48(start, count, stride) provided to the call to nc_get_vara().
49
50There are some exceptions to the formation of the fetch constraint.
51In all cases, the fetch constraint will use any URL selections,
52but will use different fetch projections.
53a. URL is unconstrainable (e.g. file://...):
54           fetchprojection = null => fetch whole dataset
55b. The target variable (as specified in nc_get_vara())
56   is already in the cache and is whole variable.
57           fetchprojection = N.A. since variable is in the cache
58c. Vara is requesting part of a variable but NCF_WHOLEVAR flag is set.
59           fetchprojection = unsliced vara variable => fetch whole variable
60d. Vara is requesting part of a variable and NCF_WHOLEVAR flag is not set.
61           fetchprojection = sliced vara variable => fetch part variable
62
632. At this point, all or part of the target variable is available in the cache.
64
653. We build a projection to walk (guide) the use of the oc
66   data procedures in extract the required data from the cache.
67   For cases a,b,c:
68       walkprojection = merge(urlprojection,varaprojection)
69   For case d:
70       walkprojection =  varaprojection without slicing.
71       This means we need only extract the complete contents of the cache.
72       Notice that this will not necessarily be a direct memory to
73       memory copy because the dap encoding still needs to be
74       interpreted. For this case, we derive a walk projection
75       from the vara projection that will properly access the cached data.
76       This walk projection shifts the merged projection so all slices
77       start at 0 and have a stride of 1.
78
79*/
80
81NCerror
82nc3d_getvarx(int ncid, int varid,
83            const size_t *startp,
84            const size_t *countp,
85            const ptrdiff_t* stridep,
86            void *data,
87            nc_type dsttype0)
88{
89    NCerror ncstat = NC_NOERR;
90    OCerror ocstat = OC_NOERR;
91    int i;
92    NC* drno;
93    NC* substrate;
94    NCDAPCOMMON* dapcomm;
95    CDFnode* cdfvar; /* cdf node mapping to var*/
96    NClist* varnodes;
97    nc_type dsttype;
98    Getvara* varainfo = NULL;
99    CDFnode* xtarget = NULL; /* target in DATADDS */
100    CDFnode* target = NULL; /* target in constrained DDS */
101    DCEprojection* varaprojection = NULL;
102    NCcachenode* cachenode = NULL;
103    size_t localcount[NC_MAX_VAR_DIMS];
104    NClist* ncdimsall;
105    size_t ncrank;
106    NClist* vars = NULL;
107    DCEconstraint* fetchconstraint = NULL;
108    DCEprojection* fetchprojection = NULL;
109    DCEprojection* walkprojection = NULL;
110    int state;
111#define FETCHWHOLE 1 /* fetch whole data set */
112#define FETCHVAR   2 /* fetch whole variable */
113#define FETCHPART  4 /* fetch constrained variable */
114#define CACHED     8 /* whole variable is already in the cache */
115
116    ncstat = NC_check_id(ncid, (NC**)&drno); 
117    if(ncstat != NC_NOERR) goto fail;
118    dapcomm = (NCDAPCOMMON*)drno->dispatchdata;
119   
120    ncstat = NC_check_id(drno->substrate, (NC**)&substrate); 
121    if(ncstat != NC_NOERR) goto fail;
122
123    /* Locate var node via varid */
124    varnodes = dapcomm->cdf.varnodes;
125    for(i=0;i<nclistlength(varnodes);i++) {
126        CDFnode* node = (CDFnode*)nclistget(varnodes,i);
127        if(node->array.basevar == NULL
128           && node->nctype == NC_Primitive
129           && node->ncid == varid) {
130            cdfvar = node;
131            break;
132        }
133    }
134
135    ASSERT((cdfvar != NULL));
136
137    /* Get the dimension info */
138    ncdimsall = cdfvar->array.dimsetall;
139    ncrank = nclistlength(ncdimsall);
140
141#ifdef DEBUG
142 {
143int i;
144fprintf(stderr,"getvarx: %s",cdfvar->ncfullname);
145for(i=0;i<ncrank;i++)
146  fprintf(stderr,"[%ld:%ld:%ld]",
147        (long)startp[i],
148        (long)countp[i],
149        (long)stridep[i]
150        );
151fprintf(stderr,"\n");
152 }
153#endif
154
155    /* Fill in missing arguments */
156    if(startp == NULL)
157        startp = nc_sizevector0;
158
159    if(countp == NULL) {
160        /* Accumulate the dimension sizes */
161        for(i=0;i<ncrank;i++) {
162            CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i);
163            localcount[i] = dim->dim.declsize;
164        }
165        countp = localcount;
166    }
167
168    if(stridep == NULL)
169        stridep = nc_ptrdiffvector1;
170
171    /* Validate the dimension sizes */
172    for(i=0;i<ncrank;i++) {
173        CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i);
174        if(startp[i] > dim->dim.declsize
175           || startp[i]+countp[i] > dim->dim.declsize) {
176            ncstat = NC_EINVALCOORDS;
177            goto fail;     
178        }
179    }       
180
181#ifdef DEBUG
182 {
183NClist* dims = cdfvar->array.dimsetall;
184fprintf(stderr,"getvarx: %s",cdfvar->ncfullname);
185if(nclistlength(dims) > 0) {int i;
186for(i=0;i<nclistlength(dims);i++) 
187fprintf(stderr,"[%lu:%lu:%lu]",(unsigned long)startp[i],(unsigned long)countp[i],(unsigned long)stridep[i]);
188fprintf(stderr," -> ");
189for(i=0;i<nclistlength(dims);i++) 
190if(stridep[i]==1)
191fprintf(stderr,"[%lu:%lu]",(unsigned long)startp[i],(unsigned long)((startp[i]+countp[i])-1));
192else
193fprintf(stderr,"[%lu:%lu:%lu]",
194(unsigned long)startp[i],
195(unsigned long)stridep[i],
196(unsigned long)(((startp[i]+countp[i])*stridep[i])-1));
197}
198fprintf(stderr,"\n");
199 }
200#endif
201
202    dsttype = (dsttype0);
203
204    /* Default to using the inquiry type for this var*/
205    if(dsttype == NC_NAT) dsttype = cdfvar->externaltype;
206
207    /* Validate any implied type conversion*/
208    if(cdfvar->etype != dsttype && dsttype == NC_CHAR) {
209        /* The only disallowed conversion is to/from char and non-byte
210           numeric types*/
211        switch (cdfvar->etype) {
212        case NC_STRING: case NC_URL:
213        case NC_CHAR: case NC_BYTE: case NC_UBYTE:
214            break;
215        default:
216            return THROW(NC_ECHAR);
217        }
218    }
219
220    ncstat = makegetvar34(dapcomm,cdfvar,data,dsttype,&varainfo);
221    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
222
223    state = 0;
224    if(iscached(dapcomm,cdfvar,&cachenode)) {
225        state = CACHED;
226        ASSERT((cachenode != NULL));
227#ifdef DEBUG
228fprintf(stderr,"var is in cache\n");
229#endif
230        /* If it is cached, then it is a whole variable but may still
231           need to apply constraints during the walk */
232        ASSERT(cachenode->wholevariable); /* by construction */
233    } else if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
234        state = FETCHWHOLE;
235    } else {/* load using constraints */
236        if(FLAGSET(dapcomm->controls,NCF_WHOLEVAR))
237            state = FETCHVAR;
238        else
239            state = FETCHPART;
240    }
241
242    ASSERT(state != 0);   
243
244    /* Convert the start/stop/stride info into a projection */
245    ncstat = buildvaraprojection3(varainfo,
246                                  startp,countp,stridep,
247                                  &varaprojection);
248    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
249
250    fetchprojection = NULL;
251    walkprojection = NULL;
252
253    /* Create walkprojection as the merge of the url projections
254       and the vara projection; may change in FETCHPART case below*/
255    ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections,
256                                   varaprojection,&walkprojection);
257    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
258
259#ifdef DEBUG
260fprintf(stderr,"getvarx: walkprojection: |%s|\n",dumpprojection(walkprojection));
261#endif
262
263    /* define the var list of interest */
264    vars = nclistnew();
265    nclistpush(vars,(ncelem)varainfo->target);
266
267    switch (state) {
268
269    case FETCHWHOLE: {
270        /* buildcachenode3 will create a new cachenode and
271           will also fetch the whole corresponding datadds.
272        */
273        /* Build the complete constraint to use in the fetch */
274        fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
275        /* Use no projections or selections */
276        fetchconstraint->projections = nclistnew();
277        fetchconstraint->selections = nclistnew();
278#ifdef DEBUG
279fprintf(stderr,"getvarx: FETCHWHOLE: fetchconstraint: %s\n",dumpconstraint(fetchconstraint));
280#endif
281        ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0);
282        fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/
283        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
284    } break;
285
286    case CACHED: {
287    } break;
288
289    case FETCHVAR: { /* Fetch a complete single variable */
290        /* Create fetch projection as the merge of the url projections
291           and the vara projection */
292        ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections,
293                                       varaprojection,&fetchprojection);
294        /* elide any sequence and string dimensions (dap servers do not allow such). */
295        ncstat = removepseudodims(fetchprojection);
296        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
297
298        /* Convert to a whole variable projection */
299        dcemakewholeprojection(fetchprojection);
300
301#ifdef DEBUG
302fprintf(stderr,"getvarx: FETCHVAR: fetchprojection: |%s|\n",dumpprojection(fetchprojection));
303#endif
304
305        /* Build the complete constraint to use in the fetch */
306        fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
307        /* merged constraint just uses the url constraint selection */
308        fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections);
309        /* and the created fetch projection */
310        fetchconstraint->projections = nclistnew();
311        nclistpush(fetchconstraint->projections,(ncelem)fetchprojection);
312#ifdef DEBUG
313fprintf(stderr,"getvarx: FETCHVAR: fetchconstraint: %s\n",dumpconstraint(fetchconstraint));
314#endif
315        /* buildcachenode3 will create a new cachenode and
316           will also fetch the corresponding datadds.
317        */
318        ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0);
319        fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/
320        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
321    } break;
322
323    case FETCHPART: {
324        /* Create fetch projection as the merge of the url projections
325           and the vara projection */
326        ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections,
327                                       varaprojection,&fetchprojection);
328        /* elide any sequence and string dimensions (dap servers do not allow such). */
329        ncstat = removepseudodims(fetchprojection);
330        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
331
332        /* Shift the varaprojection for simple walk */
333        dcefree((DCEnode*)walkprojection) ; /* reclaim any existing walkprojection */       
334        walkprojection = (DCEprojection*)dceclone((DCEnode*)varaprojection);
335        dapshiftprojection(walkprojection);
336
337#ifdef DEBUG
338fprintf(stderr,"getvarx: FETCHPART: fetchprojection: |%s|\n",dumpprojection(fetchprojection));
339#endif
340
341        /* Build the complete constraint to use in the fetch */
342        fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
343        /* merged constraint just uses the url constraint selection */
344        fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections);
345        /* and the created fetch projection */
346        fetchconstraint->projections = nclistnew();
347        nclistpush(fetchconstraint->projections,(ncelem)fetchprojection);
348#ifdef DEBUG
349fprintf(stderr,"getvarx: FETCHPART: fetchconstraint: %s\n",dumpconstraint(fetchconstraint));
350#endif
351        /* buildcachenode3 will create a new cachenode and
352           will also fetch the corresponding datadds.
353        */
354        ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0);
355        fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/
356        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
357    } break;
358
359    default: PANIC1("unknown fetch state: %d\n",state);
360    }
361
362    ASSERT(cachenode != NULL);
363
364#ifdef DEBUG
365fprintf(stderr,"cache.datadds=%s\n",dumptree(cachenode->datadds));
366#endif
367
368    /* attach DATADDS to (constrained) DDS */
369    unattach34(dapcomm->cdf.ddsroot);
370    ncstat = attachsubset34(cachenode->datadds,dapcomm->cdf.ddsroot);
371    if(ncstat) goto fail;       
372
373    /* Fix up varainfo to use the cache */
374    varainfo->cache = cachenode;
375    cachenode = NULL;
376    varainfo->varaprojection = walkprojection;
377    walkprojection = NULL;
378
379    /* Get the var correlate from the datadds */
380    target = varainfo->target;
381    xtarget = target->attachment;
382    if(xtarget == NULL) 
383        {THROWCHK(ncstat=NC_ENODATA); goto fail;}
384
385    /* Switch to datadds tree space*/
386    varainfo->target = xtarget;
387    ncstat = moveto(dapcomm,varainfo,varainfo->cache->datadds,data);
388    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
389
390    goto ok;
391
392fail:
393    if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
394ok:
395    nclistfree(vars);
396    dcefree((DCEnode*)varaprojection);
397    dcefree((DCEnode*)fetchconstraint);
398    freegetvara(varainfo);
399    return THROW(ncstat);
400}
401
402/* Remove any pseudodimensions (sequence and string)*/
403static NCerror
404removepseudodims(DCEprojection* proj)
405{
406    int i;
407#ifdef DEBUG1
408fprintf(stderr,"removesequencedims.before: %s\n",dumpprojection(proj));
409#endif
410    for(i=0;i<nclistlength(proj->var->segments);i++) {
411        DCEsegment* seg = (DCEsegment*)nclistget(proj->var->segments,i);
412        CDFnode* cdfnode = (CDFnode*)seg->annotation;
413        if(cdfnode->array.seqdim != NULL)
414            seg->rank = 0;
415        else if(cdfnode->array.stringdim != NULL)
416            seg->rank--;
417    }
418#ifdef DEBUG1
419fprintf(stderr,"removepseudodims.after: %s\n",dumpprojection(proj));
420#endif
421    return NC_NOERR;
422}
423
424static NCerror
425moveto(NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xrootnode, void* memory)
426{
427    OCerror ocstat = OC_NOERR;
428    NCerror ncstat = NC_NOERR;
429    OCconnection conn = nccomm->oc.conn;
430    OCdata xrootcontent;
431    OCobject ocroot;
432    NClist* path = nclistnew();
433    struct NCMEMORY memstate;
434
435    memstate.next = (memstate.memory = memory);
436
437    /* Get the root content*/
438    ocroot = xrootnode->tree->ocroot;
439    xrootcontent = oc_data_new(conn);
440    ocstat = oc_data_root(conn,ocroot,xrootcontent);
441    if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
442
443    /* Remember: xgetvar->target is in DATADDS tree */
444    collectnodepath3(xgetvar->target,path,WITHDATASET);
445    ncstat = movetor(nccomm,xrootcontent,
446                     path,0,xgetvar,0,&memstate,
447                     xgetvar->varaprojection->var->segments);
448
449done:
450    nclistfree(path);
451    oc_data_free(conn,xrootcontent);
452    if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
453    return THROW(ncstat);
454}
455
456static NCerror
457movetor(NCDAPCOMMON* nccomm,
458        OCdata currentcontent,
459        NClist* path,
460        int depth, /* depth is position in segment list*/
461        Getvara* xgetvar,
462        int dimindex, /* dimindex is position in xgetvar->slices*/
463        struct NCMEMORY* memory,
464        NClist* segments)
465{
466    int i;
467    OCerror ocstat = OC_NOERR;
468    NCerror ncstat = NC_NOERR;
469    size_t fieldindex,gridindex,rank;
470    OCconnection conn = nccomm->oc.conn;
471    CDFnode* xnode = (CDFnode*)nclistget(path,depth);
472    OCdata reccontent = OCNULL;
473    OCdata dimcontent = OCNULL;
474    OCdata fieldcontent = OCNULL;
475    Dapodometer* odom = OCNULL;
476    OCmode currentmode = OCNULLMODE;
477    CDFnode* xnext;
478    int hasstringdim = 0;
479    size_t dimoffset;
480    DCEsegment* segment;
481    int newdepth;
482    int caching = FLAGSET(nccomm->controls,NCF_CACHE);
483    int unconstrainable = FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE);
484
485    /* Note that we use depth-1 because the path contains the DATASET
486       but the segment list does not */
487    segment = (DCEsegment*)nclistget(segments,depth-1); /*may be NULL*/
488    if(xnode->etype == NC_STRING || xnode->etype == NC_URL) hasstringdim = 1;
489
490    ocstat = oc_data_mode(conn,currentcontent,&currentmode);
491
492#ifdef DEBUG2
493fprintf(stderr,"moveto: nctype=%d currentmode=%d depth=%d dimindex=%d",
494        xnode->nctype, currentmode, depth,dimindex);
495fprintf(stderr," segment=%s hasstringdim=%d\n",
496                dcetostring((DCEnode*)segment),hasstringdim);
497#endif
498
499    /* Switch on the combination of nctype and mode */
500#define CASE(nc1,nc2) (nc1*1024+nc2)
501
502    /* This must be consistent with the oc mode transition function */
503    switch (CASE(xnode->nctype,currentmode)) {
504
505    default:
506        PANIC2("Illegal combination: nctype=%d mode=%d",
507                (int)xnode->nctype,(int)currentmode);
508        break;
509
510    case CASE(NC_Sequence,OCFIELDMODE):
511    case CASE(NC_Dataset,OCFIELDMODE):
512    case CASE(NC_Grid,OCFIELDMODE):
513    case CASE(NC_Structure,OCFIELDMODE):
514        /* currentcontent points to the grid/dataset/structure instance */
515        xnext = (CDFnode*)nclistget(path,depth+1);
516        ASSERT((xnext != NULL));
517        fieldindex = findfield(xnode,xnext);
518        /* If the next node is a virtual node, then
519           we need to effectively
520           ignore it and use the appropriate subnode.
521           If the next node is a structuregrid node, then
522           use it as is.
523        */
524        if(xnext->virtual) {
525            CDFnode* xgrid = xnext;
526            xnext = (CDFnode*)nclistget(path,depth+2); /* real node */
527            gridindex = fieldindex;
528            fieldindex = findfield(xgrid,xnext);
529            fieldindex += gridindex;
530            newdepth = depth+2;
531        } else {
532            newdepth = depth+1;
533        }
534        fieldcontent = oc_data_new(conn);
535        ocstat = oc_data_ith(conn,currentcontent,fieldindex,fieldcontent);
536        if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
537        ncstat = movetor(nccomm,fieldcontent,
538                         path,newdepth,xgetvar,dimindex,memory,
539                         segments);
540        break;
541
542    case CASE(NC_Sequence,OCARRAYMODE): /* will actually always be scalar, but will have
543                                           rank == 1 to account for the sequence dim */
544    case CASE(NC_Grid,OCARRAYMODE): /* will actually always be scalar */
545    case CASE(NC_Structure,OCARRAYMODE):
546        /* figure out which slices refer to this node:
547           dimindex upto dimindex+rank; */
548        ASSERT((segment != NULL));
549        rank = segment->rank;
550        if(xnode->nctype == NC_Sequence)
551            rank--; /* ignore the sequence dim */
552        if(rank == 0) {
553            odom = newdapodometer1(1);
554        } else if(caching || unconstrainable) { 
555            odom = newdapodometer(segment->slices,0,rank);         
556        } else { /*Since vara was projected out, build a simple odometer*/
557            odom = newsimpledapodometer(segment,rank);
558        }
559        while(dapodometermore(odom)) {
560            OCmode mode;
561            /* Compute which instance to move to*/
562            dimoffset = dapodometercount(odom);
563            dimcontent = oc_data_new(conn);
564            ocstat = oc_data_ith(conn,currentcontent,dimoffset,dimcontent);
565            if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
566            ocstat = oc_data_mode(conn,dimcontent,&mode);
567            ASSERT((mode == OCFIELDMODE
568                    || (mode == OCSEQUENCEMODE && xnode->nctype == NC_Sequence)));
569            ncstat = movetor(nccomm,dimcontent,
570                                 path,depth,
571                                 xgetvar,dimindex+rank,
572                                 memory,segments);
573            dapodometerincr(odom);
574        }
575        freedapodometer(odom);
576        break;
577
578    case CASE(NC_Sequence,OCSEQUENCEMODE): {
579        DCEslice* uslice;
580        ASSERT((segment != NULL));
581        /* Get and check the corresponding sequence dimension from DDS */
582        ASSERT((xnode->attachment != NULL));
583        /* use uslice to walk the sequence; however, watch out
584           for the case when the user set a limit and that limit
585           is not actually reached in this request.
586        */
587        /* By construction, this sequence represents the first
588           (and only) dimension of this segment */
589        uslice = &segment->slices[0];
590        reccontent = oc_data_new(conn);
591        for(i=uslice->first;i<uslice->stop;i+=uslice->stride) {
592            OCmode eos;
593            ocstat = oc_data_ith(conn,currentcontent,i,reccontent);
594            if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
595            ocstat = oc_data_mode(conn,reccontent,&eos);
596            if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
597            if(eos == OCNULLMODE) {
598                /* We asked for too much */
599                ncstat = THROW(NC_EINVALCOORDS);
600                goto fail;
601            }
602            ncstat = movetor(nccomm,reccontent,
603                                 path,depth,
604                                 xgetvar,dimindex+1,
605                                 memory,segments);
606            if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto fail;}
607        }
608        } break;
609
610    case CASE(NC_Primitive,OCPRIMITIVEMODE):
611        if(hasstringdim)
612            ncstat = extractstring(nccomm, xgetvar, xnode, segment, conn, currentcontent, memory);
613        else   
614            ncstat = extract(nccomm, xgetvar, xnode, segment, conn, currentcontent, memory);
615        break;
616
617    }
618    goto ok;
619
620fail:
621ok:
622    oc_data_free(conn,dimcontent);
623    oc_data_free(conn,fieldcontent);
624    oc_data_free(conn,reccontent);
625    if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
626    return THROW(ncstat);
627}
628
629/* Determine the index in the odometer at which
630   the odometer will be walking the whole subslice
631   This will allow us to optimize.
632*/
633static int 
634wholeslicepoint(Dapodometer* odom)
635{
636    unsigned int i;
637    int point;
638    for(point=-1,i=0;i<odom->rank;i++) {
639        ASSERT((odom->slices[i].declsize != 0));
640        if(odom->slices[i].first != 0 || odom->slices[i].stride != 1
641           || odom->slices[i].length != odom->slices[i].declsize)
642            point = i;
643    }
644    if(point == -1)
645        point = 0; /* wholevariable */
646    else if(point == (odom->rank - 1)) 
647        point = -1; /* no whole point */
648    else
649        point += 1; /* intermediate point */
650    return point;
651}
652
653static int
654findfield(CDFnode* node, CDFnode* field)
655{
656    size_t i;
657    for(i=0;i<nclistlength(node->subnodes);i++) {
658        CDFnode* test = (CDFnode*) nclistget(node->subnodes,i);
659        if(test == field) return i;
660    }
661    return -1;
662}
663
664
665int
666nc3d_getvarmx(int ncid, int varid,
667            const size_t *start,
668            const size_t *edges,
669            const ptrdiff_t* stride,
670            const ptrdiff_t* map,
671            void* data,
672            nc_type dsttype0)
673{
674    NCerror ncstat = NC_NOERR;
675    int i;
676    NC* drno;
677    NC* substrate;
678    NCDAPCOMMON* dapcomm;
679    NC_var* var;
680    CDFnode* cdfvar; /* cdf node mapping to var*/
681    NClist* varnodes;
682    nc_type dsttype;
683    size_t externsize;
684    size_t dimsizes[NC_MAX_VAR_DIMS];
685    Dapodometer* odom = NULL;
686    unsigned int ncrank;
687    NClist* ncdims = NULL;
688    size_t nelems;
689#ifdef NEWVARM
690    char* localcopy; /* of whole variable */
691#endif
692
693    ncstat = NC_check_id(ncid, (NC**)&drno); 
694    if(ncstat != NC_NOERR) goto done;
695    dapcomm = (NCDAPCOMMON*)drno->dispatchdata;
696
697    ncstat = NC_check_id(drno->substrate, (NC**)&substrate); 
698    if(ncstat != NC_NOERR) goto done;
699    var = NC_lookupvar(substrate,varid);
700    if(var == NULL) {ncstat = NC_ENOTVAR; goto done;}
701
702    /* Locate var node via varid */
703    varnodes = dapcomm->cdf.varnodes;
704    for(i=0;i<nclistlength(varnodes);i++) {
705        CDFnode* node = (CDFnode*)nclistget(varnodes,i);
706        if(node->array.basevar == NULL
707           && node->nctype == NC_Primitive
708           && node->ncid == varid) {
709            cdfvar = node;
710            break;
711        }
712    }
713
714    ASSERT((cdfvar != NULL));
715    ASSERT((strcmp(cdfvar->ncfullname,var->name->cp)==0));
716
717    if(nclistlength(cdfvar->array.dimsetplus) == 0) {
718       /* The variable is a scalar; consequently, there is only one
719          thing to get and only one place to put it.  (Why was I
720          called?) */
721        /* recurse with additional parameters */
722        return THROW(nc3d_getvarx(ncid,varid,
723                 NULL,NULL,NULL,
724                 data,dsttype0));
725    }
726         
727    dsttype = (dsttype0);
728
729    /* Default to using the inquiry type for this var*/
730    if(dsttype == NC_NAT) dsttype = cdfvar->externaltype;
731
732    /* Validate any implied type conversion*/
733    if(cdfvar->etype != dsttype && dsttype == NC_CHAR) {
734        /* The only disallowed conversion is to/from char and non-byte
735           numeric types*/
736        switch (cdfvar->etype) {
737        case NC_STRING: case NC_URL:
738        case NC_CHAR: case NC_BYTE: case NC_UBYTE:
739            break;
740        default:
741            return THROW(NC_ECHAR);
742        }
743    }
744
745    externsize = nctypesizeof(dsttype);
746
747    /* Accumulate the dimension sizes and the total # of elements */
748    ncdims = cdfvar->array.dimsetall;
749    ncrank = nclistlength(ncdims);
750
751    nelems = 1; /* also Compute the number of elements being retrieved */
752    for(i=0;i<ncrank;i++) {
753        CDFnode* dim = (CDFnode*)nclistget(ncdims,i);
754        dimsizes[i] = dim->dim.declsize;
755        nelems *= edges[i];
756    }
757
758    /* Originally, this code repeatedly extracted single values
759       using get_var1. In an attempt to improve performance,
760       I have converted to reading the whole variable at once
761       and walking it locally.
762    */
763
764#ifdef NEWVARM
765    localcopy = (char*)malloc(nelems*externsize);
766
767    /* We need to use the varieties of get_vars in order to
768       properly do conversion to the external type
769    */
770
771    switch (dsttype) {
772
773    case NC_CHAR:
774        ncstat = nc_get_vars_text(ncid,varid,start, edges, stride,
775                                  (char*)localcopy);
776        break;
777    case NC_BYTE:
778        ncstat = nc_get_vars_schar(ncid,varid,start, edges, stride,
779                                   (signed char*)localcopy);
780        break;
781    case NC_SHORT:
782        ncstat = nc_get_vars_short(ncid,varid, start, edges, stride,
783                                   (short*)localcopy);
784        break;
785    case NC_INT:
786        ncstat = nc_get_vars_int(ncid,varid,start, edges, stride,
787                                 (int*)localcopy);
788        break;
789    case NC_FLOAT:
790        ncstat = nc_get_vars_float(ncid,varid,start, edges, stride,
791                                   (float*)localcopy);
792        break;
793    case NC_DOUBLE:
794        ncstat = nc_get_vars_double(ncid,varid, start, edges, stride,
795                                    (double*)localcopy);
796        break;
797    default: break;
798    }
799
800    odom = newdapodometer2(start,edges,stride,0,ncrank);
801
802    /* Walk the local copy */
803    for(i=0;i<nelems;i++) {
804        size_t voffset = dapodometervarmcount(odom,map,dimsizes);
805        void* dataoffset = (void*)(((char*)data) + (externsize*voffset));
806        char* localpos = (localcopy + externsize*i);
807        /* extract the indexset'th value from local copy */
808        memcpy(dataoffset,(void*)localpos,externsize);
809/*
810fprintf(stderr,"new: %lu -> %lu  %f\n",
811        (unsigned long)(i),
812        (unsigned long)voffset,
813        *(float*)localpos);
814*/
815        dapodometerincr(odom);
816    }   
817#else
818    odom = newdapodometer2(start,edges,stride,0,ncrank);
819    while(dapodometermore(odom)) {
820        size_t* indexset = dapodometerindices(odom);
821        size_t voffset = dapodometervarmcount(odom,map,dimsizes);
822        char internalmem[128];
823        char externalmem[128];
824        void* dataoffset = (void*)(((char*)data) + (externsize*voffset));
825
826        /* get the indexset'th value using variable's internal type */
827        ncstat = nc_get_var1(ncid,varid,indexset,(void*)&internalmem);
828        if(ncstat != NC_NOERR) goto done;
829        /* Convert to external type */
830        ncstat = dapconvert3(cdfvar->etype,dsttype,externalmem,internalmem);
831        if(ncstat != NC_NOERR) goto done;
832        memcpy(dataoffset,(void*)externalmem,externsize);
833/*
834fprintf(stderr,"old: %lu -> %lu  %f\n",
835        (unsigned long)dapodometercount(odom),
836        (unsigned long)voffset,
837        *(float*)externalmem);
838*/
839        dapodometerincr(odom);
840    }   
841#endif
842
843done:
844    return ncstat;
845}
846
847static int
848conversionrequired(nc_type t1, nc_type t2)
849{
850    if(t1 == t2)
851        return 0;
852    if(nctypesizeof(t1) != nctypesizeof(t2))
853        return 1;
854    /* Avoid too many cases by making t1 < t2 */
855    if(t1 > t2) {int tmp = t1; t1 = t2; t2 = tmp;}
856#undef CASE
857#define CASE(t1,t2) ((t1)<<5 | (t2))
858    switch (CASE(t1,t2)) {
859    case CASE(NC_BYTE,NC_UBYTE):
860    case CASE(NC_BYTE,NC_CHAR):
861    case CASE(NC_CHAR,NC_UBYTE):
862    case CASE(NC_SHORT,NC_USHORT):
863    case CASE(NC_INT,NC_UINT):
864    case CASE(NC_INT64,NC_UINT64):
865        return 0;
866    default: break;
867    }
868    return 1;
869}
870
871/* We are at a primitive variable or scalar that has no string dimensions.
872Extract the data.
873(This is way too complicated)
874*/
875static int
876extract(
877        NCDAPCOMMON* nccomm,
878        Getvara* xgetvar,
879        CDFnode* xnode,
880        DCEsegment* segment,
881        OClink conn,
882        OCdata currentcontent,
883        struct NCMEMORY* memory
884       )
885{
886    OCerror ocstat = OC_NOERR;
887    NCerror ncstat = NC_NOERR;
888    size_t rank;
889    Dapodometer* odom = OCNULL;
890    int wholepoint;
891    size_t externtypesize;
892    size_t interntypesize;
893    char* localmemory = NULL;
894    size_t odomsubsize;
895    size_t internlen;
896    int requireconversion;
897    char value[16]; 
898
899    ASSERT((segment != NULL));
900
901    requireconversion = conversionrequired(xgetvar->dsttype,xnode->etype);
902
903    rank = segment->rank;
904
905    if(rank == 0) {/* scalar */
906        char* mem = (requireconversion?value:memory->next);
907        ASSERT((segment != NULL));
908        externtypesize = nctypesizeof(xgetvar->dsttype);
909        ASSERT(externtypesize <= sizeof(value));
910        /* Read the whole scalar directly into memory  */
911        ocstat = oc_data_get(conn,currentcontent,mem,externtypesize,0,1);
912        if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
913        if(requireconversion) {
914            /* convert the value to external type */
915            ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1);
916            if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
917        }
918        memory->next += (externtypesize);
919
920    } else {/* rank > 0 */
921
922#ifdef DEBUG2
923fprintf(stderr,"moveto: primitive: segment=%s",
924                dcetostring((DCEnode*)segment));
925fprintf(stderr," iswholevariable=%d",xgetvar->cache->wholevariable);
926fprintf(stderr,"\n");
927#endif
928
929        ASSERT(xgetvar->cache != NULL);
930        if(xgetvar->cache->wholevariable) {
931            odom = newdapodometer(segment->slices,0,rank);
932        } else { /*!xgetvar->cache->wholevariable*/
933            odom = newsimpledapodometer(segment,rank);
934        }
935        /* Optimize off the use of the odometer by checking the slicing
936           to see if the whole variable, or some whole subslice
937           is being extracted.
938           However do not do this if the external type conversion is needed
939           or if the whole slice point is rank-1 (normal case anyway).
940        */
941        externtypesize = nctypesizeof(xgetvar->dsttype);
942        interntypesize = nctypesizeof(xnode->etype);
943        wholepoint = wholeslicepoint(odom);
944        if(wholepoint == -1)
945            odomsubsize = 1; /* no whole point */
946        else
947            odomsubsize = dapodometerspace(odom,wholepoint);
948        internlen = (odomsubsize*interntypesize);
949        if(requireconversion) {
950            /* copy the data locally before conversion */
951            localmemory = (char*)malloc(internlen);
952        } else {
953            localmemory = memory->next;
954        }
955
956#ifdef DEBUG2
957fprintf(stderr,"moveto: primitive: ");
958fprintf(stderr," wholepoint=%d",wholepoint);
959fprintf(stderr,"\n");
960#endif
961
962        if(wholepoint == 0) {/* whole variable */
963            /* Read the whole n elements directly into memory.*/
964            ocstat = oc_data_get(conn,currentcontent,localmemory,
965                                 internlen,0,odomsubsize);
966            if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
967            if(requireconversion) {
968                /* do conversion */
969                ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,
970                                     memory->next,localmemory,odomsubsize);
971                if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
972            }
973            memory->next += (externtypesize*odomsubsize);
974        } else if(wholepoint > 0) {/* whole subslice */
975            odom->rank = wholepoint; /* truncate */
976            while(dapodometermore(odom)) {
977                size_t dimoffset = dapodometercount(odom) * odomsubsize;
978                ocstat = oc_data_get(conn,currentcontent,localmemory,
979                                         internlen,dimoffset,odomsubsize);
980                if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
981                if(requireconversion) {
982                    /* do conversion */
983                    ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,
984                                         memory->next,localmemory,odomsubsize);
985                    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
986                }
987                memory->next += (externtypesize*odomsubsize);
988                dapodometerincr(odom);
989            }
990        } else { /* Oh well, use the odometer to walk to the
991                    appropriate fields*/
992            while(dapodometermore(odom)) {
993                char* mem = (requireconversion?value:memory->next);
994                size_t dimoffset = dapodometercount(odom);
995                ocstat = oc_data_get(conn,currentcontent,mem,externtypesize,dimoffset,1);
996                if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
997                if(requireconversion) {
998                    ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1);
999                    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
1000                }
1001                memory->next += externtypesize;
1002                dapodometerincr(odom);
1003            }
1004        }
1005        freedapodometer(odom);
1006        if(requireconversion) nullfree(localmemory);
1007    }
1008done:
1009    return THROW(ncstat);
1010}
1011
1012
1013static NCerror
1014slicestring(OCconnection conn, char* stringmem, DCEslice* slice, struct NCMEMORY* memory)
1015{
1016    size_t stringlen;
1017    unsigned int i;
1018    NCerror ncstat = NC_NOERR;
1019    char* lastchar;
1020    size_t charcount; /* number of characters inserted into memory */
1021
1022    /* libnc-dap chooses to convert string escapes to the corresponding
1023       character; so we do likewise.
1024    */
1025    dapexpandescapes(stringmem); 
1026    stringlen = strlen(stringmem);
1027
1028#ifdef DEBUG2
1029fprintf(stderr,"moveto: slicestring: string/%lu=%s\n",stringlen,stringmem);
1030fprintf(stderr,"slicestring: %lu string=|%s|\n",stringlen,stringmem);
1031fprintf(stderr,"slicestring: slice=[%lu:%lu:%lu/%lu]\n",
1032slice->first,slice->stride,slice->stop,slice->declsize);
1033#endif
1034
1035    /* Stride across string; if we go past end of string, then pad*/
1036    charcount = 0;
1037    for(i=slice->first;i<slice->length;i+=slice->stride) {
1038        if(i < stringlen)
1039            *memory->next = stringmem[i];
1040        else /* i >= stringlen*/
1041            *memory->next = NC_FILL_CHAR;
1042        memory->next++;
1043        charcount++;
1044    }
1045    lastchar = (memory->next);
1046    if(charcount > 0) {
1047        lastchar--;
1048    }
1049
1050    return THROW(ncstat);
1051}
1052
1053/*
1054Extract data for a netcdf variable that has a string dimension.
1055*/
1056static int
1057extractstring(
1058        NCDAPCOMMON* nccomm,
1059        Getvara* xgetvar,
1060        CDFnode* xnode,
1061        DCEsegment* segment,
1062        OClink conn,
1063        OCdata currentcontent,
1064        struct NCMEMORY* memory
1065       )
1066{
1067    NCerror ncstat = NC_NOERR;
1068    OCerror ocstat = OC_NOERR;
1069    int i;
1070    size_t rank;
1071    int caching = FLAGSET(nccomm->controls,NCF_CACHE);
1072    int unconstrainable = FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE);
1073    NClist* strings = NULL;
1074    Dapodometer* odom = OCNULL;
1075
1076    rank = segment->rank;
1077
1078    /* A number of optimizations are possible but none is currently used. */
1079
1080    /* Use the odometer to walk to the appropriate fields*/
1081    if(rank == 1) {
1082        odom = newdapodometer1(1); /* scalar case */
1083    } else if(caching || unconstrainable) {     
1084        odom = newdapodometer(segment->slices,0,rank-1);           
1085    } else { /*Since vara was projected out, build a simple odometer*/
1086        odom = newsimpledapodometer(segment,rank-1);
1087    }
1088
1089    /* step thru the odometer obtaining each string and storing it in an OClist */
1090    strings = nclistnew();
1091    nclistsetalloc(strings,dapodometerspace(odom,0)); /* preallocate */
1092    while(dapodometermore(odom)) {
1093        char* value = NULL;
1094        size_t dimoffset = dapodometercount(odom);
1095        ocstat = oc_data_get(conn,currentcontent,&value,sizeof(value),dimoffset,1);
1096        if(ocstat != OC_NOERR) goto done;
1097        nclistpush(strings,(ncelem)value);     
1098        dapodometerincr(odom);
1099    }
1100    freedapodometer(odom);
1101    /* Get each string in turn, slice it and store in user
1102       supplied memory */
1103    for(i=0;i<nclistlength(strings);i++) {
1104        char* s = (char*)nclistget(strings,i);
1105        slicestring(conn,s,&segment->slices[rank-1],memory);
1106        free(s);       
1107    }   
1108    nclistfree(strings);
1109done:
1110    if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
1111    return THROW(ncstat);
1112}
Note: See TracBrowser for help on using the repository browser.