# mdt.component_templates package¶

## mdt.component_templates.base module¶

class mdt.component_templates.base.ComponentBuilder[source]

Bases: object

The base class for component builders.

Component builders, together with ComponentTemplate allow you to define components using Templates, special classes where the properties are defined using class attributes.

The ComponentTemplate contains class attributes defining the component which can be used by the ComponentBuilder to create a class of the right type from the information in that template.

create_class(template)[source]

Create a class of the right type given the information in the template.

Parameters: template (ComponentTemplate) – the information as a component config the class of the right type class
class mdt.component_templates.base.ComponentTemplate[source]

Bases: object

The component configuration.

By overriding the class attributes you can define complex configurations. The actual class distilled from these configurations are loaded by the builder referenced by _builder.

_component_type

the component type of this template. Set to one of the valid template types.

Type: str
_builder

the builder to use for constructing an object of the given template

Type: ComponentBuilder
name

the name of the template

Type: str
description

a description of the object / template

Type: str

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {}
component_type = None
description = ''
classmethod meta_info()[source]
name = ''
subcomponents = []
class mdt.component_templates.base.ComponentTemplateMeta[source]

Bases: type

A pre-processor for the components.

On the moment this meta class does two things, first it adds all functions with the ‘_bind’ property to the bound_methods dictionary for binding them later to the constructed class. Second, it sets the name attribute to the template class name if there is no name attribute defined.

mdt.component_templates.base.bind_function(func)[source]

This decorator is for methods in ComponentTemplates that we would like to bind to the constructed component.

Example suppose you want to inherit or overwrite a function in the constructed model, then in your template/config you should define the function and add @bind_function to it as a decorator, like this:

# the class we want to create
class MyGoal:
def test(self):
print('test')

# the template class from which we want to construct a new MyGoal, note the @bind_function
class MyConfig(ComponentTemplate):
@bind_function
def test(self):
super().test()
print('test2')


The component builder takes care to actually bind the new method to the final object.

What this will do essentially is that it will add the property bind to the function. This should act as a flag indicating that that function should be bound.

Parameters: func (python function) – the function to bind to the build object
mdt.component_templates.base.merge_dict(dictionary)[source]

Makes sure that the given dictionary updates the dictionary of the parent template instead of overwriting it.

This is meant to be used inside component templates. Suppose the following hierarchy of templates:

class Template(ComponentTemplate):
property = {'a': 1, 'b': 2}

class Item(Template):
property = {'a': 3}


Here, the property of Item will overwrite those of Template and set the value to {‘a’: 3}. In some instances this is desired, in other instances it can be desired to have the property of Item be set to {‘a’: 3, ‘b’: 2}. To automatically merge the dictionaries with those of the parent you can use:

from mdt.component_templates.base import merge_dicts

class Item(Template):
property = merge_dict({'a': 3})


## mdt.component_templates.batch_profiles module¶

class mdt.component_templates.batch_profiles.BatchProfileBuilder[source]
class mdt.component_templates.batch_profiles.BatchProfileTemplate[source]

The batch profile template to inherit.

name

the name of this batch profile

Type: str
description

the description

Type: str
subject_base_folder

the base folder for this subject. Allows expansion of {subject_id}.

Type: str
data_fname

the filename of the data volumes file. Allows expansion of {subject_id} and {subject_base_folder}, and supports globbing. Results are afterwards filtered to exclude matches of the mask and gradient deviations files.

Type: str
mask_fname

the filename of the mask. Allows expansion of {subject_id} and {subject_base_folder}, and supports globbing.

Type: str
noise_std_fname

the filename of the noise standard deviation file. Can be textfile or a nifti file. Allows expansion of {subject_id} and {subject_base_folder}, and supports globbing.

Type: str
gradient_deviations_fname

the filename of the gradient deviations. Allows expansion of {subject_id} and {subject_base_folder}, and supports globbing.

Type: str
protocol_auto_dir

the directory from which MDT will try to autoload a directory. Supports {subject_id} and {subject_base_folder}, and supports globbing.

Type: str
protocol_fname

the filename of the protocol file to use. Supports {subject_id} and {subject_base_folder}, and supports globbing. If provided, we use it instead of the automatically searched default.

Type: str
bvec_fname

the filename of the bvec file to use. Supports {subject_id} and {subject_base_folder}, and supports globbing. If provided, we use it instead of the automatically searched default.

Type: str
bval_fname

the filename of the bval file to use. Supports {subject_id} and {subject_base_folder}, and supports globbing. If provided, we use it instead of the automatically searched default.

Type: str
protocol_columns

a dictionary with additional columns to add to the protocol file. Use this for default values for all subjects in your study.

