Ejemplo n.º 1
0
ShortAxisFitting::~ShortAxisFitting() {
	for (int i = 0; i < NUMBER_OF_NODES; i++)
	{
		Cmiss_node_destroy(&cmiss_nodes[i]);
	}
	Cmiss_field_cache_destroy(&cache);
	Cmiss_field_destroy(&coordinates_rc_);
	Cmiss_field_module_destroy(&field_module_);
	Cmiss_context_destroy(&context_);
	delete[] initialSegmentLengths;
	for (int i = 0; i < 24; i++)
	{
		delete[] segmentNodes[i];
	}
	delete[] segmentNodes;
}
Ejemplo n.º 2
0
void StrainMeasures::embedStrainOnElements(std::string fieldname, std::vector<std::string>& strain) {

	const unsigned int num_strains = numberOfModelFrames_;
	double times[1024];
	for (unsigned int j = 0; j < num_strains; j++) {
		times[j] = static_cast<double>(j) / (num_strains - 1.0);
	}
	Cmiss_time_sequence_id time_sequence = Cmiss_field_module_get_matching_time_sequence(field_module, num_strains, times);

	Cmiss_field_module_begin_change(field_module);

	//Create Node template
	Cmiss_nodeset_id nodeset = Cmiss_field_module_find_nodeset_by_name(field_module, "cmiss_nodes");
	Cmiss_node_template_id nodeTemplate = Cmiss_nodeset_create_node_template(nodeset);
	//Create the field
	Cmiss_field_id strainField = Cmiss_field_module_create_field(field_module, fieldname.c_str(), "finite number_of_components 1 component_names value");
	if (!strainField) {
		std::cout << "Unable to create field " << fieldname << std::endl;
		return;
	}

	Cmiss_node_template_define_field(nodeTemplate, strainField);
	Cmiss_node_template_define_time_sequence(nodeTemplate, strainField, time_sequence);

	//Create Element template
	Cmiss_mesh_id mesh = Cmiss_field_module_find_mesh_by_dimension(field_module, 3);
	Cmiss_element_template_id element_template = Cmiss_mesh_create_element_template(mesh);
	Cmiss_element_template_set_shape_type(element_template, CMISS_ELEMENT_SHAPE_CUBE);
	Cmiss_element_template_set_number_of_nodes(element_template, 1);
	Cmiss_element_basis_id constant_basis = Cmiss_field_module_create_element_basis(field_module, 3, CMISS_BASIS_FUNCTION_CONSTANT);
	const int local_node_index = 1;
	Cmiss_element_template_define_field_simple_nodal(element_template, strainField, -1, constant_basis, 1, &local_node_index);
	Cmiss_element_basis_destroy(&constant_basis);

	//Map strains to elements

	std::map<int, int> elemStrainMap; //Cmiss element no is mapped to strain array number
	//APLAX
	elemStrainMap[3] = elemStrainMap[10] = 1; //Array id base 0
	elemStrainMap[15] = elemStrainMap[22] = 18; //Average of strain ids 2 and 8
	elemStrainMap[27] = elemStrainMap[34] = 12;
	elemStrainMap[39] = elemStrainMap[46] = 17;
	elemStrainMap[40] = elemStrainMap[45] = 17;
	elemStrainMap[28] = elemStrainMap[33] = 10;
	elemStrainMap[16] = elemStrainMap[21] = 19; //Average of strain ids 11 and 5
	elemStrainMap[4] = elemStrainMap[9] = 4;

	//TCH
	elemStrainMap[11] = elemStrainMap[12] = 2; //Array id base 0
	elemStrainMap[23] = elemStrainMap[24] = 20; //Average of strain ids 3 and 9
	elemStrainMap[35] = elemStrainMap[36] = 8;
	elemStrainMap[47] = elemStrainMap[48] = 16;
	elemStrainMap[41] = elemStrainMap[42] = 16;
	elemStrainMap[17] = elemStrainMap[18] = 11;
	elemStrainMap[29] = elemStrainMap[30] = 21; //Average of strain ids 12 and 6
	elemStrainMap[5] = elemStrainMap[6] = 5;

	//FCH
	elemStrainMap[1] = elemStrainMap[2] = 3; //Array id base 0
	elemStrainMap[13] = elemStrainMap[14] = 22; //Average of 10 and 4
	elemStrainMap[25] = elemStrainMap[26] = 4;
	elemStrainMap[37] = elemStrainMap[38] = 23; //Average of strains 14 and 15
	elemStrainMap[43] = elemStrainMap[44] = 24; //Average of strains 16 and 13
	elemStrainMap[31] = elemStrainMap[32] = 6;
	elemStrainMap[19] = elemStrainMap[20] = 25; //Average of strains 7 and 1
	elemStrainMap[7] = elemStrainMap[8] = 0;

	std::vector<std::string> allStrain = strain;

	//Add the additional strains 18 - 23
	std::string s2 = strain[1];
	std::string s8 = strain[7];

	std::string s11 = strain[10];
	std::string s5 = strain[5];

	std::string s9 = strain[8];
	std::string s3 = strain[2];

	std::string s12 = strain[11];
	std::string s6 = strain[6];

	std::string s10 = strain[9];
	std::string s4 = strain[3];

	std::string s14 = strain[13];
	std::string s15 = strain[14];

	std::string s16 = strain[15];
	std::string s13 = strain[12];

	std::string s1 = strain[0];
	std::string s7 = strain[6];

	std::vector<std::string> compute;
	compute.push_back(s2);
	compute.push_back(s8);

	compute.push_back(s11);
	compute.push_back(s5);

	compute.push_back(s9);
	compute.push_back(s3);

	compute.push_back(s12);
	compute.push_back(s6);

	compute.push_back(s10);
	compute.push_back(s4);

	compute.push_back(s14);
	compute.push_back(s15);

	compute.push_back(s16);
	compute.push_back(s13);

	compute.push_back(s7);
	compute.push_back(s1);

	for (int cptc = 0; cptc < 16; cptc += 2) {
		std::vector<std::string> strain1;
		std::vector<std::string> strain2;
		std::ostringstream ss;
		boost::split(strain1, compute[cptc], boost::is_any_of(","));
		boost::split(strain2, compute[cptc + 1], boost::is_any_of(","));
		for (unsigned int j = 0; j < num_strains - 1; j++) {
			double value1 = atof(strain1[j].c_str());
			double value2 = atof(strain2[j].c_str());
			ss << (value1 + value2) * 0.5 << ",";
		}
		ss << "0.0";
		allStrain.push_back(ss.str());
	}

	for (unsigned int i = 0; i < num_elements; i++) {
		Cmiss_node_id temporaryNode = Cmiss_nodeset_create_node(nodeset, extraNodeStartID++, nodeTemplate);
		Cmiss_element_template_set_node(element_template, 1, temporaryNode); //Link node with the element
		Cmiss_element_merge(elements[i], element_template);
		Cmiss_field_cache_set_node(fieldCache, temporaryNode);
		std::vector<std::string> strains;
		boost::split(strains, allStrain[elemStrainMap[i + 1]], boost::is_any_of(","));
		for (unsigned int j = 0; j < num_strains; j++) {
			double value = atof(strains[j].c_str());
			double time = times[j];
			Cmiss_field_cache_set_time(fieldCache, time);
			Cmiss_field_assign_real(strainField,fieldCache,1,&value);
		}
		Cmiss_node_destroy(&temporaryNode);
	}

	Cmiss_field_module_end_change(field_module);
	Cmiss_field_destroy(&strainField);
	Cmiss_element_template_destroy(&element_template);
	Cmiss_node_template_destroy(&nodeTemplate);
	Cmiss_nodeset_destroy(&nodeset);
	//Calling the following leads to the error ERROR: DESTROY(FE_time_sequence).  Positive access_count
	//Cmiss_time_sequence_destroy(&time_sequence);

}
Ejemplo n.º 3
0
std::vector<std::string> StrainMeasures::getSegmentStrains(std::string fieldName) {
	std::vector<std::string> strains(19);
	Cmiss_field_id field = Cmiss_field_module_find_field_by_name(field_module, fieldName.c_str());

	//Compute strains
	unsigned int numSegments = mySegments->size();
	double temp_array1[3];
	double temp_array2[3];
//#define printcoord
#ifdef printcoord
#include "MeshTopology.h"

	std::vector<Cmiss_node_id> myNodes(100);
	Cmiss_nodeset_id nodeset = Cmiss_field_module_find_nodeset_by_name(field_module, "cmiss_nodes");
	Cmiss_node_iterator_id nodeIterator = Cmiss_nodeset_create_node_iterator(nodeset);
	Cmiss_node_id node = Cmiss_node_iterator_next(nodeIterator);
	if (node != 0) {
		double temp_array[3];

		while (node) {
			int node_id = Cmiss_node_get_identifier(node);
			myNodes[node_id - 1] = node;
			node = Cmiss_node_iterator_next(nodeIterator);
		}
	}
	Cmiss_nodeset_destroy(&nodeset);
	Cmiss_node_iterator_destroy(&nodeIterator);

	std::vector<int> Nodes(27);

	Nodes[8] = aplaxNodes8;
	Nodes[7] = aplaxNodes7;
	Nodes[6] = aplaxNodes6;
	Nodes[5] = aplaxNodes5;
	Nodes[4] = aplaxNodes4;
	Nodes[3] = aplaxNodes3;
	Nodes[2] = aplaxNodes2;
	Nodes[1] = aplaxNodes1;
	Nodes[0] = aplaxNodes0;

	Nodes[9] = tchNodes0;
	Nodes[10] = tchNodes1;
	Nodes[11] = tchNodes2;
	Nodes[12] = tchNodes3;
	Nodes[13] = tchNodes4;
	Nodes[14] = tchNodes5;
	Nodes[15] = tchNodes6;
	Nodes[16] = tchNodes7;
	Nodes[17] = tchNodes8;

	Nodes[18] = fchNodes0;
	Nodes[19] = fchNodes1;
	Nodes[20] = fchNodes2;
	Nodes[21] = fchNodes3;
	Nodes[22] = fchNodes4;
	Nodes[23] = fchNodes5;
	Nodes[24] = fchNodes6;
	Nodes[25] = fchNodes7;
	Nodes[26] = fchNodes8;

#endif
	std::vector<std::vector<double> > aplaxLengths;
	std::vector<std::vector<double> > tchLengths;
	std::vector<std::vector<double> > fchLengths;
	double denomj = (numberOfModelFrames_ - 1.0);
	for (int i = 0; i < numberOfModelFrames_; i++) {
		std::vector<double> cLengths;
		double time = ((double) i) / denomj;
		Cmiss_field_cache_set_time(fieldCache, time);
#ifdef printcoord
		std::cout<<"Frame "<<i<<"\t"<<time<<"\t"<<mySegments->at(0).xia[2]<<std::endl;
#endif
		for (int j = 0; j < numSegments; j++) {
			WallSegment& seg = mySegments->at(j);
			//The the lengths
			temp_array1[0] = temp_array1[1] = temp_array1[2] = 0.0;
			temp_array2[0] = temp_array2[1] = temp_array2[2] = 0.0;
			//Since cmiss id starts at 1 subtract 1 from seg.elemeid?
			//Note that accessing some computed field (those that involve gradients), with multiple versions leads to gradient set to 0 warning
			Cmiss_field_cache_set_mesh_location(fieldCache, elements[seg.elementida - 1], 3, seg.xia);
			Cmiss_field_evaluate_real(field, fieldCache, 3, temp_array1);
			Cmiss_field_cache_set_mesh_location(fieldCache, elements[seg.elementidb - 1], 3, seg.xib);
			Cmiss_field_evaluate_real(field, fieldCache, 3, temp_array2);
			Point3D p1(temp_array1);
			Point3D p2(temp_array2);
			double dist = p1.distance(p2);
#ifdef printcoord
			{
				int nodeCtr = (j / 8) * 9 + j % 8;
				Cmiss_field_cache_set_node(fieldCache, myNodes[Nodes[nodeCtr]]);
				temp_array1[0] = temp_array1[1] = temp_array1[2] = 0.0;
				Cmiss_field_evaluate_real(field, fieldCache, 3, temp_array1);
				Point3D p3(temp_array1);
				Cmiss_field_cache_set_node(fieldCache, myNodes[Nodes[nodeCtr + 1]]);
				temp_array1[0] = temp_array1[1] = temp_array1[2] = 0.0;
				Cmiss_field_evaluate_real(field, fieldCache, 3, temp_array1);
				Point3D p4(temp_array1);
				std::cout << p1 << "\t" << p2 << " = " << dist << "\t:\t Value at " << Nodes[nodeCtr] + 1 << "\t" << p3 << "\t" << p1.distance(p3) << "\t" << Nodes[nodeCtr + 1] + 1
						<< "\t" << p4 << "\t" << p2.distance(p4) << "\t distance \t " << p3.distance(p4) << std::endl;
			}
#endif
			cLengths.push_back(dist);
		}

		for (int segc = 0; segc < numSegments / 8; segc++) {
			int offset = segc * 8;
			std::vector<double> sLengths;

			sLengths.push_back(cLengths[0 + offset] + (1 / 3.0 - 1 / 4.0) * 4 * cLengths[1 + offset]);
			sLengths.push_back((1.0 - (1 / 3.0 - 1 / 4.0)) * 4 * cLengths[1 + offset] + (2 / 3.0 - 1 / 2.0) * 4 * cLengths[2 + offset]);
			sLengths.push_back((1.0 - (2 / 3.0 - 1 / 2.0)) * 4 * cLengths[2 + offset] + cLengths[3 + offset]);
			sLengths.push_back(cLengths[4 + offset] + (1.0 - (2 / 3.0 - 1 / 2.0)) * 4 * cLengths[5 + offset]);
			sLengths.push_back((2 / 3.0 - 1 / 2.0) * 4 * cLengths[5 + offset] + (1.0 - (1 / 3.0 - 1 / 4.0)) * 4 * cLengths[6 + offset]);
			sLengths.push_back((1 / 3.0 - 1 / 4.0) * 4 * cLengths[6 + offset] + cLengths[7 + offset]);

			if (segc == 0)
				aplaxLengths.push_back(sLengths);
			else if (segc == 1)
				tchLengths.push_back(sLengths);
			else
				fchLengths.push_back(sLengths);
		}
	}
	std::vector<double> avgStrains(numberOfModelFrames_, 0.0);

	for (int segc = 0; segc < numSegments / 8; segc++) {
		std::vector<std::vector<double> > dstrains;
		std::vector<std::vector<double> > distances;
		if (segc == 0)
			distances = aplaxLengths;
		else if (segc == 1)
			distances = tchLengths;
		else if (segc == 2)
			distances = fchLengths;

		std::vector<double>& initStrain = distances[0];
		for (int frame = 1; frame < numberOfModelFrames_; frame++) { //Compute Strains
			std::vector<double>& curStrainLengths = distances[frame];
			std::vector<double> curStrain;
			double c = 0;
			unsigned int ulimit = initStrain.size();
			for (int j = 0; j < ulimit; j++) {
				c = 100.0 * (curStrainLengths[j] - initStrain[j]) / initStrain[j];
				curStrain.push_back(c);
			}
			dstrains.push_back(curStrain);
		}

		std::vector<std::string> strainSeries;

		for (int j = 0; j < initStrain.size(); j++) {
			std::ostringstream ss;
			ss << 0.0; //For init step

			int denom = numberOfModelFrames_ - 1;
			double maxStrain = dstrains[denom - 1][j];
			//Note that frame goes from 1 to heart.numberOfModelFrames_ when computing strain
			//so shift down by 1
			for (int i = 0; i < denom; i++) { //Compute Strains
											  //Drift compensate
				double stc = dstrains[i][j] - (i + 1) * maxStrain / denom;
				ss << "," << stc;
				avgStrains[i] += stc;
			}
			strainSeries.push_back(ss.str());
		}
		if (segc == 0) {
			strains[2 - 1] = strainSeries[5];
			strains[8 - 1] = strainSeries[4];
			strains[17 - 1] = strainSeries[3];
			strains[18 - 1] = strainSeries[2];
			strains[11 - 1] = strainSeries[1];
			strains[5 - 1] = strainSeries[0];
		} else if (segc == 2) {
			strains[3 - 1] = strainSeries[0];
			strains[9 - 1] = strainSeries[1];
			strains[14 - 1] = strainSeries[2];
			strains[16 - 1] = strainSeries[3];
			strains[12 - 1] = strainSeries[4];
			strains[6 - 1] = strainSeries[5];
		} else if (segc == 1) {
			strains[4 - 1] = strainSeries[0];
			strains[10 - 1] = strainSeries[1];
			strains[15 - 1] = strainSeries[2];
			strains[13 - 1] = strainSeries[3];
			strains[7 - 1] = strainSeries[4];
			strains[1 - 1] = strainSeries[5];
		}
	}
#ifdef printcoord
	std::cout << "Linear 3D " << fieldName << std::endl;
	for (int i = 1; i < 100; i++)
		Cmiss_node_destroy(&myNodes[i]);

#endif
	//Add the average strain
	//Num strain segments depends on the number of active segments (6 strain segments per view, which has 8 active segments)
	double denom = (numSegments / 8) * 6;

	std::ostringstream ss;
	ss << 0.0; //For init step
	for (int i = 0; i < numberOfModelFrames_ - 1; i++) { //Compute the Average
		ss << "," << avgStrains[i] / denom;
	}
	strains[18] = ss.str();

	//Check if model PGS should be calculated
	if (computeModelPGS) {
		double max = fabs(avgStrains[0]);
		int idx = 0;
		for (int i = 1; i < numberOfModelFrames_ - 1; i++) {
			if (fabs(avgStrains[i]) > max) {
				max = fabs(avgStrains[i]);
				idx = i;
			}
		}
		modelPGS = avgStrains[idx] / denom;
		computeModelPGS = false; //set it so that it is not computed in subsequent calls
	}

	Cmiss_field_destroy(&field);

	return strains;
}
Ejemplo n.º 4
0
int define_Computed_field_type_nodal_lookup(struct Parse_state *state,
	void *field_modify_void, void *computed_field_lookup_package_void)
