Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

OVF (OOMMF Vector Field file format) parser library with C API and language bindings

License

NotificationsYou must be signed in to change notification settings

spirit-code/ovf

Repository files navigation

Simple API for powerful OOMMF Vector Field file parsing

OVF format specification

Build Status

Python package:PyPI version

Library CoveragePython Bindings Coverage
Library Coverage StatusPython Bindings Coverage Status

How to use

For usage examples, take a look into the test folders:test,python/test orfortran/test.

Except for opening a file or initializing a segment, all functions return status codes(generallyOVF_OK,OVF_INVALID orOVF_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_segment you pass in isinitialized, i.e. you already called eitherovf_read_segment_header orovf_segment_create.

C/C++

Opening and closing:

  • struct ovf_file *myfile = ovf_open("myfilename.ovf") to open a file
  • myfile->found to check if the file exists on disk
  • myfile->is_ovf to check if the file contains an OVF header
  • myfile->n_segments to check the number of segments the file should contain
  • ovf_close(myfile); to close the file and free resources

Reading from a file:

  • struct ovf_segment *segment = ovf_segment_create() to initialize a new segment and get the pointer
  • ovf_read_segment_header(myfile, index, segment) to read the header into the segment struct
  • create float data array of appropriate size...
  • ovf_read_segment_data_4(myfile, index, segment, data) to read the segment data into your float array
  • settingsegment->N before reading allows partial reading of large data segments

Writing and appending to a file:

  • struct ovf_segment *segment = ovf_segment_create() to initialize a new segment and get the pointer
  • segment->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 data
  • ovf_append_segment_4(myfile, segment, data, OVF_FORMAT_TEXT) to append the segment header and data to the file

Python

To install theovf python package, either build and install from sourceor simply use

pip install ovf

To useovf from 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())

Fortran

The 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 segmentcall segment%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_messageSTOP1endif

For more information on how to generate modern Fortran bindings,see alsohttps://github.com/MRedies/Interfacing-Fortran

How to embed it into your project

If you are using CMake, it is as simple as cloning this into a subdirectory,e.g.thirdparty/ovf and 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.

Build

On Unix systems

Usually:

mkdir buildcd buildcmake ..make

On Windows

One possibility:

  • open the folder in the CMake GUI
  • generate the VS project
  • open the resulting project in VS and build it

CMake Options

The following options areON by default.If you want to switch them off, just pass-D<OPTION>=OFF to CMake,e.g.-DOVF_BUILD_FORTRAN_BINDINGS=OFF.

  • OVF_BUILD_PYTHON_BINDINGS
  • OVF_BUILD_FORTRAN_BINDINGS
  • OVF_BUILD_TEST

On Windows, you can also set these from the CMake GUI.

Create and install the Python package

Instead ofpip-installing it, you can e.g. build everythingand then install the package locally, where the-e flag willlet you change/update the package without having to re-install it.

cd pythonpip install -e .

Build without CMake

The following is an example of how to manually build the C library andlink 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# staticar qc libovf_static.a ovf.cpp.oranlib libovf_static.a# sharedg++ -fPIC -shared -lc++ ovf.cpp.o -o libovf_shared.so

C/C++ test executable:

g++ -Iinclude -Itest -std=c++11 -c test/main.cpp -o main.cpp.og++ -Iinclude -Itest -std=c++11 -c test/simple.cpp -o simple.cpp.o# link static libg++ -lc++ libovf_static.a main.cpp.o simple.cpp.o -o test_cpp_simple# link shared libg++ libovf_shared.so main.cpp.o simple.cpp.o -o test_cpp_simple

Fortran library:

gfortran -fPIC -c fortran/ovf.f90 -o ovf.f90.oar qc libovf_fortran.a libovf_static.a ovf.f90.oranlib libovf_fortran.a

Fortran test executable

gfortran -c fortran/test/simple.f90 -o simple.f90.ogfortran -lc++ libovf_fortran.a simple.f90.o -o test_fortran_simple

When linking statically, you can also link the object fileovf.cpp.o instead oflibovf_static.a.

Note: depending on compiler and/or system, you may need-lstdc++ instead of-lc++.

File format v2.0 specification

This 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.