Type: dict

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {}
bval_fname = None
bvec_fname = None
component_type = 'batch_profiles'
data_fname = '{subject_base_folder}/*.nii*'
description = ''
gradient_deviations_fname = '{subject_base_folder}/grad_dev.nii*'
mask_fname = '{subject_base_folder}/*mask.nii*'
name = None
noise_std_fname = '{subject_base_folder}/noise_std*'
protocol_auto_dir = '{subject_base_folder}'
protocol_columns = {}
protocol_fname = None
subcomponents = []
subject_base_folder = '{subject_id}'

## mdt.component_templates.compartment_models module¶

class mdt.component_templates.compartment_models.CompartmentBuilder[source]
class mdt.component_templates.compartment_models.CompartmentTemplate[source]

The compartment config to inherit from.

These configs are loaded on the fly by the CompartmentBuilder.

name

the name of the model, defaults to the class name

Type: str
description

model description

Type: str
return_type

the return type of this compartment, defaults to double.

Type: str
parameters

the list of parameters to use. A few options are possible per item, that is, if given:

• a string, we will look for a corresponding parameter with the given name
• an instance of a CLFunctionParameter subclass, this will then be used directly
• the literal @observation, this injects the current volume/observation into this function
of type mot_float_type and name observation.
• the literal @observations, this injects a pointer to all the observations into this function.
of type float and name observations.
• the literal @observation_ind, the index of the current observation we are computing the signal for,
of type uint and name observation_ind.
• the literal @nmr_observation, injects the total number of observations,
of type uint and name nmr_observation.
• the literal @cache, this injects the data cache into this function, with the name cache
and a struct as datatype. The struct type name is provided by this compartment name appended with _DataCache.
• the literal @noise_std, this injects the current value of the noise standard sigma parameter value
of the likelihood function in this parameter.
Type: list
dependencies

the list of functions this function depends on, can contain string which will be resolved as library functions.

Type: list
cl_code

the CL code definition to use, please provide here the body of your CL function.

Type: str
cl_extra

additional CL code for your model. This will be prepended to the body of your CL function.

Type: str
constraints

additional inequality constraints for this model. Each constraint needs to be implemented as g(x) where we assume that g(x) <= 0. For example, to implement a simple inequality constraint like d >= dperp0, we first write it as dperp0 - d <= 0. We can then implement it as:

constraints = '''
constraints[0] = dperp0 - d;
'''


To add more constraint, add another entry to the constraints array. MDT parses the given text and automatically recognizes the model parameter names and the number of constraints.

Type: str or None
prior

an extra MCMC sample prior for this compartment. This is additional to the priors defined in the parameters. This should be an instance of a CLFunction or a string with a CL function body. If the latter, the CLFunction is automatically constructed based on the content of the string.

Type: str or None
cache_info

the data cache information. This works in combination with specifying the @cache parameter for this compartment. The cache info should have two elements, fields and cl_code. The fields specify the items we need to store in the structure, the syntax per field is either a string like double alpha or a tuple like ('double', 'alpha'). Specifying a tuple also allows for specifying arrays like: ('double', 'beta', 10). The CL code given by cl_code is supposed to fill the cache. This cl_code will be wrapped in a function with as arguments all free parameters of the compartments, and the cache. The fields in the cache are accessible using *cache->alpha, i.e. dereferencing a pointer to a variable using the cache. An optional element in the cache info is “use_local_reduction” which specifies that for this compartment we use all workitems in the workgroup. If not set, or if False, we will execute the cache CL code only for the first work item. The default is True.

Type: dict
extra_optimization_maps

a list of functions to return extra information maps based on a point estimate. This is called after the model calculated uncertainties based on the Fisher Information Matrix. Therefore, these routines can propagate uncertainties in the estimates.

These functions should accept as single argument an object of type mdt.models.composite.ExtraOptimizationMapsInfo.

Examples:

extra_optimization_maps_funcs = [lambda d: {'FS': 1 - d['w']},
lambda d: {'Kurtosis.MK': <...>},
lambda d: {'Power2': d['foo']**2, 'Power3': d['foo']**3},
...]

Type: list
extra_sampling_maps

a list of functions to return additional maps as results from sample. This is called after sample with as argument a dictionary containing the sample results and the values of the fixed parameters.

Examples:

extra_sampling_maps = [lambda s: {'MD': np.mean((s['d'] + s['dperp0'] + s['dperp1'])/3., axis=1)}
...]