/*******************************************************************************
LAST MODIFIED : 25 August 2006

DESCRIPTION :
Converts <field> into type COMPUTED_FIELD_NODAL_LOOKUP (if it is not
already) and allows its contents to be modified.
==============================================================================*/
{
	int return_code;
	Computed_field_lookup_package *computed_field_lookup_package;
	Computed_field_modify_data *field_modify;

	if (state&&(field_modify=(Computed_field_modify_data *)field_modify_void) &&
		(computed_field_lookup_package=
		(Computed_field_lookup_package *)
		computed_field_lookup_package_void))
	{
		return_code = 1;
		Cmiss_field_id source_field = 0;
		char *nodeset_name = duplicate_string("cmiss_nodes");
		char node_flag = 0;
		int node_identifier = 0;
		if ((NULL != field_modify->get_field()) &&
			(computed_field_nodal_lookup_type_string ==
				Computed_field_get_type_string(field_modify->get_field())))
		{
			Cmiss_node_id lookup_node = 0;
			return_code = Computed_field_get_type_nodal_lookup(field_modify->get_field(),
				&source_field, &lookup_node);
			if (source_field)
			{
				 ACCESS(Computed_field)(source_field);
			}
			if (lookup_node)
			{
				node_identifier = get_FE_node_identifier(lookup_node);
				FE_region *fe_region = FE_node_get_FE_region(lookup_node);
				if (!FE_region_contains_FE_node(fe_region, lookup_node))
				{
					DEALLOCATE(nodeset_name);
					nodeset_name = duplicate_string("cmiss_data");
				}
				node_flag = 1;
			}
		}

		Option_table *option_table = CREATE(Option_table)();
		/* source field */
		Set_Computed_field_conditional_data set_source_field_data;
		set_source_field_data.computed_field_manager = field_modify->get_field_manager();
		set_source_field_data.conditional_function = Computed_field_has_numerical_components;
		set_source_field_data.conditional_function_user_data = (void *)NULL;
		Option_table_add_entry(option_table,"field", &source_field,
			&set_source_field_data,set_Computed_field_conditional);
		/* the node to nodal_lookup */
		Option_table_add_entry(option_table, "node", &node_identifier,
			&node_flag, set_int_and_char_flag);
		/* the nodeset the node is from */
		Option_table_add_string_entry(option_table, "nodeset", &nodeset_name,
			" NODE_GROUP_FIELD_NAME|[GROUP_NAME.]cmiss_nodes|cmiss_data[cmiss_nodes]");
		return_code = Option_table_multi_parse(option_table,state);
		DESTROY(Option_table)(&option_table);

		if (return_code && node_flag)
		{
			Cmiss_nodeset_id nodeset = Cmiss_field_module_find_nodeset_by_name(field_modify->get_field_module(), nodeset_name);
			Cmiss_node_id node = Cmiss_nodeset_find_node_by_identifier(nodeset, node_identifier);
			if (node)
			{
				return_code = field_modify->update_field_and_deaccess(
					Computed_field_create_nodal_lookup(field_modify->get_field_module(),
						source_field, node));
			}
			else
			{
				display_message(ERROR_MESSAGE,
					"define field nodal lookup.  Invalid node %d", node_identifier);
				return_code = 0;
			}
			Cmiss_node_destroy(&node);
			Cmiss_nodeset_destroy(&nodeset);
		}
		else
		{
			if ((!state->current_token)||
				(strcmp(PARSER_HELP_STRING,state->current_token)&&
					strcmp(PARSER_RECURSIVE_HELP_STRING,state->current_token)))
			{
				display_message(ERROR_MESSAGE,
					"define_Computed_field_type_time_nodal_lookup.  Failed");
			}
		}
		DEALLOCATE(nodeset_name);
		REACCESS(Computed_field)(&source_field, NULL);
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"define_Computed_field_type_nodal_lookup.  Invalid argument(s)");
		return_code = 0;
	}
	return (return_code);
}
Ejemplo n.º 5
0
int define_Computed_field_type_quaternion_SLERP(struct Parse_state *state,
	void *field_modify_void, void *computed_field_lookup_package_void)
