Skip to content

Commit 2d549ad

Browse files
authored
Merge pull request #45 from wkliao/copy_attr
add test program to test attribute copy
2 parents 995a2b1 + ef151be commit 2d549ad

File tree

3 files changed

+157
-1
lines changed

3 files changed

+157
-1
lines changed

test/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#
55

66
check_PROGRAMS = tst_atts.py \
7+
tst_copy_attr.py \
78
tst_default_format.py \
89
tst_dims.py \
910
tst_file_fill.py \

test/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,12 @@ installation information.
9898
+ Test non-blocking APIs and then use `wait/wait_all` method of `File` class
9999
to flush out the pending I/O requests.
100100

101-
101+
* **tst_copy_attr.py**
102+
+ Copying an attribute from one file to another in python can be done without
103+
`ncmpi_copy_att()`. For exampl, this can be done in two lines of python
104+
codes below:
105+
```
106+
att = source_file.get_att("history")
107+
destition_file.put_att('history', att)
108+
```
102109

test/tst_copy_attr.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#
2+
# Copyright (C) 2024, Northwestern University and Argonne National Laboratory
3+
# See COPYRIGHT notice in top-level directory.
4+
#
5+
6+
"""
7+
This program tests how to copy an attribute from a file to another. Note that
8+
there is no ncmpi_copy_att() function in PnetCDF-Python. This is because
9+
copying a python object is much simpler than in C. In C, without
10+
ncmpi_copy_att(), one have to do the followings.
11+
1. find the size and type of the attribute from the source file
12+
2. malloc space, read from the source file
13+
3. write to the destination file
14+
4. free the buffer
15+
16+
In python, this can be done in two lines of codes:
17+
att = source_file.get_att("history")
18+
destition_file.put_att('history', att)
19+
20+
To run:
21+
% mpiexec -n num_process python3 tst_copy_attr.py [test_file_name]
22+
23+
Example commands for MPI run and outputs from running ncmpidump on the
24+
output netCDF file produced by this example program:
25+
26+
% mpiexec -n num_process python3 tst_copy_attr.py testfile.nc
27+
28+
% ncmpidump testfile.nc
29+
netcdf testfile {
30+
// file format: CDF-1
31+
variables:
32+
int var0 ;
33+
var0:history = "today" ;
34+
35+
// global attributes:
36+
:history = "today" ;
37+
data:
38+
39+
var0 = 0 ;
40+
}
41+
"""
42+
43+
import sys, os, argparse
44+
import numpy as np
45+
from mpi4py import MPI
46+
import pnetcdf
47+
48+
49+
def parse_help():
50+
help_flag = "-h" in sys.argv or "--help" in sys.argv
51+
if help_flag and rank == 0:
52+
help_text = (
53+
"Usage: {} [-h] | [-v] [file_name]\n"
54+
" [-h] Print help\n"
55+
" [-v] Verbose mode\n"
56+
" [-k format] file format: 1 for CDF-1, 2 for CDF-2, 5 for CDF-5\n"
57+
" [filename] (Optional) output netCDF file name\n"
58+
).format(sys.argv[0])
59+
print(help_text)
60+
return help_flag
61+
62+
63+
# Create two files and copy attributes from one file to another
64+
def pnetcdf_io(filename, file_format):
65+
66+
# Create the file
67+
f0 = pnetcdf.File(filename = filename, mode = 'w', format = file_format,
68+
comm = comm, info = None)
69+
70+
filename_dup = filename + "_dup.nc"
71+
f1 = pnetcdf.File(filename = filename_dup, mode = 'w', format = file_format,
72+
comm = comm, info = None)
73+
74+
# define a variable in each file
75+
v0 = f0.def_var('var0', 'i4', ())
76+
v1 = f1.def_var('var1', 'i4', ())
77+
78+
# put a new global attribute in f0
79+
f0.put_att('history','today')
80+
81+
# put a new attribute to variable v0 in f0
82+
v0.put_att('history','today')
83+
84+
# retrieve the global attribute from f0
85+
att = f0.get_att("history")
86+
87+
# copy it to f1
88+
f1.put_att('history', att)
89+
90+
# retrieve v0's attribute from f0
91+
v_att = v0.get_att("history")
92+
93+
# copy it to variable v1 in f1
94+
v1.put_att('history', v_att)
95+
96+
# close files
97+
f0.close()
98+
f1.close()
99+
100+
# Open file f1 and check the attribute contents
101+
f1 = pnetcdf.File(filename_dup, 'r', comm = comm)
102+
assert("today" == f1.get_att("history"))
103+
104+
v1=f1.variables['var1']
105+
assert("today" == v1.get_att("history"))
106+
107+
# close files
108+
f1.close()
109+
110+
111+
if __name__ == "__main__":
112+
comm = MPI.COMM_WORLD
113+
rank = comm.Get_rank()
114+
nprocs = comm.Get_size()
115+
116+
if parse_help():
117+
MPI.Finalize()
118+
sys.exit(1)
119+
120+
# get command-line arguments
121+
args = None
122+
parser = argparse.ArgumentParser()
123+
parser.add_argument("dir", nargs="?", type=str, help="(Optional) output directory name",\
124+
default = ".")
125+
parser.add_argument("-v", help="Verbose mod ", action="store_true")
126+
parser.add_argument("-k", help="File format: 1 for CDF-1, 2 for CDF-2, 5 for CDF-5")
127+
args = parser.parse_args()
128+
129+
verbose = True if args.v else False
130+
131+
file_format = None
132+
if args.k:
133+
kind_dict = {'1':None, '2':"NC_64BIT_OFFSET", '5':"NC_64BIT_DATA"}
134+
file_format = kind_dict[args.k]
135+
136+
filename = os.path.join(args.dir, "tst_copy_attr.nc")
137+
138+
if verbose and rank == 0:
139+
print("{}: test copying attributes ".format(os.path.basename(__file__)))
140+
141+
try:
142+
pnetcdf_io(filename, file_format)
143+
except BaseException as err:
144+
print("Error: type:", type(err), str(err))
145+
raise
146+
147+
MPI.Finalize()
148+

0 commit comments

Comments
 (0)