Type: list

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {}
cache_info = None
cl_code = None
cl_extra = None
component_type = 'compartment_models'
constraints = None
dependencies = []
description = ''
extra_optimization_maps = []
extra_sampling_maps = []
name = ''
parameters = []
prior = None
return_type = 'double'
subcomponents = []
class mdt.component_templates.compartment_models.WeightBuilder[source]
class mdt.component_templates.compartment_models.WeightCompartmentTemplate[source]

Special compartment template for representing a Weight.

Defining a compartment as a Weight enables automatic volume fraction weighting, and ensures that all weights sum to one during optimization and sample.

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {}
cl_code = None
cl_extra = None
component_type = 'compartment_models'
dependencies = []
description = ''
name = ''
parameters = []
return_type = 'double'
subcomponents = []

## mdt.component_templates.composite_models module¶

class mdt.component_templates.composite_models.CompartmentContextResults(compartment_name, input_results)[source]

Bases: collections.abc.Mapping

Translates the original results to the context of a single compartment.

This basically adds a wrapper around the input dictionary to make the keys relative to the compartment.

Parameters: compartment_name (str) – the name of the compartment we are making things relative for input_results (dict) – the original input we want to make relative
class mdt.component_templates.composite_models.CompositeModelTemplate[source]

The composite model config to inherit from.

These configs are loaded on the fly by the DMRICompositeModelBuilder

name

the name of the model, defaults to the class name

Type: str
description

model description

Type: str
extra_optimization_maps

a list of functions to return extra information maps based on a point estimate. This is called after after the model calculated uncertainties based on the Fisher Information Matrix. Therefore, these routines can propagate uncertainties in the estimates.

These functions should accept as single argument an object of type mdt.models.composite.ExtraOptimizationMapsInfo.

Examples:

extra_optimization_maps = [lambda d: {'FS': 1 - d['w_ball.w']},
lambda d: {'Kurtosis.MK': <...>},
lambda d: {'Power2': d['foo']**2, 'Power3': d['foo']**3},
...]

Type: list
extra_sampling_maps

a list of functions to return additional maps as results from sample. This is called after sample with as argument a dictionary containing the sample results and the values of the fixed parameters.

Examples:

extra_sampling_maps = [lambda d: {'FS': np.mean(d['w_stick0.w'], axis=1),
'FS.std': np.std(d['w_stick0.w'], axis=1)}
...]

Type: list
model_expression

the model expression. For the syntax see: mdt.models.parsers.CompositeModelExpression.ebnf

Type: str
likelihood_function

the likelihood function to use during optimization, can also can be a string with one of ‘Gaussian’, ‘OffsetGaussian’ or ‘Rician’

signal_noise_model

optional signal noise decorator

Type: SignalNoiseModel
inits

indicating the initialization values for the parameters. Example:

inits = {'Stick.theta': np.pi}

Type: dict
fixes

indicating the constant value for the given parameters. Example:

fixes = {'Ball.d': 3.0e-9,
'NODDI_EC.kappa': SimpleAssignment('NODDI_IC.kappa'),
'NODDI_EC.theta': 'NODDI_IC.theta'}


Next to values, this also accepts strings as dependencies (or dependecy objects directly).

Type: dict
upper_bounds

indicating the upper bounds for the given parameters. Example:

upper_bounds = {'Stick.theta': pi}

Type: dict
lower_bounds

indicating the lower bounds for the given parameters. Example:

lower_bounds = {'Stick.theta': 0}

Type: dict
enforce_weights_sum_to_one

set to False to disable the automatic Weight-sum-to-one dependency. By default it is True and we add them.

Type: boolean
volume_selection

the volume selection by this model. This can be used to limit the volumes used in the analysis to only the volumes included in the specification. You can specify specific protocol names here for limiting the selected volumes. For example, for the Tensor model we can write:

volume_selection = {'b': [(0, 1.5e9 + 0.1e9)]}


To limit the volumes to the b-values between 0 and 1.6e9. If the method _get_suitable_volume_indices is overwritten, this does nothing.

Type: dict
prior

a model wide prior. This is used in conjunction with the compartment priors and the parameter priors.

Type: str or CLFunction or None
constraints

additional inequality constraints for this model. Each constraint needs to be implemented as g(x) where we assume that g(x) <= 0. For example, to implement a simple inequality constraint like Tensor.d >= Tensor.dperp0, we first write it as Tensor.dperp0 - Tensor.d <= 0. We can then implement it as:

constraints = 'constraints[0] = Tensor.dperp0 - Tensor.d;'


To add more constraint, add another entry to the constraints array. MDT parses the given text and automatically recognizes the model parameter names and the number of constraints.