/*******************************************************************************
LAST MODIFIED : 25 August 2006

DESCRIPTION :
Converts <field> into type 'quaterions' (if it is not already) and allows its
contents to be modified.
==============================================================================*/
{
	int return_code;
	Computed_field_lookup_package *computed_field_lookup_package;
	Computed_field_modify_data *field_modify;

	ENTER(define_Computed_field_type_quaternion_SLERP);
	if (state&&(field_modify=(Computed_field_modify_data *)field_modify_void) &&
		 (computed_field_lookup_package=
				(Computed_field_lookup_package *)
				computed_field_lookup_package_void))
	{
		return_code = 1;
		Cmiss_field_id source_field = 0;
		char *nodeset_name = duplicate_string("cmiss_nodes");
		char node_flag = 0;
		int node_identifier = 0;
		if ((NULL != field_modify->get_field()) &&
			(computed_field_quaternion_SLERP_type_string ==
				Computed_field_get_type_string(field_modify->get_field())))
		{
			Cmiss_node_id lookup_node = 0;
			return_code = Computed_field_get_type_quaternion_SLERP(field_modify->get_field(),
				 &source_field, &lookup_node);
			if (source_field)
			{
				 ACCESS(Computed_field)(source_field);
			}
			if (lookup_node)
			{
				node_identifier = get_FE_node_identifier(lookup_node);
				FE_region *fe_region = FE_node_get_FE_region(lookup_node);
				if (!FE_region_contains_FE_node(fe_region, lookup_node))
				{
					DEALLOCATE(nodeset_name);
					nodeset_name = duplicate_string("cmiss_data");
				}
				node_flag = 1;
			}
		}

		Option_table *option_table = CREATE(Option_table)();
		Option_table_add_help(option_table,
			 "A 4 components quaternion field. The components of "
			 "the quaternion field are expected to be the w, x, y, z components"
			 "of a quaternion (4 components in total). The quaternion field  is"
			 "evaluated and interpolated using SLERP at a normalised time between two"
			 "quaternions (read in from the exnode generally). This quaternion field"
			 "can be convert to a matrix with quaternion_to_matrix field, the resulting"
			 "matrix can be used to create a smooth time dependent rotation for an object"
			 "using the quaternion_to_matrix field. This field must be define directly from"
			 "exnode file or from a matrix_to_quaternion field");
		Set_Computed_field_conditional_data set_source_field_data;
		set_source_field_data.computed_field_manager = field_modify->get_field_manager();
		set_source_field_data.conditional_function = Computed_field_has_4_components;
		set_source_field_data.conditional_function_user_data = (void *)NULL;
		Option_table_add_entry(option_table, "field", &source_field,
			&set_source_field_data, set_Computed_field_conditional);
		/* identifier of the node to lookup */
		Option_table_add_entry(option_table, "node", &node_identifier,
			&node_flag, set_int_and_char_flag);
		/* the nodeset the node is from */
		Option_table_add_string_entry(option_table, "nodeset", &nodeset_name,
			" NODE_GROUP_FIELD_NAME|[GROUP_NAME.]cmiss_nodes|cmiss_data[cmiss_nodes]");
		return_code = Option_table_multi_parse(option_table, state);
		DESTROY(Option_table)(&option_table);

		if (return_code && node_flag)
		{
			Cmiss_nodeset_id nodeset = Cmiss_field_module_find_nodeset_by_name(field_modify->get_field_module(), nodeset_name);
			Cmiss_node_id node = Cmiss_nodeset_find_node_by_identifier(nodeset, node_identifier);
			if (node)
			{
				return_code = field_modify->update_field_and_deaccess(
					Computed_field_create_quaternion_SLERP(field_modify->get_field_module(),
						source_field, node));
			}
			else
			{
				display_message(ERROR_MESSAGE,
					"define field quaternion_SLERP.  Invalid node %d", node_identifier);
				return_code = 0;
			}
			Cmiss_node_destroy(&node);
			Cmiss_nodeset_destroy(&nodeset);
		}
		else
		{
			if ((!state->current_token)||
				(strcmp(PARSER_HELP_STRING,state->current_token)&&
					strcmp(PARSER_RECURSIVE_HELP_STRING,state->current_token)))
			{
				display_message(ERROR_MESSAGE,
					"define_Computed_field_type_quaternion_SLERP.  Failed");
			}
		}
		DEALLOCATE(nodeset_name);
		REACCESS(Computed_field)(&source_field, NULL);
	}
	else
	{
		 display_message(ERROR_MESSAGE,
				"define_Computed_field_type_quaternion_SLERP.  Invalid argument(s)");
		 return_code = 0;
	}
	LEAVE;

	return (return_code);
} /* define_Computed_field_type_quaternion_SLERP */