Package: ovf
OVF Parser LibrarySimple API for powerful OOMMF Vector Field file parsingOVF format specificationPython package:Library CoveragePython Bindings CoverageHow to useFor usage examples, take a look into the test folders:test,python/testorfortran/test.Except for opening a file or initializing a segment, all functions return status codes
(generallyOVF_OK,OVF_INVALIDorOVF_ERROR).
When the return code is notOVF_OK, you can take a look into the latest message,
which should tell you what the problem was
(const char * ovf_latest_message(struct ovf_file *)in the C API).In C/C++ and Fortran, before writing a segment, make sure theovf_segmentyou pass in is
initialized, i.e. you already called eitherovf_read_segment_headerorovf_segment_create.C/C++Opening and closing:struct ovf_file *myfile = ovf_open("myfilename.ovf")to open a filemyfile->foundto check if the file exists on diskmyfile->is_ovfto check if the file contains an OVF headermyfile->n_segmentsto check the number of segments the file should containovf_close(myfile);to close the file and free resourcesReading from a file:struct ovf_segment *segment = ovf_segment_create()to initialize a new segment and get the pointerovf_read_segment_header(myfile, index, segment)to read the header into the segment structcreate float data array of appropriate size...ovf_read_segment_data_4(myfile, index, segment, data)to read the segment data into your float arraysettingsegment->Nbefore reading allows partial reading of large data segmentsWriting and appending to a file:struct ovf_segment *segment = ovf_segment_create()to initialize a new segment and get the pointersegment->n_cells[0] = ...etc to set data dimensions, title and description, etc.ovf_write_segment_4(myfile, segment, data, OVF_FORMAT_TEXT)to write a file containing the segment header and dataovf_append_segment_4(myfile, segment, data, OVF_FORMAT_TEXT)to append the segment header and data to the filePythonTo install theovf python package, either build and install from source
or simply usepip install ovfTo useovffrom Python, e.g.fromovfimportovfimportnumpyasnpdata=np.zeros((2,2,1,3),dtype='f')data[0,1,0,:]=[3.0,2.0,1.0]withovf.ovf_file("out.ovf")asovf_file:# Write one segmentsegment=ovf.ovf_segment(n_cells=[2,2,1])ifovf_file.write_segment(segment,data)!=-1:print("write_segment failed: ",ovf_file.get_latest_message())# Add a second segment to the same filedata[0,1,0,:]=[4.0,5.0,6.0]ifovf_file.append_segment(segment,data)!=-1:print("append_segment failed: ",ovf_file.get_latest_message())FortranThe Fortran bindings are written in object-oriented style for ease of use.
Writing a file, for example:type(ovf_file)::filetype(ovf_segment)::segmentinteger::successreal(kind=4),allocatable::array_4(:,:)real(kind=8),allocatable::array_8(:,:)! Initialize segmentcallsegment%initialize()! Write a filecall file%open_file("fortran/test/testfile_f.ovf")segment%N_Cells=[2,2,1]segment%N=product(segment%N_Cells)allocate(array_4(3,segment%N))array_4=0array_4(:,1)=[6.0,7.0,8.0]array_4(:,2)=[5.0,4.0,3.0]success=file%write_segment(segment,array_4,OVF_FORMAT_TEXT)if(success==OVF_OK)thenwrite(*,*)"test write_segment succeeded."! write (*,*) "n_cells = ", segment%N_Cells! write (*,*) "n_total = ", segment%Nelsewrite(*,*)"test write_segment did not work. Message: ",file%latest_messageSTOP1endifFor more information on how to generate modern Fortran bindings,
see alsohttps://github.com/MRedies/Interfacing-FortranHow to embed it into your projectIf you are using CMake, it is as simple as cloning this into a subdirectory,
e.g.thirdparty/ovfand using it withadd_subdirectory:add_subdirectory( ${PROJECT_SOURCE_DIR}/thirdparty/ovf )
set( OVF_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/thirdparty/ovf/include )
target_include_directories( myproject PRIVATE ${OVF_INCLUDE_DIRS} )
target_link_libraries( myproject PUBLIC ${OVF_LIBRARIES_STATIC} )If you're not using CMake, you may need to put in some manual work.BuildOn Unix systemsUsually:mkdir build
cd build
cmake ..
makeOn WindowsOne possibility:open the folder in the CMake GUIgenerate the VS projectopen the resulting project in VS and build itCMake OptionsThe following options areONby default.
If you want to switch them off, just pass-D<OPTION>=OFFto CMake,
e.g.-DOVF_BUILD_FORTRAN_BINDINGS=OFF.OVF_BUILD_PYTHON_BINDINGSOVF_BUILD_FORTRAN_BINDINGSOVF_BUILD_TESTOn Windows, you can also set these from the CMake GUI.Create and install the Python packageInstead ofpip-installing it, you can e.g. build everything
and then install the package locally, where the-eflag will
let you change/update the package without having to re-install it.cd python
pip install -e .Build without CMakeThe following is an example of how to manually build the C library and
link it with bindings into a corresponding Fortran executable, using gcc.C library:g++ -DFMT_HEADER_ONLY -Iinclude -fPIC -std=c++11 -c src/ovf.cpp -o ovf.cpp.o