Type: str or None

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {}
component_type = 'composite_models'
constraints = None
description = ''
enforce_weights_sum_to_one = True
extra_optimization_maps = []
extra_sampling_maps = []
fixes = {}
inits = {}
likelihood_function = 'OffsetGaussian'
lower_bounds = {}
classmethod meta_info()[source]
model_expression = ''
name = ''
prior = None
signal_noise_model = None
subcomponents = []
upper_bounds = {}
volume_selection = None
class mdt.component_templates.composite_models.DMRICompositeModelBuilder[source]
mdt.component_templates.composite_models.parse_composite_model_expression(model_expression)[source]

Parse the given model expression into a suitable model tree.

Parameters: model_expression (str) – the model expression string. Example: model_expression = ''' S0 * ( (Weight(Wball) * Ball) + (Weight(Wstick) * Stick ) ) '''  the model name is followed by parenthesis the string in parenthesis will represent the model's nickname. (If) – the compartment model tree for use in composite models. list

## mdt.component_templates.library_functions module¶

class mdt.component_templates.library_functions.LibraryFunctionTemplate[source]

The library function config to inherit from.

These configs are loaded on the fly by the LibraryFunctionsBuilder.

name

the name of the model, defaults to the class name

Type: str
description

model description

Type: str
return_type

the return type of the function, defaults to void

Type: str
parameters

the list of parameters to use. If a parameter is a string we will use it automatically, if not it is supposed to be a LibraryParameter instance that we append directly.

Type: list
cl_code

the CL code definition to use.

Type: str
cl_extra

auxiliary functions for the library, prepended to the generated CL function.

Type: str
dependencies

the list of functions this function depends on, can contain string which will be resolved as library functions.

Type: list
is_function

set to False to disable the automatic generation of a function signature. Use this for macro or typedef only libraries.

Type: boolean

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {}
cl_code = None
cl_extra = None
component_type = 'library_functions'
dependencies = []
description = ''
is_function = True
name = ''
parameters = []
return_type = 'void'
subcomponents = []
class mdt.component_templates.library_functions.LibraryFunctionsBuilder[source]

## mdt.component_templates.parameters module¶

class mdt.component_templates.parameters.AzimuthAngleParameterTemplate[source]

Azimuth angle for use in spherical coordinate systems.

If a compartment uses both a PolarAngleParameterTemplate and AzimuthAngleParameterTemplate, the composite model will ensure that the resulting cartesian coordinates are within the right spherical hemisphere. This is possible since diffusion is symmetric.

In the background, we limit both the the polar angle and the azimuth angle between [0, pi] parameter between [0, pi] by projecting any other angle combination onto the right spherical hemisphere.

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {<bound method MockNamedComponent.__name__ of <class 'unittest.mock.MockNamedComponent'>>: <MockNamedComponent name='mock()' id='140623431627944'>}
component_type = 'parameters'
name = 'AzimuthAngleParameterTemplate'
subcomponents = []
class mdt.component_templates.parameters.FreeParameterTemplate[source]

init_value

the initial value

Type: float
fixed

if this parameter is fixed or not. If not fixed this should hold a reference to a value or a matrix

Type: boolean or ndarray of float
lower_bound

the lower bounds, used in the parameter transform and prior

Type: float
upper_bound

the upper bounds, used in the parameter transform and prior

Type: float
parameter_transform

(str or AbstractTransformation): the parameter transformation, this is used for automatic range transformation of the parameters during optimization. See Harms 2017 NeuroImage for details. Typical elements are:

• Identity: no transformation
• Scale: scales the parameters (try to aim for a range between [0, 1])
• Positivity: ensures the parameters are positive
• Clamp: limits the parameter between its lower and upper bounds
• CosSqrClamp: changes the range of the optimized parameters to [0, 1] and ensures boundary constraints
• SinSqrClamp: same as CosSqrClamp
• SqrClamp: same as clamp but with an additional square root to change the magnitude of the range
• AbsModPi: ensures absolute modulus of the input parameters between zero and pi.
• AbsModTwoPi: ensures absolute modulus of the input parameters between zero and two pi.
sampling_proposal_std

the default proposal standard deviation for this parameter. This is used in some MCMC sample routines.

Type: float
sampling_prior

the prior function

numdiff_info

the information necessary to take the numerical derivative of a model with respect to this parameter. Either a dictionary with the keyword arguments to SimpleNumDiffInfo or an information object directly. If None, we use an empty dictionary. Please note that if you override this, you will have to specify all of the items (no automatic inheritance of sub-items).

