Hi gary: Thanks for your contributions. Below are some questions and comments: > > ---------------------------------------------------------------------------- > > A first example is a 3-D temperature grid for an ocean model. (I'm just a > programmer so the real-life applicability of the examples may be off. :) > Suppose the grid is curvilinear with sigma levels, defined with dimensions > (i, j, k). But for analysis or plotting the grid may need to be viewed over > lat/lon and either sigma or depth for the height, where the lat, lon, sigma, > and depth mappings are stored directly in the file as variables. Lat and lon > depend upon the (j,k) coordinate, depth depends upon (i,j,k), sigma depends > upon (i). > > * lat(j,k) > * lon(j,k) > * depth(i,j,k) > * sigma(i) > > There are at least four coordinate systems which associate the manifold > domain with an alternate base domain (using the wording Steve mentioned), > including the identity coordinate system. > > (i,j,k) => (depth, lon, lat) > (i,j,k) => (sigma, lon, lat) > (i,j,k) => (i, lon, lat) > (i,j,k) => (i,j,k) > > So to associate each alternate mapping with the temperature variable, each > mapping is named in the temp variable's temp attribute (except for the > identity since it's implicit): > > float temp(i, j, k); > temp:temp = "depth-map sigma-map lat-lon-map"; > > The mapping name refers to a global attribute which lists the coordinates of > the system. I appended -map to the names for clarity; I'm not suggesting the > convention require it. > > :depth-map = "depth lon lat"; > :sigma-map = "sigma lon lat"; > :lat-lon-map = "lon lat"; > :sigma = "sigma"; > > float lat(j, k); > float lon(j, k); > float sigma(i); > float depth(i,j,k); > depth:depth = "sigma"; > > Each coordinate name in a global map attribute refers to the variable which > maps to the values of that coordinate. There is some important consistency > here: a variable is always a mapping (from N-space to the 1-D range of the > variable), and the global map attributes are always used to specify the > components or range for a mapping, e.g., the coordinates of a coordinate > system. I would restate as: "a variable and a coord sys for the variable can both be considered functions on (more or less) the same index domain". I just wanted to check if you are saying more? > > Note that the lat-lon-map is independent of the i coordinate, in which case > the i coordinate is added to the lat-lon-map as an identity mapping of the > indices along i. E.g., point (1,1,1) of temp is at coordinate (1, -105.0, > 40.1) in the lat-lon-map coordinate system, point (2,j,k) is at (2, > lon(j,k), lat(j,k)). > > A user or application can deduce the coordinates on the depth grid of point > (i,j,k) by calculating (depth(i,j,k), lon(j,k), lat(j,k)). Choosing > sigma-map yields (sigma(i), lon(j,k), lat(j,k)). > > The sigma global map attribute indicates that it makes sense to plot depth > along a sigma axis, using the values of the sigma variable as the axis > coordinates. This is an example of the recursiveness allowed by the > convention. The temp variable's temp attribute can be followed to the > depth-map mapping, which points to the depth variable. But the depth > variable itself has an alternate coordinate system, sigma, whose global map > attribute refers directly to the sigma variable. Through this recursion an > application could infer the availability of the sigma-map mapping without it > being explicitly named in the temp attribute. I dont understand what the point of the lat-lon map or the sigma-map coord systems are. It seems like they are implied by the depth-map and the sigma-map coord systems? Also, the need for the identity coord function is not obvious. I would just say that the lat-lon coord sys is not complete. I am also noticing that the identity coord function doesnt really "assign a physical value", which is my definition of a coord system. I acknowledge you might need it now and then for ill-specified files, but I dont really think it deserves much of a place in our conventions. > > Note that this example doesn't change much if some of the variables are > dependent upon time. If the lat and lon variable mappings are static, the > coordinate systems would look like below. > > dimensions: > time (UNLIMITED); > i = 10; > j = 100; > k = 100; > > variables: > > float time(time); > float temp(time, i, j, k); > temp:temp = "depth-map sigma-map lat-lon-map"; > float salinity(time, i, j, k); > temp:temp = "depth-map sigma-map lat-lon-map"; > float density(time, i, j, k); > temp:temp = "depth-map sigma-map lat-lon-map"; > float depth(time, i,j,k); > depth:depth = "sigma"; > float lat(j, k); > float lon(j, k); > float sigma(i); > > :depth-map = "depth lon lat"; > :sigma-map = "sigma lon lat"; > :lat-lon-map = "lon lat"; > :sigma = "sigma"; > :time = "time"; > > The time mapping attribute is essentially an encoding of the usual > interpretation of 1-D coordinate variables. For backwards compatibility, the > existence of a coordinate variable could imply this attribute. Since none of > the alternate mappings for temp depend upon the time coordinate, time is > looked up as its own mapping, and the time global attribute refers back to > the time variable. > > The temp coordinate systems could also be named "more completely" as > follows: > > :depth-map = "time depth lon lat"; > :sigma-map = "time sigma lon lat"; > :lat-lon-map = "time i lon lat"; > > This is perhaps clearer and might be preferred by some users. The i > component in the lat-lon-map does not refer to another variable or mapping, > so it reverts to the identity mapping from the domain of the i coordinate. > (The identity mapping is effectively the default coordinate system for a > dimension.) > > Comments > > I thought about allowing the mapping names to refer directly to the > variable's attributes rather a global attribute, but in my opinion it's > better to make a mapping name unique for the whole file and avoid allowing > conflicting uses of map names between variables. I also considered letting a > mapping name refer directly to a variable name, so that these global > attributes would be unnecessary. > > :sigma = "sigma"; > :time = "time"; > > But that violates the orthogonality and consistency of mapping names always > being global attributes. I think some confusion could be avoided by naming > every mapping explicitly as a global attribute, even those mappings > currently implied by the coordinate variable convention. I think its important to have global specification with variable override. Imagine you have a file with 150 variables in it, and you have to specify the coord sys for each individual variable. Now you have a ncdump output: gotta check each one to see if they are the same (barf) ! On the other hand, if you have three variables each with a different coord system, its more compact to specify at the variable level. > > Lastly, there is nothing preventing an application from merging alternate > mappings of a variable. The temperature mappings could be listed as follows: > > float temp(time, i, j, k); > temp:temp = "time depth-map sigma-map lat-lon-map"; > > :depth-map = "depth"; > :sigma-map = "sigma"; > :lat-lon-map = "lon lat"; > :sigma = "sigma"; > :time = "time"; > > An application could assemble all possible combinations of mappings and > their coordinates, and in any order, including: > > (time(time), i, j, k) > (time(time), sigma(i), j, k) > (time(time), depth(time,i,j,k), lat(j,k), lon(j,k)) > (lat(j,k), lon(j,k), i, time) > (i, j, k, time(time), sigma(i), depth(time,i,j,k), lon(j,k), lat(j,k)) > > The last mapping, consisting of the intersection of all of the possible > coordinate systems, might be useful for a table. (A really, really, big > table. :) The mappings which can be described with this convention are > merely a superset of those possible with the proposed coordinates > referential attribute, which essentially lists the independent variables of > each alternate coordinate system for a variable. I'm merely suggesting an > extension of the referential idea to allow naming specific sets of > coordinates, so that each coordinate set can completely and more intuitively > describe a base coordinate system, not just for one variable but for the > whole file. I really think this is the wrong way to go, but as I see that you basically argue against it below, I'll assume you agree. But by saying that you would allow it I think you confuse whether you are listing coordinate systems or coordinate functions (I think "independent variables" is not true). All your good examples I think list coord systems. > > ---------------------------------------------------------------------------- > > Examples > > Wire Coil > > Here's Steve's wire coil example using the above ideas. I added two > coordinate systems for the wire temperature: the physical distance along the > wire and the cartesian coordinates. > > dimensions: > s = 100; > > variables: > float temp(s); // temperature along spiral > temp:temp = "distance-map cylinder-map cartesian-map" > float rho(s); // distance from CCS center axis > float theta(s); // CCS azimuth > float z(s); // CCS height > float distance(s); > distance:units = "cm"; > float y(s); > float x(s); > > // physical distance along wire > :distance-map = "distance" > // cylindrical coordinate system (CCS) > :cylinder-map = "z rho theta"; > // Cartesian map > :cartesian-map = "z y x"; this is good. > > Rectilinear Grid > > The simple coordinate variable case for a rectilinear grid > > float temp(lat,lon); > float lat(lat); > float lon(lon); > > becomes: > > float temp(time,lat,lon); > temp:temp = "world-map"; > float lat(lat); > float lon(lon); > :world-map = "lon lat"; > > The lat and lon dimensions could be renamed without affecting the > association described. Since the lat and lon mappings are independent of > each other in this case, this example could boil down to exactly the > previous referential attribute examples, except the usual coordinate > variable convention has been made explicit with a global map attribute: > > float temp(time,lat,lon); > temp:temp = "lat lon"; > float lat(lat); > float lon(lon); > :lat = "lat"; > :lon = "lon"; > > Comparisons to coordinates Attribute > > The temp mappings in the wire coil example can be replaced with their > constituent coordinates (variables), similar to the Walker and Waring > example and to Signell's independent variables: > > > double salt(n,k,j,i); > > salt:long_name = "Salinity"; > > salt:units = "1"; > > salt:coordinates = "t cell_z cell_y cell_x cell_lat > > temp:temp = "distance z rho theta y x" > > An application can generate all possible combinations of the mappings, > "factor out" (Russ' words) coordinates where possible and if desired, and > allow a user to choose the ones which make most sense. However, using the > global coordinate attribute allows the sensible mappings to be explicitly > named once for a file and referred to directly in each variable, and the > availability of "common" coordinate systems is more immediately evident to > the user. Also, the first mapping in a variable's referential attribute can > designate the default coordinate system. > > Also, I'd prefer using a global attribute over using variable attributes > with the same name as the corresponding dimension. Several fields with the > same "manifold" domain would each need attributes for each dimension, > instead of naming a single mapping in a single variable attribute. A global > map attribute would be unique for the whole file, whereas dimension > attributes among different variables would be redundant and could > contradict. Russ gave similar arguments and others in support of the global > dimension attribute. > > >From John Caron's comments about Walker and Waring: > > > > One part of their example I disagree with is lumping all of the > > coordinate functions together: > > double salt(n,k,j,i); > > salt:long_name = "Salinity"; > > salt:units = "1"; > > salt:coordinates = "t cell_z cell_y cell_x cell_lat > > cell_lon"; > > > > While there's nothing illegal about it, better is: > > salt:coordinates_xy = "t cell_z cell_y cell_x"; > > salt:coordinates_latlon = "t cell_z cell_lat cell_lon"; > > emphasizing that you are specifying two coordinate systems. > > I would agree with John, but I'd suggest this construction: > > double salt(n,k,j,i); > salt:long_name = "Salinity"; > salt:units = "1"; > salt:salt = "lat-lon-map cartesian-map"; > > :lat-lon-map = "t cell_z cell_lat cell_lon"; > :cartesian-map = "t cell_z cell_y cell_x"; > > The coordinate systems are explicit, and they only need to be specified once > rather than for each variable. your formulation would be acceptable; i'm not convinced that the temp:temp part is worth the trouble; theres nothing to suggest such an attribute should point to a coordinate system. The tradeoff is explicitness (eg an attribute "coordinate") vs avoiding "english-centricity". also i dont really agree/understand the notion of "factoring out". > > Boundary Layers > > Russ' boundary layer example using referential attributes, converted to > global map attributes: > > dimensions: > > bndlay = 5 ; // boundary layers > lon = 93 ; > lat = 65 ; > > variables: > > float RH_bndlay(bndlay, lat, lon) ; > RH_bndlay:long_name = "relative humidity in boundary layer" ; > RH_bndlay:units = "percent" ; > RH_bndlay:RH_bndlay = "boundary-map"; > > float bndlay_bot(bndlay) ; > bndlay_bot:long_name = "bottom of layer" ; > bndlay_bot:units = "hPa" ; > > float bndlay_top(bndlay) ; > bndlay_top:long_name = "top of layer" ; > bndlay_top:units = "hPa" ; > > :boundary-map = "bndlay_bot bndlay_top lat lon"; ive been toying with the idea of introducing a grouping syntax, like: :boundary-map = "(bndlay_bot bndlay_top) lat lon"; but i havent yet thought it through. > > record Attribute > > The NUWG conventions suggest a record attribute for model grids. > > float u(record, z, x, y); > u:record = "valtime, reftime"; > > double valtime(record); > valtime:long_name = "valid time of model"; > valtime:units = "minutes since (1993-1-1 00:00:00.0)"; > > double reftime(record); > reftime:long_name = "reference time of model"; > reftime:units = "minutes since (1993-1-1 00:00:00.0)"; > > Using map attributes, the multiple time components become a global mapping, > similar to Russ' example of a dimension attribute for time: > > 2. A global "dimension attribute": > > :time = "year day_of_year second_of_day"; > > Following are the corresponding examples using global map attributes. The > time mappings could be combined with lat/lon or other mappings for the other > dimensions as needed. > > variables: > float u (record, z, y, x); > u:u = "model-time-map"; > float observed_temp (record, z, y, x); > observed_temp:observed_temp = > "time-map model-time-map month-map"; > int year(record); > int day_of_year(record); > float second_of_day(record); > char month(record,4); > > :time-map = "year day_of_year second_of_day"; > :model-time-map = "valtime reftime"; > :month-map = "year month"; this is a confusing example, partly because of the indirection but once i parse it, i guess its straightforward: (i'll eliminate the x,y,z dimensions): we have two variables u(record) and observer_temp(record). u has coordinate system model-time-map, and observed_temp has coordinate systems model-time-map, time-map, and month-map. it would be surprising (though certainly possible) that in a real file u would not also have the other two time coords. > > Grid levels > > Here is an example based on the NUWG conventions for alternate grid level > coordinates, p or vpt. > > float u(record, z, x, y); > u:z = "vpt, p"; > > Using the global map attributes: > > float u(record, z, x, y); > u:u = "pres-grid-map vpt-grid-map"; > float p(record, z, x, y); > u:u = "vpt-grid-map"; > float vpt(record, z, x, y); > u:u = "pres-grid-map"; > > :pres-grid-map = "p x y"; > :vpt-grid-map = "vpt x y"; > > The default coordinate system for u would use pressure p for the height > axis, but availability of vpt is evident. actually, its explicit. > > ---------------------------------------------------------------------------- > > Extensions > > Set Notation > > Looking to the future, the global mapping attribute could adopt some > specialized syntax so that simple mappings could be included as a formula > rather than a whole array of data. If the distance variable in the wiring > example above is proportional to s, then distance-map could describe the > mapping using set notation. > > :distance-map = "{ (s) : s*1.6 }" this could be worth exploring. we'd need a syntax definition. did i say we couldn't embed methods? > > Virtual Vector Variables > > Since the global map attribute essentially lists multiple components of an > n-space range, it could also be interpreted as a vector. Perhaps call it a > virtual vector variable: > > float u_wind (time); > float v_wind (time); > float w_wind (time); > > :wind = "u_wind v_wind w_wind"; // 3-D vectors over time > > The problem is how to clearly indicate wind as a virtual variable. Perhaps > in a global vectors or variables attribute. how about :vector_<name> = "list of components"; eg :vector_wind = "u_wind v_wind w_wind"; // 3-D vectors over time although the question of what applications might do with tat info is unanswered. > > Sub-mapping > > It would be interesting to be able to specify mappings which map directly to > the coordinates of dimensions in the file. Suppose we wanted to specify a > subset of the ocean temperature grid in the first example. We could specify > a coordinate system whose range maps a subset of the domain of the temp > variable over (i,j,k). As one possibility, specify integer variables which > map into i, j, and k, and a global mapping which uses a colon (':') to > indicate that the coordinates map directly into the i, j, and k coordinates > of temp. The same method could be used for specifying the path of a particle > through the grid: > > dimensions: > i = 10; // Whole grid > j = 100; > k = 100; > i2 = 10; // Region of grid > j2 = 20; > k2 = 20; > > float temp (time, i, j, k); > temp:temp = "subgrid-map particle-trace-map"; > float depth(time, i,j,k); > depth:depth = "depth-estimate particle-trace-map"; > float lat(j, k); > lat:lat = "particle-trace-map"; > float lon(j, k); > lon:lon = "particle-trace-map"; > > int a (i2, j2, k2); > int b (i2, j2, k2); > int c (i2, j2, k2); > > int particle_i (time); > int particle_j (time); > int particle_k (time); > > :subgrid-map = "a:i b:j c:k"; > :particle-trace-map = "particle_i:i particle_j:j particle_k:k"; > > Using a "sub-mapping" implies a different domain for the variable's mapping. > In the case of plotting the water temperature along the particle track, the > user asks for temp over the particle-trace-map, which an application can > directly expand to > > temp (particle_i(time), particle_j(time), particle_k(time)) > > The particle's locations would be > > lat (particle_j(time), particle_k(time)) > lon (particle_j(time), particle_k(time)) > depth (time, particle_i(time), particle_j(time), particle_k(time)) > > which in turn might be described by a "virtual vector": > > :particle_locn = "lat lon depth"; > > If the sub-grid were sampled along each dimension independent of the other > dimensions: > > int a (i2); > int b (j2); > int c (k2); sorry, my eyeballs glazed over.... i'll try this example again later.... > > Close > > I left out details, like the specific syntax of the referential attribute, > and I'm concentrating specifically on describing coordinates systems and > mappings. Other conventions could be added later, such as units, projection > types, labelling of geographic coordinates so that applications can > recognize them, orientation of coordinates (e.g. vertical vs horizontal), > and so on. > > I've been working with netcdf since the beginning, especially with regards > to visualization software (Zebra) which stores and interprets > multi-dimensional data. Some netcdf conventions for describing these data > and their geographic coordinates would be very helpful, so I wanted to > contribute some ideas. If any of my reasoning is wrong, faulty, or unclear, > please let me and/or the netcdf mailing list know. Thanks for taking time to > check this out. > > ---------------------------------------------------------------------------- > > Gary Granger > July 12, 1997 i would be interested in examples from real life that you think a convention should cover, especially if not already listed in http://acd.ucar.edu/~caron/coordvar.html Regards, John.