# static
ar qc libovf_static.a ovf.cpp.o
ranlib libovf_static.a

# shared
g++ -fPIC -shared -lc++ ovf.cpp.o -o libovf_shared.soC/C++ test executable:g++ -Iinclude -Itest -std=c++11 -c test/main.cpp -o main.cpp.o
g++ -Iinclude -Itest -std=c++11 -c test/simple.cpp -o simple.cpp.o

# link static lib
g++ -lc++ libovf_static.a main.cpp.o simple.cpp.o -o test_cpp_simple

# link shared lib
g++ libovf_shared.so main.cpp.o simple.cpp.o -o test_cpp_simpleFortran library:gfortran -fPIC -c fortran/ovf.f90 -o ovf.f90.o

ar qc libovf_fortran.a libovf_static.a ovf.f90.o
ranlib libovf_fortran.aFortran test executablegfortran -c fortran/test/simple.f90 -o simple.f90.o
gfortran -lc++ libovf_fortran.a simple.f90.o -o test_fortran_simpleWhen linking statically, you can also link the object fileovf.cpp.oinstead oflibovf_static.a.Note: depending on compiler and/or system, you may need-lstdc++instead of-lc++.File format v2.0 specificationThis specification is written according to theNIST user guide for OOMMFand has been implemented, but not tested or verified against OOMMF.Note: The OVF 2.0 format is a modification to the OVF 1.0 format that also supports fields across three spatial dimensions but having values of arbitrary (but fixed) dimension. The following is a full specification of the 2.0 format.GeneralAn OVF file has an ASCII header and trailer, and data blocks that may be either ASCII or binary.All non-data lines begin with a#characterComments start with##and are ignored by the parser. A comment continues until the end of the line.There is no line continuation characterLines starting with a#but containing only whitespace are ignoredLines starting with a#but containing an unknown keyword are are an errorAfter an overall header, the file consists of segment blocks, each composed of a segment header, data block and trailer.The field domain (i.e., the spatial extent) lies across three dimensions, with units typically expressed in meters or nanometersThe field can be of any arbitrary dimensionN > 0(This dimension, however, is fixed within each segment).HeaderThe first line of an OVF 2.0 file must be# OOMMF OVF 2.0The header should also contain the number of segments, specified as e.g.# Segment count: 000001Zero-padding of the segment count is not specifiedSegmentsSegment HeaderEach block begins with a# Begin: <block type>line, and ends with a corresponding# End: <block type>lineA non-empty non-comment line consists of a keyword and a value:A keyword consists of all characters after the initial#up to the first colon (:) character. Case is ignored, and all whitespace is removedUnknown keywords are errorsThe value consists of all characters after the first colon (:) up to a comment (##) or line endingThe order of keywords is not specifiedNone of the keywords have default values, so all are required unless stated otherwiseEverything inside theHeaderblock should be either comments or one of the following file keyword linestitle: long file name or titledesc(optional): description line, use as many as desiredmeshunit: fundamental mesh spatial unit. The comment marker##is not allowed in this line. Example value:nmvalueunits: should be a (Tcl) list of value units. The comment marker##is not allowed in this line. Example value:"kA/m". The length of the list should be one ofN: each element denotes the units for the corresponding dimension index1: the single element is applied to all dimension indexesvaluelabels: This should be aN-item (Tcl) list of value labels, one for each value dimension. The labels identify the quantity in each dimension. For example, in an energy density file,Nwould be1, valueunits could be"J/m3", and valuelabels might be"Exchange energy density"valuedim(integer): specifies an integer value,N, which is the dimensionality of the field.N >= 1xmin,ymin,zmin,xmax,ymax,zmax: six separate lines, specifying the bounding box for the mesh, in units ofmeshunitmeshtype: grid structure; one ofrectangular: Requires alsoxbase,ybase,zbase: three separate lines, denoting the origin (i.e. the position of the first point in the data section), in units ofmeshunitxstepsize,ystepsize,zstepsize: three separate lines, specifying the distance between adjacent grid points, in units ofmeshunitxnodes,ynodes,znodes(integers): three separate lines, specifying the number of nodes along each axis.irregular: Requires alsopointcount(integer): number of data sample points/locations, i.e., nodes. For irregular grids onlySegment DataThe data block start is marked by a line of the form# Begin: data <representation>(and therefore closed by# End: data <representation>), where<representation>is one oftextbinary 4binary 8In the Data block, for regular meshes each record consists ofNvalues, whereNis the value dimension as specified by thevaluedimrecord in the Segment Header. For irregular meshes, each record consists ofN + 3values, where the first three values are the x , y and z components of the node position.It is common convention for thetextdata to be inNcolumns, separated by whitespaceData ordering is generally with the x index incremented first, then the y index, and the z index lastFor binary data:The binary representations are IEEE 754 standardized floating point numbers in little endian (LSB) order. To ensure that the byte order is correct, and to provide a partial check that the file hasn't been sent through a non 8-bit clean channel, the first data value is fixed to1234567.0for 4-byte mode, corresponding to the LSB hex byte sequence38 B4 96 49, and123456789012345.0for 8-byte mode, corresponding to the LSB hex byte sequence40 DE 77 83 21 12 DC 42The data immediately follows the check valueThe first character after the last data value should be a newlineExtensions made by this libraryThese extensions are mainly to help with data for atomistic systems.The segment count is padded to 6 digits with zeros (this is so that segments can be appended and the count incremented without having to re-write the entire file)Lines starting with a#but containing an unknown keyword are ignored.##is always a comment and is allowed in all keyword lines, includingmeshunitandvalueunitsAll keywords have default values, so none are requiredcsvis also a valid ASCII data representation and corresponds to comma-separated columns oftexttypeCurrent limitations of this librarynaming of variables in structs/classes is inconsistent with the file format specificationsnot all defaults in the segment are guaranteed to be sensiblevalueunitsandvaluelabelsare written and parsed, but not checked for dimensionality or content in eitherminandmaxvalues are not checked to make sure they are sensible boundsirregularmesh type is not supported properly, as positions are not accounted for in read or writeExampleAn example OVF 2.0 file for an irregular mesh with N = 2:# OOMMF OVF 2.0
#
# Segment count: 1
#
# Begin: Segment
# Begin: Header
#
# Title: Long file name or title goes here
#
# Desc: Optional description line 1.
# Desc: Optional description line 2.
# Desc: ...
#
## Fundamental mesh measurement unit.  Treated as a label:
# meshunit: nm
#
# meshtype: irregular
# pointcount: 5      ## Number of nodes in mesh
#
# xmin:    0.    ## Corner points defining mesh bounding box in
# ymin:    0.    ## 'meshunit'.  Floating point values.
# zmin:    0.
# xmax:   10.
# ymax:    5.
# zmax:    1.
#
# valuedim: 2    ## Value dimension
#
## Fundamental field value units, treated as labels (i.e., unparsed).
## In general, there should be one label for each value dimension.
# valueunits:  J/m^3  A/m
# valuelabels: "Zeeman energy density"  "Anisotropy field"
#
# End: Header
#
## Each data records consists of N+3 values: the (x,y,z) node
## location, followed by the N value components.  In this example,
## N+3 = 5, the two value components are in units of J/m^3 and A/m,
## corresponding to Zeeman energy density and a magneto-crystalline
## anisotropy field, respectively.
#
# Begin: data text
0.5 0.5 0.5  500.  4e4
9.5 0.5 0.5  300.  5e3
0.5 4.5 0.5  400.  4e4
9.5 4.5 0.5  200.  5e3
5.0 2.5 0.5  350.  2.1e4
# End: data text
# End: segmentComparison to OVF 1.0The first line reads# OOMMF OVF 2.0for both regular and irregular meshes.In the segment header blockthe keywordsvaluemultiplier,boundary,ValueRangeMaxMagandValueRangeMinMagof the OVF 1.0 format are not supported.the new keywordvaluedimis required. This must specify an integer value,N, bigger or equal to one.the newvalueunitskeyword replaces thevalueunitkeyword of OVF 1.0, which is not allowed in OVF 2.0 files.the newvaluelabelskeyword is required.In the segment data blockThe node ordering is the same as for the OVF 1.0 format.For data blocks using text representation withN = 3, the data block in OVF 1.0 and OVF 2.0 files are exactly the same. Another common case isN = 1, which represents scalar fields, such as energy density (in say,J/m3)