Type: dict or NumDiffInfo

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {<bound method MockNamedComponent.__name__ of <class 'unittest.mock.MockNamedComponent'>>: <MockNamedComponent name='mock()' id='140623431627944'>}
component_type = 'parameters'
data_type = 'mot_float_type'
fixed = False
init_value = 1
lower_bound = -1e+20
name = 'FreeParameterTemplate'
numdiff_info = {'max_step': 0.1, 'scale_factor': 1, 'use_bounds': True, 'use_lower_bound': True, 'use_upper_bound': True}
parameter_transform = 'Identity'
sampling_prior = <MockNamedComponent name='mock()' id='140623431627944'>
sampling_proposal_std = 1
subcomponents = []
upper_bound = 1e+20
class mdt.component_templates.parameters.ParameterBuilder[source]
class mdt.component_templates.parameters.ParameterTemplate[source]

The parameter template to inherit from.

These templates are loaded on the fly by the ParametersBuilder

template options:
name (str): the name of the parameter, defaults to the class name description (str): the description of this parameter data_type (str): the data type for this parameter

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {}
component_type = 'parameters'
data_type = 'mot_float_type'
description = ''
name = ''
subcomponents = []
class mdt.component_templates.parameters.PolarAngleParameterTemplate[source]

Polar angle for use in spherical coordinate systems.

If a compartment uses both a PolarAngleParameterTemplate and AzimuthAngleParameterTemplate, the composite model will ensure that the resulting cartesian coordinates are within the right spherical hemisphere. This is possible since diffusion is symmetric.

In the background, we limit both the the polar angle and the azimuth angle between [0, pi] parameter between [0, pi] by projecting any other angle combination onto the right spherical hemisphere.

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {<bound method MockNamedComponent.__name__ of <class 'unittest.mock.MockNamedComponent'>>: <MockNamedComponent name='mock()' id='140623431627944'>}
component_type = 'parameters'
name = 'PolarAngleParameterTemplate'
subcomponents = []
class mdt.component_templates.parameters.ProtocolParameterTemplate[source]

The default template options for protocol parameters.

To save on memory, protocol data is loaded as a float by default.

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {}
component_type = 'parameters'
data_type = 'float'
name = 'ProtocolParameterTemplate'
subcomponents = []
value = None
class mdt.component_templates.parameters.RotationalAngleParameterTemplate[source]

Template base class for parameters for which we want to enforce a modulus range.

Parameters of this type are essentially unbounded, but their range is restricted to [0, modulus] using a modulo transformation. The modulus can be provided as an argument. This parameter class is recognized by the composite model which adds the necessary functions to the optimization and sampling routines.

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {<bound method MockNamedComponent.__name__ of <class 'unittest.mock.MockNamedComponent'>>: <MockNamedComponent name='mock()' id='140623431627944'>}
component_type = 'parameters'
init_value = 1.5707963267948966
modulus = 3.141592653589793
name = 'RotationalAngleParameterTemplate'
numdiff_info = {'max_step': 0.1, 'scale_factor': 10, 'use_lower_bound': False, 'use_upper_bound': False}
sampling_proposal_std = 0.1
subcomponents = []
class mdt.component_templates.parameters.SphericalCoordinateParameterTemplate[source]

Template base class for spherical coordinate parameters.

These are meant to be inherited by the polar angle template and the azimuth angle template.

Instead of creating an instance of a Template, this will build the actual component.

This allows one to build the model of a template by regular object initialization. For example, these two calls (a and b) are exactly the same:

template = Template
a = construct_component(template)
b = template()

bound_methods = {<bound method MockNamedComponent.__name__ of <class 'unittest.mock.MockNamedComponent'>>: <MockNamedComponent name='mock()' id='140623431627944'>}
component_type = 'parameters'
init_value = 1.5707963267948966
name = 'SphericalCoordinateParameterTemplate'
numdiff_info = {'max_step': 0.1, 'scale_factor': 10, 'use_lower_bound': False, 'use_upper_bound': False}
sampling_proposal_std = 0.1
subcomponents = []

## mdt.component_templates.utils module¶

class mdt.component_templates.utils.TemplateModifier(template)[source]

Bases: object

Given a template instance, this class can update the properties of the template and write that to a file.

This will overwrite the template definition in the source file where the template was originally defined. If you desire a different location then first create a new file for the template.

Parameters: template (ComponentTemplate) – the template to update
get_source()[source]

Return the current source code buffer.

Returns: the updated source code str
update(property_name, source_code_str)[source]

Update the given property with the given source code.

This does not write the results to file immediately, rather, this updates an internal buffer with the updated source code. To write to file use write_to_file().

Parameters: property_name (str) – the property (attribute or function) to update source_code_str (str) – the updated source code for the property
write_to_file()[source]

Write the updated source code to file.

This can be called repetitively after calling update() since this method will keep track of the current position in the file.