General

  • An 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# character
  • Comments start with## and are ignored by the parser. A comment continues until the end of the line.
  • There is no line continuation character
  • Lines starting with a# but containing only whitespace are ignored
  • Lines starting with a# but containing an unknown keyword are are an error

After 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 nanometers
  • The field can be of any arbitrary dimensionN > 0 (This dimension, however, is fixed within each segment).

Header

  • The first line of an OVF 2.0 file must be# OOMMF OVF 2.0
  • The header should also contain the number of segments, specified as e.g.# Segment count: 000001
  • Zero-padding of the segment count is not specified

Segments

Segment Header

  • Each block begins with a# Begin: <block type> line, and ends with a corresponding# End: <block type> line
  • A 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 removed
    • Unknown keywords are errors
    • The value consists of all characters after the first colon (:) up to a comment (##) or line ending
  • The order of keywords is not specified
  • None of the keywords have default values, so all are required unless stated otherwise

Everything inside theHeader block should be either comments or one of the following file keyword lines

  • title: long file name or title
  • desc (optional): description line, use as many as desired
  • meshunit: fundamental mesh spatial unit. The comment marker## is not allowed in this line. Example value:nm
  • valueunits: 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 of
    • N: each element denotes the units for the corresponding dimension index
    • 1: the single element is applied to all dimension indexes
  • valuelabels: 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,N would 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 >= 1
  • xmin,ymin,zmin,xmax,ymax,zmax: six separate lines, specifying the bounding box for the mesh, in units ofmeshunit
  • meshtype: grid structure; one of
    • rectangular: Requires also
      • xbase,ybase,zbase: three separate lines, denoting the origin (i.e. the position of the first point in the data section), in units ofmeshunit
      • xstepsize,ystepsize,zstepsize: three separate lines, specifying the distance between adjacent grid points, in units ofmeshunit
      • xnodes,ynodes,znodes (integers): three separate lines, specifying the number of nodes along each axis.
    • irregular: Requires also
      • pointcount (integer): number of data sample points/locations, i.e., nodes. For irregular grids only

Segment Data

  • The 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 of
    • text
    • binary 4
    • binary 8
  • In the Data block, for regular meshes each record consists ofN values, whereN is the value dimension as specified by thevaluedim record in the Segment Header. For irregular meshes, each record consists ofN + 3 values, where the first three values are the x , y and z components of the node position.
  • It is common convention for thetext data to be inN columns, separated by whitespace
  • Data ordering is generally with the x index incremented first, then the y index, and the z index last

For 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.0 for 4-byte mode, corresponding to the LSB hex byte sequence38 B4 96 49, and123456789012345.0 for 8-byte mode, corresponding to the LSB hex byte sequence40 DE 77 83 21 12 DC 42
  • The data immediately follows the check value
  • The first character after the last data value should be a newline

Extensions made by this library

These 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, includingmeshunit andvalueunits
  • All keywords have default values, so none are required
  • csv is also a valid ASCII data representation and corresponds to comma-separated columns oftext type

Current limitations of this library

  • naming of variables in structs/classes is inconsistent with the file format specifications
  • not all defaults in the segment are guaranteed to be sensible
  • valueunits andvaluelabels are written and parsed, but not checked for dimensionality or content in either
  • min andmax values are not checked to make sure they are sensible bounds
  • irregular mesh type is not supported properly, as positions are not accounted for in read or write

Example

An 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 text0.5 0.5 0.5  500.  4e49.5 0.5 0.5  300.  5e30.5 4.5 0.5  400.  4e49.5 4.5 0.5  200.  5e35.0 2.5 0.5  350.  2.1e4# End: data text# End: segment

Comparison to OVF 1.0

  • The first line reads# OOMMF OVF 2.0 for both regular and irregular meshes.
  • In the segment header block
    • the keywordsvaluemultiplier,boundary,ValueRangeMaxMag andValueRangeMinMag of the OVF 1.0 format are not supported.
    • the new keywordvaluedim is required. This must specify an integer value,N, bigger or equal to one.
    • the newvalueunits keyword replaces thevalueunit keyword of OVF 1.0, which is not allowed in OVF 2.0 files.
    • the newvaluelabels keyword is required.
  • In the segment data block
    • The 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 )

[8]ページ先頭

©2009-2025 Movatter.jp